HARVEST — Solana accumulation & yield
This is the design HARVEST was built from (August 2026). The module has been live and armed since 2026-08-29 and diverged from this design in several places — custody model, who executes, LP pairs, cadence. The authoritative description of the running system, its API and its gaps is HARVEST — as built. Sections below carry an As built note where they diverge. Live parameters (capital, ladder triggers, venue splits) are owner inputs and live in the internal module spec, not here.
Not to be confused with the Hermes parity roadmap — "Hermes" there is NousResearch's coding agent. HARVEST descends from the trading Hermes lineage (the Python desk Nexus's trading stack ports).
1. What HARVEST is
A rule-based module that manages a fixed treasury through three phases:
Phase 1 WAIT stablecoins earn on Solana lending markets (Kamino/MarginFi)
Phase 2 ACCUMULATE laddered spot buys of SOL and cbBTC fire on oracle
price triggers, 24/7, clip-based fills via Jupiter
Phase 3 YIELD the accumulated stack earns: LST staking, supply-only
lending, and (capped, opt-in) SOL/cbBTC LP positions
Non-goals: no leverage, no perps, no shorting, no borrowing against the stack, no discretionary overrides mid-drawdown. The core ladder has no exits; the bounded swing sleeve managed by the accumulation desk may sell rebounds above its own cost basis. Cycle-top de-risking is a separate future module.
2. Custody model
┌─────────────────────────────────────────────────┐
│ VAULT — Squads multisig (2-of-3, human keys) │
│ lending positions, filled SOL/cbBTC, idle │
│ stables, all Phase-3 yield positions │
└──────────────┬──────────────────────────────────┘
│ per-tranche funding, capped by a
│ Squads spending limit
┌──────────────▼──────────────────────────────────┐
│ EXEC — hot wallet (nexus-solana controlled) │
│ holds at most one active tranche + gas │
│ swap-only; outbound whitelist = VAULT │
└─────────────────────────────────────────────────┘
Worst-case bot-key compromise loses one tranche, never the treasury. Tranches above the owner-set threshold, and any path outside the whitelist, require human approval. The Squads multisig is the on-chain root of trust; the Telegram approval gate (§6) is a convenience layer on top, never a replacement.
The multisig is 1-of-2 (both owner hardware wallets), not 2-of-3. On 2026-08-29 custody went automation-first: EXEC holds the working treasury (USDC float, lending receipts, JitoSOL, LP positions, order escrows) so that lending, staking, orders and LP can run unattended; VAULT is the cold destination. No Squads spending limit exists yet, so there is no VAULT→EXEC automation, no on-chain destination whitelist and no EXEC→VAULT sweep — refills are owner-signed. The per-transaction USD cap rejects or chunks oversized automation rather than escalating it to a human; the human gate covers sells, CEX actions and fallback activation. See as built §2.
3. New project: nexus-solana
Everything Solana lives in one new repo, deployed via gitops as two cluster-internal Deployments from one Cargo workspace:
nexus-solana-oracle— read-only plane: Pyth + Jupiter price feeds, divergence-guard inputs, lending APY/utilization telemetry. No keys.nexus-solana-exec— signing plane: lending supply/withdraw, Jupiter clip swaps, Squads VAULT↔EXEC tranche flow, LP positions. The only process in the entire fleet that mounts the EXEC key.
Symmetric to how the CEX manager is the venue service for KuCoin: REST for
services, MCP tools for agents. nexus-platform keeps zero chain code —
its oracle consumes nexus-solana-oracle through a thin OracleSource REST
client, and its contribution to HARVEST is the Telegram confirmation flow
(§6) plus scheduling, ledger, and notifications.
See nexus-solana for the planned layout
and the full copy-set. The key finding from the fleet review
(prochain-crypto repos): most of the on-chain floor already exists —
| Capability | Copy from | State |
|---|---|---|
| Lending supply/withdraw, APY, utilization | prochain-amm-server prochain-lending-* (Kamino/MarginFi behind a Lending trait) | working, REST-exposed |
| Tx signing, confirm/retry, priority fees, ALTs | prochain-launchpad-server prochain-transaction | newest copy, production-used |
| Jupiter Metis quoting (self-hosted server) | prochain-solana-jup-server cexdex jupiter.rs | already targets a Metis endpoint; retarget base URL |
| Swap signing + compute-budget helpers | prochain-core-server prochain-jup-client | reuse sign/send + fee helpers; hosted Ultra flow replaced by Metis |
| ATA management, token transfers | prochain-solana-server prochain-ata-cache, prochain-solana-service | working |
| CLMM/LP instruction builders (Phase 3) | official Orca Rust SDK (prochain-amm-server solana/whirlpools/rust-sdk) + prochain-solana-server programs-codama/meteora-dlmm | built — solana-clmm position service (Orca + Meteora DLMM) |
| Metrics, stall detection, runtime settings | prochain-solana-jup-server ops crates | working |
Genuinely new (nothing to copy anywhere in the fleet): Squads v4 client, a real Pyth price client, multi-endpoint RPC failover, the LP position service, the ladder trigger state machine, and key custody beyond a plaintext env var. As built: all written except RPC failover (the pool crate exists, unwired) and the Squads spending-limit path (builder written, never simulation-verified or created on-chain).
Owned infrastructure. The hot path depends on no hosted third-party API:
a self-hosted Jupiter Metis server (LAN) provides unlimited quotes and
builds the swap transactions, which nexus-solana-exec signs locally and
submits through a dedicated Solana node (LAN) — primary RPC for all
reads and sends, with at least one external provider as health-scored
fallback. If Metis is down, clip fills pause while triggers keep persisting;
a node silently serving stale slots is caught by slot-lag monitoring plus
the oracle divergence guard. Endpoints live in internal config, not here.
4. Mapping onto the platform
| Concern | Home | Pattern followed |
|---|---|---|
| Price oracle (Pyth + divergence guard) | nexus-solana-oracle; nexus-oracle gets one thin SolanaSource REST client | same shape as CexManagerSource — platform holds no chain code |
| Ledger | nexus-trading-db, NEXUS_BOOK_NS=accum | namespaced book collections, isolated from paper/live |
| Trigger + clip engine | new nexus-accum-domain / nexus-accum-engine crates | pure functions, injected clock, replayable |
| Risk guards | new nexus-accum-guards | deploy caps, price bands, slippage caps, mint allowlist, depeg halt — fail closed |
| Treasury allocator | harvest-allocator crate in nexus-solana | liquidity ladder + recall-before-act invariants (§6) |
| Arming | two-key: ExecutionMode + NEXUS_ACCUM_ARM=1 | copied from nexus-executor; dry-run is the default |
| Paper-first | simulated Jupiter fills at oracle marks | PaperBroker rationale: skipped writes teach nothing; simulated fills resolve |
| Scheduling | scheduled_jobs + scheduler.command | idempotent, replica-safe firing |
| Notifications | notify.events → Telegram | existing |
| Agent tools | accum.* via the Tool registry | read/monitor only; agents never execute |
| UI | nexus-ui /trading/harvest page + HARVEST panel in the monitoring overhaul | shares the desk SSE layout |
| Deploy | nexus-gitops: solanaOracle: + solanaExec: values blocks, two deployment templates | copy of the executor: block, enabled: false by default; only the exec pod mounts the key secret |
Crate names are harvest-domain / harvest-engine / harvest-guards (not
nexus-accum-*); harvest-guards and harvest-allocator compile but are
not called. There is no SolanaSource in nexus-oracle — worker jobs call
the oracle plane over HTTP directly. State is not a NEXUS_BOOK_NS=accum
book but kind-tagged operator_digests rows plus accum_* collections
written by the exec plane. There are no accum.* agent tools and the agent
layer does execute (within caps). Both deployments are enabled: true,
the exec plane mode: live, arm: true; there was no paper-broker phase.
See as built §4–§5.
Deliberately not reused: the perp guard (check_order speaks
leverage/margin/beta), stop-distance Kelly sizing, and the position manager
(built around venue-resting stops). Spot accumulation has different failure
modes — venue, oracle, slippage, custody — and gets its own parallel guard
vocabulary.
5. Phase 3 — yield tiers
Risk-ordered; each tier adds one protocol layer, is capped, and requires explicit activation above Tier 0.
| Tier | What | Cap | Added risk |
|---|---|---|---|
| 0 (default) | SOL → LST staking (JitoSOL) | — | LST protocol |
| 1 | supply-only lending of LST/cbBTC | per-asset + single-venue caps | lending solvency, withdrawal liquidity |
| 2 | SOL/cbBTC and LST/SOL LP | small fraction of stack | AMM contract risk + impermanent loss |
A SOL/cbBTC LP mechanically sells the outperformer as prices diverge — in the expected recovery scenario that means bleeding SOL against the accumulation target. Tier 2 is a fee-harvest sleeve, measured in SOL-equivalent terms and unwound if trailing fees underrun IL. Borrowing is banned at every tier.
All yield positions live in VAULT and must be unwindable to spot within 24h.
Tier 0 (JitoSOL) and Tier 2 LP are live and desk-decided each cycle; Tier 1
is USDC lending on Kamino (no LST/cbBTC lending reserve is configured). LP
pairs are coin/USDC (SOL/USDC, cbBTC/USDC) on Orca Whirlpools and
Meteora DLMM — not SOL/cbBTC or JitoSOL/SOL — because a coin/USDC LP is an
automated swing. Since the owner policy of 2026-09-09 an LP no longer
draws on the 20% swing sleeve: its coin side counts against the LP core
allowance and its USDC leg against the LP's own 40% share of NAV, whose
only cap is limits.lp_total_frac. No hard cumulative fraction cap is
enforced in the executor; every position is EXEC-owned. Single-asset vaults are
catalogued but have no executor. See as built §7.
6. Treasury allocator — no idle capital
The tiers say what is allowed; a dedicated allocator (a harvest-allocator
crate in nexus-solana) makes it continuous: every asset always sits in its
best venue, and every action can recall what it needs. It classifies venues
into a liquidity ladder:
| Tier | Venues | Recall | Holds |
|---|---|---|---|
| HOT | idle in VAULT | instant | gas + a small buffer; anything above it gets swept warm within hours |
| WARM | lending supply; JitoSOL (sellable instantly via Metis — staking costs no liquidity) | same-block, utilization-gated | ladder reserves, swing capital, the default coin stack |
| COLD | CLMM LP positions | minutes, range-dependent | long-term stack only |
Invariants, enforced deterministically each pass and at hourly reconciliation:
- Nothing idle — no balance sits hot above the buffer beyond a few hours. USD earns on lending; coins earn via LST/lending/LP.
- Rungs always fireable — unfired ladder budget is never COLD, and the lending-utilization alert doubles as a recallability alert: utilization spikes exactly during the crashes that fire rungs.
- Swing inventory stays liquid — coins the desk may sell into a rebound are never in an LP: a rebound is when you must sell now, and LP unwind latency plus impermanent loss both work against the sale. LP is reserved for the frozen long-term stack.
- Recall-before-act — rung fires, swing trades, and tranche funding all recall from the allocator first and proceed when funds land hot.
- Hysteresis — venues change only on a sustained APY spread, so yield is never churned into fees.
Allocation state (asset × venue, % idle, pending recalls, utilization headroom) surfaces on the monitoring HARVEST panel — "% idle ≈ 0" is itself a monitored health signal.
The harvest-allocator crate is not wired. "Nothing idle" is implemented as
(1) the executor's hygiene sweep — originally utilization recall above 92%,
repark below 88%, APY rotation ≥150 bps on a single read; superseded
2026-09-05 by the owner lending policy (yield-first, rare moves: recall
only on confirmed stress — 95% utilization or liquidity below 10× our
position on two sweeps — rotation only on a 2 pp spread sustained ≈ 24 h
with a 7-day cooldown; see
as built §5) —
(2) reserves decided by the decision officer
each cycle (the USDC float and SOL gas the sweep leaves hot; nothing
hardcoded), and (3) a sleeping-money block in every cycle prompt with
doctrine that treats idle SOL as a defect. Invariant 3 ("swing inventory is
never in an LP") is superseded by the held-coin LP clause, and since the
owner policy of 2026-09-09 the accounting is explicit: a held-coin LP's
coin side counts against the LP core allowance
(ACCUM_LP_CORE_SOL_MAX), its USDC leg against the LP's own 40% share
of NAV (capped only by limits.lp_total_frac), and neither against the
20% swing sleeve — that sleeve budgets resting swing orders and swing
inventory alone. See
as built §6.
7. Known gaps to build
The pre-build gap list is kept for history; the live list is as built §12.
- Telegram approval gate — built, command-based (
/pending,/approve <id>,/reject <id>,/basis) overoperator_digestsrows; it gates sells, CEX actions, fallback activation and breakout tranches — not a tranche-funding path. - Spot domain types — built (
harvest-domain). - Oracle entity keying — resolved: the price plane is asset-keyed
(
Sol,CbBtc). - Fleet-wide misses — Squads client (partial: ceremony builders, no spending limit), Pyth client, LP position service and key custody are built; multi-endpoint RPC failover is not.
Design work still to be documented before build (tracked here so the docs admit what they don't yet cover):
- Data model — the
accumnamespace collections: rungs, tranches, spot lots + cost basis, yield/allocator positions, recall queue, benchmark books. Deserves a data-model page once shapes firm up. - API surface — the concrete REST + MCP endpoint list for both
nexus-solana binaries (the platform's
apis/page pattern). - Oracle entity keying decision — mint-keyed entities vs synthetic symbols for cbBTC (flagged in item 3; a decision, not just a gap).
- Testing & simulation plan — golden-vector parity for the new guards (the platform's proven pattern), simulated Metis fills for the paper sleeve, LiteSVM pre-flight, and the $500 mainnet tranche protocol.
- Operational runbooks (internal docs, not public): Squads signing ceremony + signer-loss recovery, EXEC key generation/rotation, venue incident response, reconciliation-mismatch procedure.
- Desk cadence — the accumulation desk's base cycle + event-driven wake (see the accumulation desk spec, §6).
8. Build order
- ✅
nexus-solanarepo bootstrap: workspace + the two app binaries, vendor the copy-set crates fromprochain-crypto, gitops deployment. - ◐ Squads vault + EXEC wallet ✅; spending limit ✗; reconciliation loop ✅ (balances only, no expectation check).
- ✅ Pyth oracle source + trigger state machine (hardened guard: quorum, outlier gate, direct-route probes).
- ◐ Fills are single Metis swaps with a 75 bps cap; no clip loop.
- ✅ Fallback evaluation (approve-in) + breakout tranches + DCA runner + Telegram approval gate + weekly digest.
- ◐ Phase 3: Tier 1 lending ✅ (Kamino), Tier 0 staking ✅ (pool vs Metis), Tier 2 LP ✅ (Orca + Meteora, coin/USDC); allocator loop ✗ — replaced by executor hygiene + decided reserves.
- ◐ Monitoring: accumulation cycle health + self-healing ✅; fleet grid / rule engine ✗.
- ✅ Accumulation desk — built with a different contract and eight souls (see the desk page); went straight to live, no paper period.
- ✗ Shadow period / paper benchmark — did not happen.
Related
- HARVEST — as built — the running system
- nexus-solana — the chain plane
- Accumulation desk — the intelligent sleeve beside the ladder
- Monitoring & alerting — the fleet health UI
- Solana DeFi integrations
- Hermes parity — the (unrelated) coding-agent roadmap