5.3 KiB
Context
Issue #67 introduced a generic, blocking SolanaBlockChain.awaitTransaction() operation with explicit commitment, timeout, and outcome semantics. Jupiter Swap and Perps already own their respective build, validation, signing, and single provider-submission flows, so they are the correct boundaries for adding independent Solana confirmation. Their public APIs and implementations are already package-separated even though they currently share this repository.
Goals / Non-Goals
Goals:
- Add one consistent Jupiter-level representation for definitive on-chain failure and unknown timeout.
- Keep provider-response validation visibly separate from the subsequent independent Solana confirmation.
- Preserve existing constructors and operation return types while making confirmation timeout an injectable high-level policy.
- Keep increase and decrease confirmation behavior identical and keep alarm reporting outcome-aware.
Non-Goals:
- Changing blockchain awaiting, wallet submission, transaction construction, signing, Jupiter provider submission, or financial validation.
- Adding retries, resubmission, persistent reconciliation, configuration changes, or automated tests.
- Integrating confirmation into burn, Evelyn, Discord, or other consumers.
Decisions
Put the outcome exception in the common Jupiter API package
JupiterTransactionOutcomeException will be a checked public exception in com.r35157.libs.jupiter, shared by Swap and Perps without making either API depend on the other. It will defensively validate and retain the signature, requested commitment, and complete SolanaTransactionOutcome. Its message will derive definitive-failure or unknown-timeout diagnostics from that structured state.
An exception local to each service was rejected because it would duplicate identical cross-provider outcome semantics and prevent callers such as alarm actions from applying one policy.
Confirm only after complete provider validation
Swap will build its JupiterSwapResult only after all existing /execute status, code, signature, and actual-amount checks pass, then await the result signature. Perps will await only after its existing execution response yields a valid non-blank txid. This maintains two explicit trust boundaries: Jupiter validates its response first; Solana independently establishes the on-chain outcome second.
Treating provider success as implicit confirmation was rejected because it is the gap this change closes. Replacing provider validation with Solana confirmation was rejected because on-chain status cannot validate Jupiter's reported token amounts or response contract.
Keep timeout policy immutable in each service instance
Each implementation will store a validated Duration. Existing constructors delegate to overloads using a two-minute constant. The duration is passed unchanged to each awaitTransaction() call at CONFIRMED, so pre-confirmation work does not consume it.
A configuration-file setting was rejected because issue #68 deliberately defines constructor policy only. A timeout in wallet or blockchain submission was rejected because confirmation belongs to the high-level operation.
Centralize confirmation policy at the smallest useful scope
Perps increase and decrease will call one private helper that invokes awaitTransaction() and switches on all three outcomes. Swap will use its own equivalent private helper because the implementations are separate future artifacts; sharing implementation mechanics across them would create an unnecessary coupling.
Both helpers wrap only confirmation IOExceptions with operation, signature, and unknown-outcome context, preserve the cause, allow InterruptedException to propagate directly, and never retry. This avoids accidentally changing existing pre-signature/provider error behavior.
Keep alarms presentation-only for confirmation results
The two alarm actions will catch JupiterTransactionOutcomeException before their generic error handling and format FAILED and TIMED_OUT separately. They will not call the blockchain API or attempt reconciliation, preserving the Jupiter service as owner of complete operation orchestration.
Risks / Trade-offs
- [A provider submission can succeed while confirmation communication fails] → Preserve the known signature, report the on-chain outcome as unknown, retain the cause, and prohibit automatic resubmission.
- [Synchronous confirmation extends operation latency] → Use an immutable configurable timeout with a safe two-minute default and preserve interruption.
- [Alarm reporting is transient and not reconciled] → Clearly label timeout as unknown; persistent reconciliation remains explicitly deferred.
- [Checked exception propagation affects callers at compile time] → Update both public service contracts and every affected call site in this repository consistently.
Migration Plan
- Add the common checked exception and update both public service contracts.
- Add compatible implementation constructor overloads and confirmation helpers.
- Update alarm actions for structured outcome reporting.
- Compile main and test source sets, run available non-live checks, and retain the active OpenSpec change for review.
Rollback consists of reverting this change as one unit; no data or configuration migration is involved.