5.5 KiB
Design
Context
See proposal.md and issue #91. The burner currently loses a known timed-out swap's identity behind swapsSuspended. Jupiter retains its order's last valid block height internally, but structured outcomes expose no validity metadata and confirmation I/O failures expose a signature only in text. Solana awaiting already uses historical status lookup and a shared five-second gate.
Goals / Non-Goals
Goals: Resume buybacks after a safely resolved original transaction while maintaining duplicate prevention, process-local state and the existing burn path.
Non-Goals: Build persistent submission infrastructure or change token amount policy, provider selection, burn confirmation or worker scheduling.
Decisions
- Keep the shared transaction outcome enum unchanged. Add a small separate reconciliation result and original transaction-validity value in the Solana package, and a read-only reconciliation method. The cached decorator delegates it directly. An additive conservative default permits existing blockchain implementations to await but never infer expiry.
- Extend the existing structured Jupiter outcome exception with optional validity metadata while preserving the three-argument constructor used by perps. Add typed IOException and InterruptedException subclasses carrying submission-stage certainty, optional trustworthy signature, original validity and the original cause. Preparation failures are explicitly pre-submission; ambiguous execution failures without a signature retain manual suspension. A known confirmation signature is retained even when confirmation I/O or interruption fails.
- Capture a finalized pre-submission slot, taker address and the order's last valid block height. Extract the original recent blockhash from the serialized transaction message and reject a signer response that changes it. Bind the execution signature to the signed transaction's first signature when it is populated. A sponsor signature completed by Jupiter retains provider identity for status checks, but cannot prove expiry of the local payload. No unrelated latest blockhash participates in expiry evidence.
- Reconcile in a bounded thirty-second operation using the existing shared RPC gate/deadline. A historical status at CONFIRMED or stronger resolves success/failure. Any lower-commitment observation remains pending. For an absent signature, require finalized epoch height above the original validity height, the original blockhash to be invalid at that finalized context, local
minimumLedgerSlotat/before the original submission anchor, and a subsequent finalized signer-address history lookup withminContextSlotat/after that finalized context and no original signature. One page (limit 1000) must extend strictly before the submission anchor or exhaust the covered retained history; a full page ending at/after the anchor remains unresolved. Missing, pruned, stale, inconsistent or failed evidence remains unresolved. This trusts the configured RPC's retained-history contract; it does not treat a remote archive's earliest block as contiguous local coverage. - Pending burns retain absolute priority. Otherwise pending swaps are reconciled before input selection; resolution clears state and selection reloads wallet balances. Unresolved swaps block only new swaps and still reach the existing complete-EVE burn path. Never call
swap()as reconciliation or resubmit/re-sign an unresolved operation. - Log canonical symbol/UUID, attempted amount, known signature, status and next action. Log safe phase/cause classes instead of transport body, signer payload, transaction bytes or arbitrary cause messages.
Risks / Trade-offs
- History pruned before the retained anchor or incomplete/contradictory evidence → keep pending and diagnose the missing evidence; no speculative recovery.
- A process restart discards pending state → document external reconciliation before restart and retain no persistent journal.
- Additional read-only preparation/reconciliation calls add gate latency → use shared pacing and a bounded reconciliation deadline; add no immediate retry loop.
- RPC evidence cannot be independently audited against the entire chain → rely only on the configured history-enabled RPC's local-retention contract and preserve pending on detected uncertainty.
Primary references
- Solana historical signature status.
- Solana transaction retry guidance.
- minimumLedgerSlot identifies the lowest retained local ledger slot, which may advance as history is purged.
- isBlockhashValid supports commitment and minimum context slot.
- Finalized address history binds absence to a minimum finalized context; Agave rejects a finalized request if its highest super-majority root has not reached that context.
- Agave RPC implementation checks transaction-history availability for historical signature lookup; getFirstAvailableBlock may include BigTable and is not used as local coverage evidence.
Migration Plan
Deployment remains separate. Replace the application only after reconciling unknown transactions in any old process; restarting either version loses in-memory pending state. No configuration or history migration is required, and current reserves/maxima remain unchanged.