Files

4.8 KiB

Design

Context

See proposal.md for motivation. Raydium already discovers position NFTs and decodes pool/position state but does not execute liquidity decrease. SolanaWallet provides external jup signer validation, signing/submission and SPL transfer with ATA creation; JupiterSwapService confirms exact-input swaps. The Hub has a constructor catalogue and explicit ordered process selection.

Goals / Non-Goals

Goals: Implement the specified pipeline with fresh direct RPC reads and exact eligibility math; leave an offline-verifiable, inactive deployment template.

Non-Goals: No generic strategy, service-container framework, durable pending transaction queue or new currency ValueTags.

Decisions

  • Keep the public service a domain marker, mirroring the burner; the reference implementation additionally owns NenjimProcess startup and AutoCloseable shutdown. One scheduled executor uses fixed delay and propagates interruption across step boundaries.
  • Keep the existing shared Hub graph eager; construct/register liquidity deployment configuration and dedicated passive dependencies only at the selected liquidity entry, as reflected by the Hub/Registry deltas.
  • Build a dedicated direct Raydium instance when selected so cached pool/position state cannot trigger stale decisions. Resolve currencies through CIS and programs/precision from validated mint accounts.
  • Finish NFT discovery first, then read a fresh pool state immediately before evaluating each owned positive-liquidity position. Pass that same state to withdrawal minimum-output math. Do not reuse a price across discovery or earlier withdrawals; an unusable pool read stops the remaining withdrawals in that iteration while swap and payout remain independent.
  • Compare squared Q64.64 values by exact cross multiplication. Decimal factors cancel because pool and position share mints. For reversed ordering compare current raw price to lower-bound raw price times the retained percentage. This avoids display rounding and inversion rounding.
  • Port the official CLMM integer tick algorithm into a small Raydium math helper, reusing it for exact integer principal amounts. Existing display math remains unchanged.
  • Execute decrease_liquidity_v2 (legacy and Token-2022) with owner NFT holding, personal/protocol position PDA, vaults, tick arrays, owner destination token accounts and bitmap extension. Reuse an existing owner holding for each pool/reward mint, validating its account's mint, owner, program and initialized state. Only fall back to an existing or idempotently created ATA when no holding exists; failed holdings discovery must not create an extra account. This preserves the existing wallet's single-account-per-mint contract. Request a 600,000 compute-unit limit for the combined operation. Account details stay in the Raydium implementation; a private legacy transaction encoder uses existing address codec, PDA and wallet primitives.
  • Validate pool and personal-position discriminators, token metadata and owner holding before signing. Apply explicit slippage to integer expected principal. Fail closed on unsupported transfer-affecting Token-2022 extensions rather than silently weakening minimums. Required reward accounts, if present, only collect into this wallet and never enter swaps/payouts.
  • Parse only conf/evelyn-liquidity.conf with format-version validation, unknown/duplicate key rejection and required keys. Deployment addresses/signer remain placeholders in the ignored local runtime file and tracked example. Existing Hub example stays unchanged.
  • Use controlled JUnit fixtures explicitly requested by issue #89, including transaction bytes. No test constructs a real signer or submits a financial operation.

Risks / Trade-offs

  • [Pool moves during discovery or earlier withdrawals] → Refresh price and eligibility for each position. Minimum principal limits protect received principal, not the harvest-distance threshold. Market movement after the final decision remains possible before execution; later iterations reread state.
  • [Unknown transaction outcome] → Log signature when available, preserve ordinary underlying confirmation; subsequent iterations use current balances/positions as requested.
  • [Mint extension or program layout changes] → Validate discriminators/layout and fail safely on unsupported extensions; document official source references and exact supported behavior.
  • [SOL starvation] → Document funding for transaction fees and token-account rent; no hidden token reserves.

Migration Plan

Copy/edit the example, bind a dedicated external signer, fund SOL and manually select evelyn.liquidity.prod in the Hub runtime plan. Stop/remove the selection to disable; positions and wallet balances remain the recovery state. Keep the OpenSpec change active for user review; no commit, push or deployment.