68: Await CONFIRMED on-chain outcomes for Jupiter Swap and Perps operations
This commit is contained in:
+2
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-08-11
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
## 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 `IOException`s 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
|
||||
|
||||
1. Add the common checked exception and update both public service contracts.
|
||||
2. Add compatible implementation constructor overloads and confirmation helpers.
|
||||
3. Update alarm actions for structured outcome reporting.
|
||||
4. 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.
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
## Why
|
||||
|
||||
Jupiter's provider responses currently end Swap and Perps operations without independently confirming the returned transaction signature on Solana. The shared `SolanaBlockChain.awaitTransaction()` API now makes it possible for these high-level operations to report success only after `CONFIRMED` on-chain success while preserving definitive failure and unknown-timeout outcomes.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Add a shared checked Jupiter outcome exception that preserves the submitted signature, requested commitment, and complete failed or timed-out Solana outcome.
|
||||
- Make Jupiter Swap independently await its validated execution signature at `CONFIRMED` before returning its existing result.
|
||||
- Make Jupiter Perps increase and decrease independently await their valid execution signatures at `CONFIRMED` through one common private policy helper.
|
||||
- Add validated constructor-injected confirmation timeouts while preserving existing constructors with a two-minute default.
|
||||
- Preserve Jupiter provider-response validation as a distinct prerequisite to Solana confirmation, including Swap actual-amount validation.
|
||||
- Add outcome-specific Perps alarm reporting without moving confirmation into alarm actions or introducing retries or resubmission.
|
||||
- Update affected public Javadoc and checked-exception declarations.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `jupiter-perps-transaction-confirmation`: Defines independent on-chain confirmation and alarm reporting for Jupiter Perps increase and decrease operations.
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `jupiter-swap-service`: Requires independent `CONFIRMED` Solana success after the existing Jupiter execution-response validation and defines structured failure and timeout handling.
|
||||
|
||||
## Impact
|
||||
|
||||
The Jupiter common API gains one checked exception. The Jupiter Swap and Perps APIs, their reference implementations, and the two Perps alarm actions gain corresponding confirmation and error propagation behavior. Existing transaction construction, signing, provider submission, wallet methods, pacing, and retry behavior remain unchanged.
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
## Purpose
|
||||
|
||||
Defines independent Solana confirmation and outcome reporting for completed Jupiter Perps increase and decrease submissions.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Confirmed Perps operation completion
|
||||
After the existing Perps increase or decrease flow produces a valid non-blank transaction signature, the service SHALL independently await that signature at `CONFIRMED`. It SHALL return the existing signature result only for `SUCCEEDED`; provider response validation and financial validation SHALL remain distinct prerequisites and SHALL not themselves constitute on-chain confirmation.
|
||||
|
||||
#### Scenario: Increase reaches confirmed success
|
||||
- **WHEN** an increase submission returns a valid signature and its independent `CONFIRMED` outcome is `SUCCEEDED`
|
||||
- **THEN** the service returns that signature
|
||||
|
||||
#### Scenario: Decrease reaches confirmed success
|
||||
- **WHEN** a decrease submission returns a valid signature and its independent `CONFIRMED` outcome is `SUCCEEDED`
|
||||
- **THEN** the service returns that signature
|
||||
|
||||
### Requirement: Structured exceptional outcomes
|
||||
The shared Jupiter API SHALL expose a checked outcome exception containing the known non-blank transaction signature, requested commitment, and complete transaction outcome. Construction SHALL reject null or blank signatures, null commitments, null outcomes, and `SUCCEEDED` outcomes. `FAILED` SHALL identify a definitive on-chain failure including its slot and compact Solana error, while `TIMED_OUT` SHALL identify an unknown outcome and explicitly warn against automatic equivalent resubmission.
|
||||
|
||||
#### Scenario: Confirmed on-chain failure
|
||||
- **WHEN** an increase or decrease signature reaches `CONFIRMED` with a `FAILED` outcome
|
||||
- **THEN** the service throws the checked outcome exception preserving the signature, `CONFIRMED`, slot, and complete compact Solana failure details
|
||||
|
||||
#### Scenario: Confirmation timeout
|
||||
- **WHEN** an increase or decrease signature produces a `TIMED_OUT` outcome
|
||||
- **THEN** the service throws the checked outcome exception preserving the signature, `CONFIRMED`, and unknown outcome without automatically resubmitting
|
||||
|
||||
#### Scenario: Successful outcome is supplied to exception
|
||||
- **WHEN** a caller attempts to construct the outcome exception with `SUCCEEDED` or inconsistent null or blank data
|
||||
- **THEN** construction fails immediately
|
||||
|
||||
### Requirement: Perps confirmation timeout policy
|
||||
The reference service SHALL accept a constructor-injected, non-null, strictly positive confirmation timeout and SHALL preserve its existing constructor with a two-minute default. The configured duration SHALL be forwarded unchanged and SHALL begin governing only when awaiting the already submitted signature starts. Increase and decrease SHALL apply the same confirmation and outcome policy.
|
||||
|
||||
#### Scenario: Existing constructor is used
|
||||
- **WHEN** the reference service is constructed without a confirmation timeout
|
||||
- **THEN** each submitted increase or decrease uses a two-minute confirmation timeout
|
||||
|
||||
#### Scenario: Custom timeout is used
|
||||
- **WHEN** the reference service is constructed with a positive duration
|
||||
- **THEN** each submitted increase or decrease forwards exactly that duration to `CONFIRMED` awaiting
|
||||
|
||||
#### Scenario: Invalid timeout is supplied
|
||||
- **WHEN** the reference service is constructed with a null, zero, or negative duration
|
||||
- **THEN** construction fails before any Perps operation can be submitted
|
||||
|
||||
### Requirement: Post-submission communication and interruption policy
|
||||
If independent confirmation throws an I/O error after a signature is known, the service SHALL throw an `IOException` whose message identifies the increase or decrease operation, includes the signature, and states that the on-chain outcome is unknown, retaining the original error as cause. `InterruptedException` SHALL propagate directly without another RPC or Jupiter request. Confirmation SHALL never submit, rebuild, re-sign, retry, or resubmit a transaction.
|
||||
|
||||
#### Scenario: Confirmation communication fails
|
||||
- **WHEN** independent confirmation throws an I/O error for a known Perps signature
|
||||
- **THEN** the service reports the operation, signature, and unknown outcome, preserves the original error, and performs no retry or resubmission
|
||||
|
||||
#### Scenario: Confirmation is interrupted
|
||||
- **WHEN** independent confirmation throws `InterruptedException`
|
||||
- **THEN** interruption propagates directly and no subsequent request occurs
|
||||
|
||||
### Requirement: Outcome-aware Perps alarm reporting
|
||||
Perps increase and decrease alarm actions SHALL rely on the Perps service for confirmation and SHALL distinguish structured `FAILED`, structured `TIMED_OUT`, and other errors. A failed report SHALL include operation, signature, confirmation slot, and compact Solana failure details. A timed-out report SHALL include operation, signature, unknown-outcome status, and that no equivalent transaction was automatically resubmitted. Alarm actions SHALL NOT invoke transaction awaiting themselves.
|
||||
|
||||
#### Scenario: Alarm operation fails on-chain
|
||||
- **WHEN** a Perps alarm action receives a structured `FAILED` outcome exception
|
||||
- **THEN** it reports the operation, signature, confirmation slot, and compact on-chain failure details distinctly from generic errors
|
||||
|
||||
#### Scenario: Alarm operation remains unknown
|
||||
- **WHEN** a Perps alarm action receives a structured `TIMED_OUT` outcome exception
|
||||
- **THEN** it reports the operation, signature, unknown outcome, and absence of automatic equivalent resubmission distinctly from generic errors
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Confirmed execution result validation
|
||||
The service SHALL first accept a Jupiter execution response only when it has status `Success`, explicitly has result code `0`, contains a non-blank transaction signature, and contains positive valid actual total input and output raw amounts. It SHALL convert each actual amount using the independently resolved precision of its mint. After this provider-response validation, the service SHALL independently await the returned signature on Solana at `CONFIRMED` using its configured confirmation timeout and SHALL return the already validated swap result only for a `SUCCEEDED` outcome. Non-success HTTP responses, malformed responses, expired or rejected swaps, failed or contradictory status/code combinations, missing result codes, blank signatures, and invalid result amounts SHALL remain provider failures and SHALL not be represented as successful swaps.
|
||||
|
||||
#### Scenario: Provider response and on-chain confirmation succeed
|
||||
- **WHEN** Jupiter reports status `Success`, code `0`, a signature, and valid actual total input and output amounts, and that signature independently reaches `CONFIRMED` with a `SUCCEEDED` outcome
|
||||
- **THEN** the service returns the signature and those actual amounts in human-readable units
|
||||
|
||||
#### Scenario: Jupiter rejects or fails execution
|
||||
- **WHEN** Jupiter returns a failed status, a missing or non-zero result code, a contradictory status/code combination, expiration, rejection, non-success HTTP status, malformed body, blank signature, or invalid actual amount
|
||||
- **THEN** the service reports an I/O failure without treating provider validation as an on-chain confirmation
|
||||
|
||||
#### Scenario: Provider succeeds but transaction fails on-chain
|
||||
- **WHEN** a fully validated Jupiter execution response contains a signature whose independent `CONFIRMED` outcome is `FAILED`
|
||||
- **THEN** the service throws a structured checked outcome exception preserving the signature, requested commitment, slot, and complete compact Solana failure details
|
||||
|
||||
#### Scenario: Provider succeeds but confirmation times out
|
||||
- **WHEN** a fully validated Jupiter execution response contains a signature whose independent `CONFIRMED` outcome is `TIMED_OUT`
|
||||
- **THEN** the service throws a structured checked outcome exception preserving the signature, requested commitment, and unknown outcome warning and does not automatically resubmit an equivalent transaction
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Swap confirmation timeout policy
|
||||
The reference service SHALL accept a constructor-injected, non-null, strictly positive confirmation timeout and SHALL preserve its existing constructor with a two-minute default. The configured duration SHALL be passed unchanged to independent confirmation after submission and SHALL begin governing only when awaiting the known signature starts.
|
||||
|
||||
#### Scenario: Valid custom timeout
|
||||
- **WHEN** a reference service is constructed with a positive duration and later obtains a validated execution signature
|
||||
- **THEN** it awaits that signature at `CONFIRMED` with exactly the supplied duration
|
||||
|
||||
#### Scenario: Invalid custom timeout
|
||||
- **WHEN** a reference service is constructed with a null, zero, or negative duration
|
||||
- **THEN** construction fails before any operation can be submitted
|
||||
|
||||
### Requirement: Post-submission communication and interruption policy
|
||||
If independent confirmation fails with an I/O error after the signature is known, the service SHALL throw an `IOException` whose message identifies the swap operation, includes the signature, and states that the on-chain outcome is unknown, with the original error retained as its cause. Interruption SHALL propagate directly as `InterruptedException` without another RPC or Jupiter request. Neither condition SHALL trigger rebuilding, re-signing, retrying, or resubmitting a transaction.
|
||||
|
||||
#### Scenario: Confirmation communication fails
|
||||
- **WHEN** independent confirmation throws an I/O error for a known submitted signature
|
||||
- **THEN** the service reports the signature and unknown on-chain outcome while preserving the original error and performs no retry or resubmission
|
||||
|
||||
#### Scenario: Confirmation is interrupted
|
||||
- **WHEN** independent confirmation throws `InterruptedException`
|
||||
- **THEN** that interruption propagates directly and the service performs no subsequent request
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
## 1. Public Jupiter API
|
||||
|
||||
- [x] 1.1 Add the checked, documented `JupiterTransactionOutcomeException` with validated structured signature, commitment, and failed/timed-out outcome access.
|
||||
- [x] 1.2 Update Jupiter Swap and Perps public Javadoc and checked-exception declarations through their API call chains.
|
||||
|
||||
## 2. Jupiter Service Confirmation
|
||||
|
||||
- [x] 2.1 Add a validated confirmation-timeout overload to `JupiterSwapServiceImpl`, retain its two-minute default constructor, and await validated Swap results at `CONFIRMED` without changing provider validation or submission behavior.
|
||||
- [x] 2.2 Add a validated confirmation-timeout overload to `AnchorIdlJupiterPerpsServiceImpl`, retain its two-minute default constructor, and route increase and decrease signatures through one private `CONFIRMED` outcome-policy helper.
|
||||
- [x] 2.3 Ensure both services preserve structured `FAILED` and `TIMED_OUT` outcomes, contextualize confirmation `IOException`s as unknown outcomes, propagate interruption directly, and perform no retry or resubmission.
|
||||
|
||||
## 3. Perps Alarm Reporting
|
||||
|
||||
- [x] 3.1 Update the increase alarm action to report `FAILED` and `TIMED_OUT` distinctly while leaving confirmation ownership in the Perps service.
|
||||
- [x] 3.2 Update the decrease alarm action to report `FAILED` and `TIMED_OUT` distinctly while leaving confirmation ownership in the Perps service.
|
||||
|
||||
## 4. Verification
|
||||
|
||||
- [x] 4.1 Compile main and test source sets without adding tests or executing live Jupiter/Solana transactions.
|
||||
- [x] 4.2 Run available relevant existing tests only if their runtime is non-live and practical.
|
||||
- [x] 4.3 Run strict OpenSpec validation and `git diff --check`.
|
||||
- [x] 4.4 Review the complete diff for checked-exception propagation, unchanged provider validations, exact timeout forwarding, direct interruption propagation, no retry/resubmission, no generated-source edits, and no unrelated changes.
|
||||
Reference in New Issue
Block a user