$npx -y skills add agiprolabs/claude-trading-skills --skill dex-executionSolana DEX swap execution via Jupiter aggregator including quoting, transaction building, signing, and confirmation
| 1 | # DEX Execution — Solana Swap Execution via Jupiter |
| 2 | |
| 3 | Execute token swaps on Solana through Jupiter, the dominant DEX aggregator routing across Raydium, Orca, Meteora, Phoenix, Lifinity, and 20+ other venues. |
| 4 | |
| 5 | ## Overview |
| 6 | |
| 7 | Jupiter aggregates liquidity across all major Solana DEXes to find optimal swap routes. A single swap may split across multiple pools and hop through intermediate tokens to minimize price impact. The Jupiter v6 API handles route discovery, transaction building, and fee optimization — your code handles quoting, user confirmation, signing, and submission. |
| 8 | |
| 9 | **Base URL**: `https://quote-api.jup.ag/v6` |
| 10 | |
| 11 | ## Execution Pipeline |
| 12 | |
| 13 | Every swap follows this seven-step pipeline. Never skip steps 2-3 (display and confirm). |
| 14 | |
| 15 | ### Step 1 — Get Quote |
| 16 | |
| 17 | ```python |
| 18 | import httpx |
| 19 | |
| 20 | params = { |
| 21 | "inputMint": "So11111111111111111111111111111111111111112", # SOL |
| 22 | "outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", # USDC |
| 23 | "amount": 1_000_000_000, # 1 SOL in lamports |
| 24 | "slippageBps": 50, # 0.5% |
| 25 | } |
| 26 | resp = httpx.get("https://quote-api.jup.ag/v6/quote", params=params) |
| 27 | quote = resp.json() |
| 28 | ``` |
| 29 | |
| 30 | ### Step 2 — Display Quote to User |
| 31 | |
| 32 | Always show these fields before proceeding: |
| 33 | |
| 34 | | Field | Source | |
| 35 | |---|---| |
| 36 | | Input amount | `quote["inAmount"]` (in token decimals) | |
| 37 | | Output amount | `quote["outAmount"]` | |
| 38 | | Minimum received | `quote["otherAmountThreshold"]` | |
| 39 | | Price impact | `quote["priceImpactPct"]` | |
| 40 | | Route | `quote["routePlan"]` — DEXes used | |
| 41 | | Slippage | The `slippageBps` you requested | |
| 42 | |
| 43 | ### Step 3 — Require User Confirmation |
| 44 | |
| 45 | ``` |
| 46 | ⚠️ SWAP PREVIEW |
| 47 | Selling: 1.000 SOL |
| 48 | Buying: ~142.50 USDC |
| 49 | Min recv: 141.79 USDC (0.5% slippage) |
| 50 | Impact: 0.01% |
| 51 | Route: Raydium V4 → USDC |
| 52 | |
| 53 | Proceed? [y/N] |
| 54 | ``` |
| 55 | |
| 56 | **NEVER proceed without explicit "yes" from the user.** |
| 57 | |
| 58 | ### Step 4 — Build Transaction |
| 59 | |
| 60 | ```python |
| 61 | swap_body = { |
| 62 | "quoteResponse": quote, |
| 63 | "userPublicKey": "YourPubkeyBase58...", |
| 64 | "wrapAndUnwrapSol": True, |
| 65 | "dynamicComputeUnitLimit": True, |
| 66 | "prioritizationFeeLamports": "auto", |
| 67 | } |
| 68 | resp = httpx.post("https://quote-api.jup.ag/v6/swap", json=swap_body) |
| 69 | swap_data = resp.json() |
| 70 | swap_tx = swap_data["swapTransaction"] # base64-encoded transaction |
| 71 | ``` |
| 72 | |
| 73 | ### Step 5 — Sign Transaction |
| 74 | |
| 75 | ```python |
| 76 | import base64 |
| 77 | from solders.transaction import VersionedTransaction |
| 78 | from solders.keypair import Keypair |
| 79 | |
| 80 | raw_tx = base64.b64decode(swap_tx) |
| 81 | tx = VersionedTransaction.from_bytes(raw_tx) |
| 82 | keypair = Keypair.from_base58_string(os.environ["WALLET_PRIVATE_KEY"]) |
| 83 | tx.sign([keypair]) |
| 84 | ``` |
| 85 | |
| 86 | ### Step 6 — Submit Transaction |
| 87 | |
| 88 | ```python |
| 89 | rpc_url = os.environ.get("SOLANA_RPC_URL", "https://api.mainnet-beta.solana.com") |
| 90 | signed_bytes = bytes(tx) |
| 91 | payload = { |
| 92 | "jsonrpc": "2.0", "id": 1, |
| 93 | "method": "sendTransaction", |
| 94 | "params": [ |
| 95 | base64.b64encode(signed_bytes).decode(), |
| 96 | {"encoding": "base64", "skipPreflight": False, |
| 97 | "maxRetries": 3, "preflightCommitment": "confirmed"} |
| 98 | ], |
| 99 | } |
| 100 | resp = httpx.post(rpc_url, json=payload) |
| 101 | sig = resp.json()["result"] |
| 102 | print(f"Submitted: https://solscan.io/tx/{sig}") |
| 103 | ``` |
| 104 | |
| 105 | ### Step 7 — Confirm Transaction |
| 106 | |
| 107 | ```python |
| 108 | import time |
| 109 | |
| 110 | for attempt in range(30): |
| 111 | payload = { |
| 112 | "jsonrpc": "2.0", "id": 1, |
| 113 | "method": "getSignatureStatuses", |
| 114 | "params": [[sig], {"searchTransactionHistory": False}], |
| 115 | } |
| 116 | resp = httpx.post(rpc_url, json=payload) |
| 117 | status = resp.json()["result"]["value"][0] |
| 118 | if status and status.get("confirmationStatus") in ("confirmed", "finalized"): |
| 119 | print(f"Confirmed at slot {status['slot']}") |
| 120 | break |
| 121 | time.sleep(2) |
| 122 | else: |
| 123 | print("Transaction not confirmed within 60s — check explorer") |
| 124 | ``` |
| 125 | |
| 126 | ## Jupiter API v6 Endpoints |
| 127 | |
| 128 | | Endpoint | Method | Purpose | |
| 129 | |---|---|---| |
| 130 | | `/quote` | GET | Get best-price quote with routing | |
| 131 | | `/swap` | POST | Build a swap transaction from a quote | |
| 132 | | `/swap-instructions` | POST | Get individual instructions (advanced) | |
| 133 | | `/price?ids=token1,token2` | GET | Simple price lookup (v2) | |
| 134 | | `/tokens` | GET | List all supported tokens | |
| 135 | |
| 136 | See `references/jupiter_api.md` for full parameter and response documentation. |
| 137 | |
| 138 | ## Key Parameters |
| 139 | |
| 140 | ### Slippage (`slippageBps`) |
| 141 | |
| 142 | | Token Type | Recommended Range | Notes | |
| 143 | |---|---|---| |
| 144 | | SOL, USDC, major tokens | 50-100 (0.5-1%) | Stable liquidity | |
| 145 | | Mid-cap tokens | 100-300 (1-3%) | Variable liquidity | |
| 146 | | PumpFun / meme tokens | 500-2000 (5-20%) | Thin books, high volatility | |
| 147 | | New launches (<1h old) | 1000-3000 (10-30%) | Extreme volatility | |
| 148 | |
| 149 | ### Dynamic Slippage |
| 150 | |
| 151 | Set `dynamicSlippage: true` in the swap request to let Jupiter auto-adjust slippage based on current market conditions. Preferred for most use cases. |
| 152 | |
| 153 | ### Priority Fees (`prioritizationFeeLamports`) |
| 154 | |
| 155 | Priority fees determine transaction ordering within a block. |
| 156 | |
| 157 | | Level | microLamports | When to Use | |
| 158 | |---|---|---| |
| 159 | | Low |