
Raptor Dex
- 189 installs
- 257 repo stars
- Updated June 24, 2026
- agiprolabs/claude-trading-skills
raptor-dex is a Claude Code skill for driving Raptor, a self-hosted Solana DEX aggregator that routes swaps across 25+ DEXes via an HTTP API.
About
raptor-dex is a Claude Code skill for Raptor, a self-hosted Solana DEX aggregator by SolanaTracker. It documents the quote, swap, send-transaction, and status-tracking HTTP endpoints for multi-hop routing across 25+ DEXes, with local signing and Yellowstone Jet TPU submission. A developer uses it to build swap execution against a self-run Raptor binary with no rate limits or API key.
- Multi-hop swap routing across 25+ Solana DEXes via a self-hosted Rust binary
- Quote, swap, send-transaction, and status endpoints with local signing (private key never leaves the machine)
- Yellowstone Jet TPU submission with auto-retry; no rate limits and no API key
Raptor Dex by the numbers
- 189 all-time installs (skills.sh)
- Ranked #489 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
raptor-dex capabilities & compatibility
Free during public beta with no API key; requires you to self-host the Raptor binary and provide your own Solana RPC and Yellowstone gRPC endpoints.
- Capabilities
- dex aggregation · swap routing · transaction submission · quote comparison
- Use cases
- data analysis
- Platforms
- Linux · macOS
- Runs
- Runs locally
- Pricing
- Free
What raptor-dex says it does
Raptor is a self-hosted Rust binary that aggregates swap quotes across 25+ Solana DEXes.
Unlike Jupiter, Raptor runs on your own infrastructure with **no rate limits**, **no API key**, and **no dependency on external API availability**.
npx skills add https://github.com/agiprolabs/claude-trading-skills --skill raptor-dexAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 189 |
|---|---|
| repo stars | ★ 257 |
| Last updated | June 24, 2026 |
| Repository | agiprolabs/claude-trading-skills ↗ |
What it does
Get swap quotes and submit swaps across 25+ Solana DEXes through the self-hosted Raptor aggregator.
Who is it for?
Getting best-route swap quotes and executing Solana swaps through a self-hosted aggregator.
Skip if: Managed/hosted swap APIs with rate limits; Raptor must be self-hosted.
When should I use this skill?
You are building Solana swap execution and want self-hosted multi-DEX routing without an external API dependency.
What you get
Best-route swap quotes and submitted, locally-signed swap transactions across 25+ Solana DEXes.
- Best-route swap quote
- Unsigned swap transaction
- Submitted transaction signature and status
By the numbers
- 25+ Solana DEXes aggregated
- 7 HTTP API endpoints (quote, swap, swap-instructions, quote-and-swap, send-transaction, transaction, health)
- 1-4 max hops
Files
Raptor — Self-Hosted Solana DEX Aggregator
Raptor is a self-hosted Rust binary that aggregates swap quotes across 25+ Solana DEXes. Unlike Jupiter, Raptor runs on your own infrastructure with no rate limits, no API key, and no dependency on external API availability. Free during public beta.
- Program ID (Mainnet):
RaptorD5ojtsqDDtJeRsunPLg6GvLYNnwKJWxYE4m87 - GitHub: solanatracker/raptor-binary
- Docs: docs.solanatracker.io/raptor/overview
Quick Start
# Clone the binary repo (includes required signature file)
git clone https://github.com/solanatracker/raptor-binary
cd raptor-binary
# Run with required environment variables
export RPC_URL="https://your-solana-rpc.com"
export YELLOWSTONE_ENDPOINT="https://your-yellowstone-grpc.com"
export YELLOWSTONE_TOKEN="your-token" # if required by provider
./raptor
# Listens on 0.0.0.0:8080 by defaultRequirements: Solana RPC endpoint + Yellowstone gRPC endpoint (for pool indexing). Raptor uses very few RPC calls during normal operation since pool state is streamed via Yellowstone.
Signature file: The signature file must be in the same directory as the Raptor binary. It authenticates your instance and is included in the repo clone. If you move the binary, copy the signature file with it.
Execution Flow
1. GET /quote → Best route across 25+ DEXes
2. POST /swap → Unsigned versioned transaction
3. Sign locally → Your private key never leaves your machine
4. POST /send-transaction → Submit via Yellowstone Jet TPU
5. GET /transaction/{sig} → Confirm status (pending/confirmed/failed/expired)API Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /quote | Get swap quote with multi-hop routing |
POST | /swap | Build swap transaction from quote |
POST | /swap-instructions | Get swap instructions only (no tx wrapper) |
POST | /quote-and-swap | Quote + transaction in one request |
POST | /send-transaction | Submit via Yellowstone Jet TPU with auto-retry |
GET | /transaction/:signature | Track transaction status and parsed events |
GET | /health | Health check (pools, cache, Yellowstone connection) |
Get a Quote
import httpx
RAPTOR = "http://localhost:8080"
resp = httpx.get(f"{RAPTOR}/quote", params={
"inputMint": "So11111111111111111111111111111111111111112", # SOL
"outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", # USDC
"amount": 1_000_000_000, # 1 SOL in lamports
"slippageBps": 50,
})
quote = resp.json()
print(f"Output: {quote['amountOut']} lamports")
print(f"Price impact: {quote['priceImpact']}%")
print(f"Route: {len(quote['routePlan'])} hops")Quote Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
inputMint | string | Yes | Input token mint address |
outputMint | string | Yes | Output token mint address |
amount | integer | Yes | Amount in smallest unit (lamports) |
slippageBps | string | No | Basis points or "dynamic" (default: 50) |
dexes | string | No | Comma-separated DEX filter |
excludeDexes | string | No | DEXes to exclude |
maxHops | integer | No | 1-4 hops (default: 4) |
directRouteOnly | boolean | No | Only single-hop routes |
pools | string | No | Comma-separated pool address filter |
feeBps | integer | No | Platform fee 0-1000 bps |
feeAccount | string | No | Fee recipient wallet |
Build and Sign a Swap
import base64
import os
# Step 2: Build transaction from quote
resp = httpx.post(f"{RAPTOR}/swap", json={
"quoteResponse": quote,
"userPublicKey": "YOUR_WALLET_PUBKEY",
"wrapUnwrapSol": True,
"txVersion": "v0",
"priorityFee": "auto", # min|low|auto|medium|high|veryHigh|turbo|unsafeMax
"maxPriorityFee": 100_000, # cap in lamports
})
swap = resp.json()
# swap["swapTransaction"] is base64-encoded unsigned transaction
# Step 3: Sign locally (private key never sent to Raptor)
from solders.transaction import VersionedTransaction
from solders.keypair import Keypair
tx_bytes = base64.b64decode(swap["swapTransaction"])
tx = VersionedTransaction.from_bytes(tx_bytes)
keypair = Keypair.from_base58_string(os.getenv("PRIVATE_KEY"))
signed_tx = VersionedTransaction(tx.message, [keypair])
signed_b64 = base64.b64encode(bytes(signed_tx)).decode()
# Step 4: Submit via Yellowstone Jet TPU
resp = httpx.post(f"{RAPTOR}/send-transaction", json={
"transaction": signed_b64,
})
result = resp.json()
print(f"Signature: {result['signature']}")
# Step 5: Track status
resp = httpx.get(f"{RAPTOR}/transaction/{result['signature']}")
status = resp.json()
# status: pending | confirmed | failed | expired
print(f"Status: {status['status']}, Latency: {status.get('latency_ms')}ms")WebSocket Streaming
Real-time quote streaming with slot-based updates when pool state changes:
import asyncio, websockets, json
async def stream_quotes():
async with websockets.connect("ws://localhost:8080/stream") as ws:
await ws.send(json.dumps({
"type": "subscribe",
"inputMint": "So11111111111111111111111111111111111111112",
"outputMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": 1_000_000_000,
"slippageBps": "50",
}))
async for msg in ws:
data = json.loads(msg)
if data.get("type") == "quote":
print(f"Out: {data['data']['amountOut']} (slot {data['data']['contextSlot']})")/stream/swap variant pre-builds transactions ready for signing, with automatic resend every 10 slots to prevent expiry.
Supported DEXes (25+)
Raydium: AMM, CLMM, CPMM, LaunchLab | Meteora: DLMM, Dynamic AMM, DAMM V2, Curve, DBC | Orca: Whirlpool v1/v2 | Bonding Curves: Pump.fun, Pumpswap, Heaven, MoonIt, Boopfun | PropAMM: Humidifi, Tessera, Solfi V1/V2, AlphaQ, ZeroFi, BisonFi, GoonFi V2 | Other: FluxBeam, PancakeSwap V3
Configuration
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
RPC_URL | Yes | — | Solana RPC endpoint |
YELLOWSTONE_ENDPOINT | Yes | — | Yellowstone gRPC endpoint |
YELLOWSTONE_TOKEN | No | — | Auth token (if provider requires) |
BIND_ADDR | No | 0.0.0.0:8080 | Listen address |
INCLUDE_DEXES | No | all | Comma-separated DEX filter |
EXCLUDE_DEXES | No | none | DEXes to exclude |
WORKER_THREADS | No | CPU cores | Worker thread count |
ENABLE_WEBSOCKET | No | false | Enable /stream endpoints |
ENABLE_YELLOWSTONE_JET | No | false | Enable Jet TPU for /send-transaction |
ENABLE_ARBITRAGE | No | false | Enable circular arbitrage routes |
CLI Flags
./raptor --include-dexes raydium,orca,meteora \
--enable-websocket \
--enable-yellowstone-jet \
--workers 4DEX Filtering Examples
# Only bonding curve DEXes (for PumpFun sniping)
INCLUDE_DEXES="pumpfun,pumpswap,heaven,moonit,boopfun" ./raptor
# Only major AMMs
INCLUDE_DEXES="raydium,orca,meteora" ./raptorPriority Fee Levels
| Level | Use Case |
|---|---|
min / low | Cost-saving, non-urgent |
auto / medium | Recommended default |
high / veryHigh | Faster confirmation |
turbo / unsafeMax | Maximum speed, competitive scenarios |
Raptor vs Jupiter
| Feature | Raptor | Jupiter |
|---|---|---|
| Self-hosted | Yes | No |
| Rate limits | None (your hardware) | API rate limits |
| DEX coverage | 25+ | 30+ |
| Latency | Network-local | Remote API |
| Cost | Free (beta) | Free (hosted) |
| Tx submission | Yellowstone Jet TPU | Standard RPC |
| On-chain program | RaptorD5o... | JUP... |
| API key required | No | No |
Deployment
See references/deployment.md for Docker, Fly.io, and bare metal setup.
Files
References
references/api_reference.md— Complete HTTP and WebSocket API with request/response schemasreferences/deployment.md— Docker, Fly.io, bare metal deployment with signature file handling- docs.solanatracker.io/raptor/overview — Official Raptor documentation
- github.com/solanatracker/raptor-binary — Binary releases and README
Scripts
scripts/raptor_quote.py— Get and compare swap quotes with --demo modescripts/raptor_swap.py— Full swap flow: quote → build → sign → submit → confirm (simulation only in --demo)
Raptor API Reference
Complete HTTP and WebSocket API for the Raptor DEX aggregator.
HTTP Endpoints
GET /quote
Get the best swap quote across all supported DEXes.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
inputMint | string | Yes | Input token mint address |
outputMint | string | Yes | Output token mint address |
amount | integer | Yes | Amount in smallest unit (lamports for SOL) |
slippageBps | string | No | Basis points (e.g. 50) or "dynamic" |
dexes | string | No | Comma-separated DEX whitelist |
excludeDexes | string | No | Comma-separated DEX blacklist |
maxHops | integer | No | Max routing hops 1-4 (default: 4) |
directRouteOnly | boolean | No | Only single-hop routes |
pools | string | No | Comma-separated pool address filter |
mints | string | No | Comma-separated intermediate mint allowlist |
feeBps | integer | No | Platform fee 0-1000 bps |
feeAccount | string | No | Fee recipient wallet |
Response:
{
"amountIn": 1000000000,
"amountOut": 156234567,
"otherAmountThreshold": 155453000,
"priceImpact": 0.12,
"slippageBps": 50,
"routePlan": [
{
"inputMint": "So11...",
"outputMint": "EPjF...",
"amountIn": 1000000000,
"amountOut": 156234567,
"dex": "raydium_clmm",
"pool": "pool_address..."
}
],
"contextSlot": 298765432
}POST /swap
Build a complete swap transaction from a quote.
Request body:
{
"quoteResponse": { /* from GET /quote */ },
"userPublicKey": "wallet_pubkey",
"wrapUnwrapSol": true,
"txVersion": "v0",
"priorityFee": "auto",
"maxPriorityFee": 100000,
"computeUnitLimit": null,
"tip": null,
"destinationTokenAccount": null
}Response:
{
"swapTransaction": "base64_encoded_unsigned_transaction"
}POST /swap-instructions
Same as /swap but returns instructions only (no transaction wrapper). Useful for composing with other instructions.
POST /quote-and-swap
Combined quote + transaction build in a single request. Accepts all /quote params plus /swap body fields.
POST /send-transaction
Submit a signed transaction via Yellowstone Jet TPU. Requires --enable-yellowstone-jet.
Request body:
{
"transaction": "base64_encoded_signed_transaction"
}Response:
{
"signature": "5abc..."
}Raptor automatically retries submission for ~30 seconds or until confirmed.
GET /transaction/:signature
Track a submitted transaction's status.
Response:
{
"signature": "5abc...",
"status": "confirmed",
"latency_ms": 450,
"slot": 298765433,
"events": [
{
"name": "SwapEvent",
"parsed": {
"amountIn": 1000000000,
"amountOut": 156234567,
"inputMint": "So11...",
"outputMint": "EPjF..."
}
}
]
}Status values: pending, confirmed, failed, expired
GET /health
Returns pool count, cache status, and Yellowstone connection health.
---
WebSocket API
/stream — Real-time Quote Streaming
Connect and subscribe to receive updated quotes whenever pool state changes.
Subscribe:
{
"type": "subscribe",
"inputMint": "So11...",
"outputMint": "EPjF...",
"amount": 1000000000,
"slippageBps": "50"
}Quote update message:
{
"type": "quote",
"data": {
"amountIn": 1000000000,
"amountOut": 156234567,
"priceImpact": 0.12,
"routePlan": [...],
"contextSlot": 298765432
}
}Unsubscribe: {"type": "unsubscribe", "inputMint": "...", "outputMint": "..."}
/stream/swap — Streaming Swap Transactions
Same as /stream but returns pre-built transactions ready to sign. Automatically resends after 10 slots without an update to prevent transaction expiry.
Subscribe (additional fields):
{
"type": "subscribe",
"inputMint": "So11...",
"outputMint": "EPjF...",
"amount": 1000000000,
"slippageBps": "50",
"userPublicKey": "wallet_pubkey",
"priorityFee": "auto",
"tip": null
}Swap update message:
{
"type": "swap",
"data": {
"swapTransaction": "base64_unsigned_tx",
"quote": { /* full quote data */ }
}
}---
Error Codes
| Code | Meaning |
|---|---|
| 400 | Invalid parameters or transaction |
| 404 | Transaction not tracked / token not found |
| 503 | Service unavailable (pool indexer still loading, Yellowstone disconnected) |
Priority Fee Levels
| Level | Description |
|---|---|
min / low | Lowest fees, may take longer |
auto / medium | Recommended — balances cost and speed |
high / veryHigh | Higher fees for faster landing |
turbo / unsafeMax | Maximum priority, use for competitive scenarios |
Fees are calculated per-route and per-DEX based on recent fee data.
Raptor Deployment Guide
Prerequisites
- Solana RPC endpoint — Any RPC provider (Helius, Triton, QuickNode, etc.)
- Yellowstone gRPC endpoint — Required for pool state streaming (Helius, Triton, Shyft)
- Signature file — Must be in the same working directory as the binary (included in repo clone)
Raptor uses very few RPC calls during normal operation since pool state is streamed via Yellowstone gRPC.
Signature File
The signature file authenticates your Raptor instance. It is required and must be in the same directory where the binary runs.
# After cloning, both files are present:
ls raptor-binary/
# raptor ← the binary
# signature ← required auth file
# If you move the binary, ALWAYS copy the signature file too
cp raptor /opt/raptor/
cp signature /opt/raptor/
cd /opt/raptor && ./raptor # signature must be in working directoryWithout the signature file, Raptor will fail to start.
Bare Metal / VPS
# Option A: Clone from GitHub
git clone https://github.com/solanatracker/raptor-binary
cd raptor-binary
# Option B: Download binary directly
curl -L https://github.com/solanatracker/raptor/releases/latest/download/raptor-linux-amd64 -o raptor
chmod +x raptor
# You still need the signature file from the repo
# Set environment and run
export RPC_URL="https://your-rpc.com"
export YELLOWSTONE_ENDPOINT="https://your-yellowstone.com"
export YELLOWSTONE_TOKEN="your-token"
./raptorRecommended: systemd Service
# /etc/systemd/system/raptor.service
[Unit]
Description=Raptor DEX Aggregator
After=network.target
[Service]
Type=simple
User=raptor
WorkingDirectory=/opt/raptor
ExecStart=/opt/raptor/raptor
Environment=RPC_URL=https://your-rpc.com
Environment=YELLOWSTONE_ENDPOINT=https://your-yellowstone.com
Environment=YELLOWSTONE_TOKEN=your-token
Environment=ENABLE_WEBSOCKET=true
Environment=ENABLE_YELLOWSTONE_JET=true
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now raptor
sudo journalctl -u raptor -f # watch logsDocker
FROM ubuntu:22.04
COPY raptor /usr/local/bin/raptor
COPY signature /usr/local/bin/signature
RUN chmod +x /usr/local/bin/raptor
WORKDIR /usr/local/bin
CMD ["raptor"]docker build -t raptor .
docker run -d \
-e RPC_URL="https://your-rpc.com" \
-e YELLOWSTONE_ENDPOINT="https://your-yellowstone.com" \
-e YELLOWSTONE_TOKEN="your-token" \
-e ENABLE_WEBSOCKET=true \
-p 8080:8080 \
raptorFly.io
# fly.toml
app = "my-raptor"
primary_region = "ewr" # East US — pick closest to your RPC
[build]
dockerfile = "Dockerfile"
[env]
RPC_URL = "https://your-rpc.com"
YELLOWSTONE_ENDPOINT = "https://your-yellowstone.com"
INCLUDE_DEXES = "raydium,orca,meteora,pumpfun,pumpswap"
ENABLE_WEBSOCKET = "true"
ENABLE_YELLOWSTONE_JET = "true"
[[services]]
internal_port = 8080
protocol = "tcp"
[[services.ports]]
port = 443
handlers = ["tls", "http"]
[[vm]]
size = "shared-cpu-2x"
memory = "4gb"fly secrets set YELLOWSTONE_TOKEN="your-token"
fly deployDEX Filter Presets
# PumpFun sniping — only bonding curves
INCLUDE_DEXES="pumpfun,pumpswap,heaven,moonit,boopfun" ./raptor
# Major AMMs only
INCLUDE_DEXES="raydium,orca,meteora" ./raptor
# Everything except bonding curves
EXCLUDE_DEXES="pumpfun,pumpswap,heaven,moonit,boopfun" ./raptorPerformance Tuning
| Setting | Recommendation |
|---|---|
WORKER_THREADS | Match CPU cores (default). For quote-heavy loads, try 2x cores |
RPC_RATE_LIMIT | Set to your RPC provider's limit to avoid 429s |
| Region | Co-locate with your RPC and Yellowstone providers |
| Memory | 4GB minimum recommended for full DEX indexing |
Health Check
curl http://localhost:8080/health
# Returns: pool count, cache status, Yellowstone connection stateTroubleshooting
| Issue | Fix |
|---|---|
| Slow startup (1-2 min) | Normal — pool indexing via Yellowstone. Use --no-pool-indexer to skip (quotes may be incomplete) |
| Quote returns 0 output | Token has no liquidity on included DEXes. Check INCLUDE_DEXES |
| Transaction fails | Check slippage, priority fee, and blockhash freshness |
| Signature file missing | Copy from repo clone to working directory |
| WebSocket not connecting | Set ENABLE_WEBSOCKET=true or --enable-websocket |
/send-transaction 503 | Set ENABLE_YELLOWSTONE_JET=true and verify Yellowstone endpoint |
#!/usr/bin/env python3
"""Get and compare swap quotes from Raptor DEX aggregator.
Demonstrates the /quote endpoint with various parameters including
DEX filtering, multi-hop control, and slippage configuration.
Usage:
python scripts/raptor_quote.py --demo
python scripts/raptor_quote.py --input So11... --output EPjF... --amount 1000000000
Dependencies:
uv pip install httpx
Environment Variables:
RAPTOR_URL: Raptor instance URL (default: http://localhost:8080)
"""
import argparse
import json
import os
import sys
from typing import Optional
RAPTOR_URL = os.getenv("RAPTOR_URL", "http://localhost:8080")
# Well-known Solana token mints
SOL_MINT = "So11111111111111111111111111111111111111112"
USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
USDT_MINT = "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"
# ── Demo Data ───────────────────────────────────────────────────────
DEMO_QUOTE_SOL_USDC = {
"amountIn": 1_000_000_000,
"amountOut": 156_234_567,
"otherAmountThreshold": 155_453_394,
"priceImpact": 0.03,
"slippageBps": 50,
"routePlan": [
{
"inputMint": SOL_MINT,
"outputMint": USDC_MINT,
"amountIn": 1_000_000_000,
"amountOut": 156_234_567,
"dex": "raydium_clmm",
"pool": "7XawhbbxtsRcQA8KTkHT9f9nc6d69UwqCDh6U5EEbEmX",
}
],
"contextSlot": 298_765_432,
}
DEMO_QUOTE_SOL_USDC_MULTIHOP = {
"amountIn": 1_000_000_000,
"amountOut": 156_189_234,
"otherAmountThreshold": 155_408_288,
"priceImpact": 0.05,
"slippageBps": 50,
"routePlan": [
{
"inputMint": SOL_MINT,
"outputMint": USDT_MINT,
"amountIn": 1_000_000_000,
"amountOut": 156_300_000,
"dex": "orca_whirlpool",
"pool": "4GkRbcYg1VKsZropgai4dMf2Nj2PkXNLf43knFpavrSi",
},
{
"inputMint": USDT_MINT,
"outputMint": USDC_MINT,
"amountIn": 156_300_000,
"amountOut": 156_189_234,
"dex": "meteora_dlmm",
"pool": "ARwi1S4DaiTG5DX7S4M4ZsrXqpMD1MrTmbu9ue2tpmEq",
},
],
"contextSlot": 298_765_435,
}
DEMO_QUOTE_FILTERED = {
"amountIn": 1_000_000_000,
"amountOut": 156_100_000,
"otherAmountThreshold": 155_319_500,
"priceImpact": 0.08,
"slippageBps": 50,
"routePlan": [
{
"inputMint": SOL_MINT,
"outputMint": USDC_MINT,
"amountIn": 1_000_000_000,
"amountOut": 156_100_000,
"dex": "orca_whirlpool_v2",
"pool": "Czfq3xZZDmsdGdUyrNLtRhGc47cXcZtLG4crryfu44zE",
}
],
"contextSlot": 298_765_438,
}
# ── Core Functions ──────────────────────────────────────────────────
def get_quote(
input_mint: str,
output_mint: str,
amount: int,
slippage_bps: int = 50,
dexes: Optional[str] = None,
max_hops: Optional[int] = None,
direct_only: bool = False,
) -> dict:
"""Get a swap quote from Raptor.
Args:
input_mint: Input token mint address.
output_mint: Output token mint address.
amount: Amount in smallest unit (lamports for SOL).
slippage_bps: Slippage tolerance in basis points.
dexes: Comma-separated DEX filter.
max_hops: Maximum routing hops (1-4).
direct_only: Only return single-hop routes.
Returns:
Quote response dict.
"""
import httpx
params: dict = {
"inputMint": input_mint,
"outputMint": output_mint,
"amount": amount,
"slippageBps": slippage_bps,
}
if dexes:
params["dexes"] = dexes
if max_hops is not None:
params["maxHops"] = max_hops
if direct_only:
params["directRouteOnly"] = "true"
resp = httpx.get(f"{RAPTOR_URL}/quote", params=params, timeout=10.0)
resp.raise_for_status()
return resp.json()
def display_quote(quote: dict, label: str = "Quote") -> None:
"""Display a quote in human-readable format.
Args:
quote: Quote response dict.
label: Display label.
"""
amount_in = quote["amountIn"]
amount_out = quote["amountOut"]
impact = quote.get("priceImpact", 0)
slippage = quote.get("slippageBps", 0)
route = quote.get("routePlan", [])
slot = quote.get("contextSlot", 0)
# Assume SOL input (9 decimals) and USDC output (6 decimals)
sol_in = amount_in / 1e9
usdc_out = amount_out / 1e6
price = usdc_out / sol_in if sol_in > 0 else 0
print(f"\n{'=' * 50}")
print(f" {label}")
print(f"{'=' * 50}")
print(f" Input: {sol_in:.4f} SOL ({amount_in:,} lamports)")
print(f" Output: {usdc_out:.4f} USDC ({amount_out:,} units)")
print(f" Eff. Price: ${price:.4f} per SOL")
print(f" Price Impact: {impact:.4f}%")
print(f" Slippage: {slippage} bps")
print(f" Hops: {len(route)}")
print(f" Slot: {slot:,}")
if route:
print(f"\n Route:")
for i, hop in enumerate(route):
dex = hop.get("dex", "unknown")
pool = hop.get("pool", "")[:12] + "..."
print(f" Hop {i + 1}: {dex} via {pool}")
# ── Main ────────────────────────────────────────────────────────────
def main() -> None:
"""Get and compare Raptor swap quotes."""
parser = argparse.ArgumentParser(description="Raptor quote comparison")
parser.add_argument("--demo", action="store_true", help="Use mock data")
parser.add_argument("--input", type=str, default=SOL_MINT, help="Input mint")
parser.add_argument("--output", type=str, default=USDC_MINT, help="Output mint")
parser.add_argument("--amount", type=int, default=1_000_000_000, help="Amount in lamports")
args = parser.parse_args()
if args.demo:
print("=== RAPTOR QUOTE COMPARISON (Demo Mode) ===")
print(f"Raptor URL: {RAPTOR_URL} (not connected in demo)\n")
display_quote(DEMO_QUOTE_SOL_USDC, "Default Quote (all DEXes, up to 4 hops)")
display_quote(DEMO_QUOTE_SOL_USDC_MULTIHOP, "Multi-hop Route (SOL → USDT → USDC)")
display_quote(DEMO_QUOTE_FILTERED, "Filtered Quote (Orca only, direct route)")
# Compare
best_out = DEMO_QUOTE_SOL_USDC["amountOut"]
worst_out = DEMO_QUOTE_FILTERED["amountOut"]
diff_bps = (best_out - worst_out) / best_out * 10_000
print(f"\n{'=' * 50}")
print(f" COMPARISON")
print(f"{'=' * 50}")
print(f" Best output: {best_out / 1e6:.4f} USDC (all DEXes)")
print(f" Worst output: {worst_out / 1e6:.4f} USDC (Orca only)")
print(f" Difference: {diff_bps:.1f} bps ({(best_out - worst_out) / 1e6:.4f} USDC)")
print()
return
# Live mode
try:
import httpx # noqa: F811
except ImportError:
print("httpx is required. Install with: uv pip install httpx")
sys.exit(1)
print(f"Fetching quotes from {RAPTOR_URL}...")
try:
q_default = get_quote(args.input, args.output, args.amount)
display_quote(q_default, "Default Quote")
q_direct = get_quote(args.input, args.output, args.amount, direct_only=True)
display_quote(q_direct, "Direct Route Only")
except Exception as e:
print(f"Error: {e}")
print("Is Raptor running? Check RAPTOR_URL environment variable.")
sys.exit(1)
print()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Full Raptor swap flow: quote → build → sign → submit → confirm.
Demonstrates the complete swap lifecycle using Raptor's HTTP API.
In --demo mode, uses mock data and simulates each step without
connecting to Raptor or signing any transactions.
Usage:
python scripts/raptor_swap.py --demo
python scripts/raptor_swap.py --input So11... --output EPjF... --amount 1000000000
Dependencies:
uv pip install httpx
uv pip install solders (for live signing only)
Environment Variables:
RAPTOR_URL: Raptor instance URL (default: http://localhost:8080)
PRIVATE_KEY: Base58-encoded private key (live mode only, NEVER hardcode)
"""
import argparse
import base64
import json
import os
import sys
import time
from typing import Optional
RAPTOR_URL = os.getenv("RAPTOR_URL", "http://localhost:8080")
SOL_MINT = "So11111111111111111111111111111111111111112"
USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
# ── Demo Data ───────────────────────────────────────────────────────
DEMO_QUOTE = {
"amountIn": 100_000_000,
"amountOut": 15_623_456,
"otherAmountThreshold": 15_545_339,
"priceImpact": 0.02,
"slippageBps": 50,
"routePlan": [
{
"inputMint": SOL_MINT,
"outputMint": USDC_MINT,
"amountIn": 100_000_000,
"amountOut": 15_623_456,
"dex": "raydium_clmm",
"pool": "7XawhbbxtsRcQA8KTkHT9f9nc6d69UwqCDh6U5EEbEmX",
}
],
"contextSlot": 298_765_432,
}
DEMO_SWAP_TX = base64.b64encode(b"DEMO_UNSIGNED_TRANSACTION_BYTES_" * 4).decode()
DEMO_SIGNATURE = "5RzEHTnf5bLFDhWdPz1MzBE5c8K5MZxKiVrt7hL8cmH7aJBrFQ2DGNYw5jNzVQ6gTk3BQkXyL8v9cCXW4HFnmFy"
# ── Core Functions ──────────────────────────────────────────────────
def step_1_get_quote(
input_mint: str, output_mint: str, amount: int, slippage_bps: int = 50
) -> dict:
"""Step 1: Get swap quote from Raptor.
Args:
input_mint: Input token mint.
output_mint: Output token mint.
amount: Amount in smallest unit.
slippage_bps: Slippage tolerance.
Returns:
Quote response.
"""
import httpx
resp = httpx.get(
f"{RAPTOR_URL}/quote",
params={
"inputMint": input_mint,
"outputMint": output_mint,
"amount": amount,
"slippageBps": slippage_bps,
},
timeout=10.0,
)
resp.raise_for_status()
return resp.json()
def step_2_build_swap(
quote: dict,
user_pubkey: str,
priority_fee: str = "auto",
max_priority_fee: int = 100_000,
) -> str:
"""Step 2: Build unsigned swap transaction.
Args:
quote: Quote response from step 1.
user_pubkey: Wallet public key.
priority_fee: Fee level (min/low/auto/medium/high/veryHigh/turbo/unsafeMax).
max_priority_fee: Maximum priority fee in lamports.
Returns:
Base64-encoded unsigned transaction.
"""
import httpx
resp = httpx.post(
f"{RAPTOR_URL}/swap",
json={
"quoteResponse": quote,
"userPublicKey": user_pubkey,
"wrapUnwrapSol": True,
"txVersion": "v0",
"priorityFee": priority_fee,
"maxPriorityFee": max_priority_fee,
},
timeout=10.0,
)
resp.raise_for_status()
return resp.json()["swapTransaction"]
def step_3_sign_transaction(tx_b64: str, private_key_b58: str) -> str:
"""Step 3: Sign the transaction locally.
Args:
tx_b64: Base64-encoded unsigned transaction.
private_key_b58: Base58-encoded private key.
Returns:
Base64-encoded signed transaction.
"""
from solders.keypair import Keypair
from solders.transaction import VersionedTransaction
tx_bytes = base64.b64decode(tx_b64)
tx = VersionedTransaction.from_bytes(tx_bytes)
keypair = Keypair.from_base58_string(private_key_b58)
signed = VersionedTransaction(tx.message, [keypair])
return base64.b64encode(bytes(signed)).decode()
def step_4_send_transaction(signed_tx_b64: str) -> str:
"""Step 4: Submit signed transaction via Yellowstone Jet TPU.
Args:
signed_tx_b64: Base64-encoded signed transaction.
Returns:
Transaction signature.
"""
import httpx
resp = httpx.post(
f"{RAPTOR_URL}/send-transaction",
json={"transaction": signed_tx_b64},
timeout=30.0,
)
resp.raise_for_status()
return resp.json()["signature"]
def step_5_confirm_transaction(signature: str, timeout_s: int = 30) -> dict:
"""Step 5: Wait for transaction confirmation.
Args:
signature: Transaction signature.
timeout_s: Maximum wait time in seconds.
Returns:
Transaction status response.
"""
import httpx
start = time.time()
while time.time() - start < timeout_s:
resp = httpx.get(f"{RAPTOR_URL}/transaction/{signature}", timeout=10.0)
if resp.status_code == 404:
time.sleep(1)
continue
resp.raise_for_status()
status = resp.json()
if status.get("status") in ("confirmed", "failed", "expired"):
return status
time.sleep(1)
return {"status": "timeout", "signature": signature}
def display_step(step_num: int, title: str, details: dict) -> None:
"""Display a step result.
Args:
step_num: Step number.
title: Step title.
details: Key-value pairs to display.
"""
print(f"\n Step {step_num}: {title}")
print(f" {'─' * 40}")
for k, v in details.items():
print(f" {k}: {v}")
# ── Main ────────────────────────────────────────────────────────────
def main() -> None:
"""Execute full Raptor swap flow."""
parser = argparse.ArgumentParser(description="Raptor swap flow")
parser.add_argument("--demo", action="store_true", help="Simulate with mock data")
parser.add_argument("--input", default=SOL_MINT, help="Input mint")
parser.add_argument("--output", default=USDC_MINT, help="Output mint")
parser.add_argument("--amount", type=int, default=100_000_000, help="Amount (lamports)")
parser.add_argument("--slippage", type=int, default=50, help="Slippage (bps)")
parser.add_argument("--priority-fee", default="auto", help="Priority fee level")
args = parser.parse_args()
if args.demo:
print("=" * 50)
print(" RAPTOR SWAP FLOW (Demo / Simulation)")
print("=" * 50)
print(f" Raptor URL: {RAPTOR_URL} (not connected)")
print(f" Swap: 0.1 SOL → USDC")
# Step 1
quote = DEMO_QUOTE
sol_in = quote["amountIn"] / 1e9
usdc_out = quote["amountOut"] / 1e6
display_step(1, "GET /quote", {
"Input": f"{sol_in} SOL",
"Output": f"{usdc_out:.6f} USDC",
"Price": f"${usdc_out / sol_in:.4f}/SOL",
"Impact": f"{quote['priceImpact']}%",
"Route": f"{len(quote['routePlan'])} hop(s) via {quote['routePlan'][0]['dex']}",
"Slot": f"{quote['contextSlot']:,}",
})
# Step 2
display_step(2, "POST /swap (build transaction)", {
"Transaction": f"{DEMO_SWAP_TX[:40]}...",
"Priority fee": "auto",
"Wrap/Unwrap SOL": "true",
"Version": "v0",
})
# Step 3
display_step(3, "Sign locally", {
"Signer": "DemoWa11et... (private key never sent to Raptor)",
"Signed tx": f"{DEMO_SWAP_TX[:40]}... (simulated)",
})
# Step 4
display_step(4, "POST /send-transaction (Yellowstone Jet TPU)", {
"Signature": DEMO_SIGNATURE[:40] + "...",
"Submission": "Auto-retry for ~30 seconds",
})
# Step 5
display_step(5, "GET /transaction/{sig} (confirm)", {
"Status": "confirmed",
"Latency": "~450ms",
"Slot": "298,765,433",
})
print(f"\n{'=' * 50}")
print(" SWAP COMPLETE (simulated)")
print(f"{'=' * 50}")
print(f" Swapped: {sol_in} SOL → {usdc_out:.6f} USDC")
print(f" Signature: {DEMO_SIGNATURE[:40]}...")
print()
print(" ⚠️ This was a simulation. No real transaction was sent.")
print(" ⚠️ For live swaps, run without --demo and set PRIVATE_KEY.")
print()
return
# Live mode
try:
import httpx # noqa: F811
except ImportError:
print("httpx is required. Install with: uv pip install httpx")
sys.exit(1)
private_key = os.getenv("PRIVATE_KEY", "")
if not private_key:
print("⚠️ PRIVATE_KEY not set. Cannot sign transactions.")
print("Set PRIVATE_KEY environment variable with your base58 private key.")
print("For quote-only mode, use raptor_quote.py instead.")
sys.exit(1)
# Derive public key
try:
from solders.keypair import Keypair
keypair = Keypair.from_base58_string(private_key)
user_pubkey = str(keypair.pubkey())
except ImportError:
print("solders is required for live mode. Install with: uv pip install solders")
sys.exit(1)
print(f"Raptor URL: {RAPTOR_URL}")
print(f"Wallet: {user_pubkey}")
print(f"Swap: {args.amount} lamports of {args.input[:8]}... → {args.output[:8]}...")
# Confirmation gate
print("\n⚠️ THIS WILL EXECUTE A REAL SWAP WITH REAL FUNDS ⚠️")
confirm = input("Type 'yes' to proceed: ").strip().lower()
if confirm != "yes":
print("Cancelled.")
sys.exit(0)
quote = step_1_get_quote(args.input, args.output, args.amount, args.slippage)
print(f"Quote: {quote['amountOut']} output, {quote['priceImpact']}% impact")
tx_b64 = step_2_build_swap(quote, user_pubkey, args.priority_fee)
print(f"Transaction built: {len(tx_b64)} chars")
signed_b64 = step_3_sign_transaction(tx_b64, private_key)
print("Transaction signed locally")
signature = step_4_send_transaction(signed_b64)
print(f"Submitted: {signature}")
status = step_5_confirm_transaction(signature)
print(f"Result: {status.get('status')} (latency: {status.get('latency_ms', '?')}ms)")
print()
if __name__ == "__main__":
main()
Related skills
FAQ
How is Raptor different from Jupiter?
Raptor runs on your own infrastructure with no rate limits, no API key, and no dependency on external API availability, and is free during public beta.
Does Raptor hold your private key?
No; you sign the unsigned transaction locally and your private key never leaves your machine.