Commit 77b9123
feat: add Jupiter V6 swap support (#516)
* feat: add Jupiter V6 swap support
Add helium_lib::jupiter module for token swaps via the Jupiter V6 REST
API. Calls the API directly instead of using the jup-ag crate (which
requires solana-sdk v3, incompatible with our v2).
- jupiter::Client with quote() and swap() methods
- JupiterError dedicated error type
- QuoteResponse serde types with pass-through for /swap endpoint
- Transaction handling: base64 decode → bincode deserialize → fresh
blockhash → re-sign
- helium-wallet `swap` CLI command for interactive token swaps
- Requires JUP_API_KEY env var; optional JUP_API_URL, JUP_SLIPPAGE_BPS
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(swap): replace eprintln with JSON quote fields in output
Include quote details (in_amount, out_amount, slippage, price_impact)
in the standard JSON output instead of using eprintln, matching the
pattern of all other wallet commands.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: promote futures to workspace, use TryFutureExt for async transforms
- Add futures to workspace dependencies, use workspace ref in
helium-lib and helium-wallet
- Use TryFutureExt::map_err/map_ok before .await per project style
- Fix clippy::redundant_closure in jupiter transaction decode
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(jupiter): address PR review findings
Security:
- Remove Debug derive from Client, implement manually with api_key
redacted to prevent secret leakage in logs
Error handling:
- Return JupiterError from swap() instead of top-level Error, matching
the onboarding module pattern of self-contained error types
- Add Solana and Signing variants to JupiterError for RPC/signing
failures within swap()
- Fail on invalid JUP_SLIPPAGE_BPS instead of silently falling back
- Truncate raw Jupiter API error bodies to 200 chars
Validation:
- Reject zero swap amounts in quote()
- Reject same input/output mint in quote()
- Add amount and finite-number validation in CLI swap command
Cleanup:
- Drop redundant .map_err() wrappers — plain ? with From impls
- Drop anyhow! wrapping in CLI — JupiterError flows via ? into
anyhow::Result like all other commands
- Make RoutePlan/SwapInfo pub(crate) — not needed by crate consumers
- Remove unused futures dep from helium-wallet (no longer needed)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: re-export solana_transaction_status from helium-lib
Allows downstream crates to use TransactionConfirmationStatus for
proper enum matching instead of string-based Debug output comparison.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(jupiter): make API key optional for keyless access
Jupiter offers keyless access at 0.5 RPS on api.jup.ag — sufficient
for individual CLI swap use. API key is only needed for higher rate
limits (production/automated use like alembic).
- api_key is now Option<String> on Client
- from_env() succeeds without JUP_API_KEY (keyless mode)
- x-api-key header only sent when key is present
- has_api_key() method for callers that require authenticated access
- Env tests use Mutex to avoid parallel test pollution
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(jupiter): migrate from dead V6 API to V2
Jupiter V6 endpoint (api.jup.ag/swap/v6) returns 404 — it has been
retired. Migrate to the V2 API which uses a single /order endpoint
that returns both quote data and the assembled transaction.
API changes:
- Single GET /order call replaces separate GET /quote + POST /swap
- swap() now takes input/output mints + amount directly (no separate
quote step needed)
- Returns (VersionedTransaction, block_height, OrderResponse) — the
OrderResponse contains quote data for display/recording
- taker param replaces the old SwapRequest.userPublicKey body field
- OrderResponse has inline error/errorCode/errorMessage fields
Also:
- Fix empty error body producing "HTTP 404:" — now shows
"empty response (HTTP 404)"
- Add SwapError variant for Jupiter-reported errors in 200 responses
- Add test for empty error body and error response deserialization
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(jupiter): RoutePlan.percent is f64 in V2 API, not u8
Jupiter V2 returns percent as a float (e.g. 76.39), not an integer.
Caused deserialization failure: "invalid type: floating point 76.39,
expected u8".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>1 parent aa0730f commit 77b9123
10 files changed
Lines changed: 506 additions & 3 deletions
File tree
- helium-lib
- src
- helium-wallet
- src
- cmd
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
29 | | - | |
| 29 | + | |
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
2 | 4 | | |
3 | 5 | | |
4 | 6 | | |
| |||
52 | 54 | | |
53 | 55 | | |
54 | 56 | | |
| 57 | + | |
| 58 | + | |
55 | 59 | | |
56 | 60 | | |
57 | 61 | | |
| |||
0 commit comments