swap — CLI manual

Everything in swap --help, with examples · Operator: 9summits

swap is a terminal CLI that asks every major DEX aggregator (KyberSwap, Velora, 0x/Matcha, 1inch, Curve, Uniswap, OpenOcean, plus intent venues like CoW, UniswapX, Velora Delta and 1inch Fusion) for a swap quote on EVM chains, ranks the answers by token-out received, and — optionally — builds the executable calldata, checks your allowance, simulates the trade against your pranked balance, and hands the transaction to your wallet in the browser. Single Bun-compiled binary, no daemon, no telemetry.

$ swap 1 WBTC ETH                       # best quote across every venue
$ swap 1000 USDC USDT -v all           # side-by-side comparison block
$ swap 100 USDC USDT --from 0xYou --simulate   # dry-run, real tokenOut
$ swap 0.1 WETH USDC --from 0xYou --browser    # sign & send in your wallet
$ swap                                  # no args: open the local dApp

01Install & setup

One command downloads a prebuilt binary for macOS (arm64, x64) or Linux (arm64, x64) into ~/.local/bin. Re-run it to upgrade, or use swap update from then on.

$ curl -fsSL https://swap.9summits.io/install.sh | bash
From source

Needs Bun. Clone 9summits/swap-cli, bun install, then ./builddist/swap.

Self-update

swap update checks the published checksum and replaces the binary in place only when a newer build exists.

Installer env: SWAP_INSTALL_DIR (default ~/.local/bin), SWAP_INSTALL_BASE (asset base), SWAP_NO_PROGRESS=1.

First run

Quotes work out of the box. Building a transaction, simulating, or swapping max needs an RPC. The first time one is required, the CLI prompts for an Alchemy key or an RPC URL and saves it under ~/.swap/config. You can trigger that prompt any time:

$ swap --init      # prompt for ALCHEMY_API_KEY or RPC URL, write ~/.swap/config
$ swap update      # pull the latest public prebuilt (no-op when current)
$ swap --help

02Usage & flags

$ swap [options] <amount> <tokenIn> [tokenOut]
Flag Effect
-v, --venue <list> Venue(s) to query. One name, a comma-separated list (kyber,matcha,1inch), or all (default). --all is an alias for -v all.
-c, --chain <alias> eth (default), base, arb, op, avax, bsc, hype, unichain, robinhood, monad, plasma.
--slippage <pct> Tolerance in percent — 0.5 = 50 bps. Default 0.1. The same value drives the quote and the build.
--from <addr|alias> Sender and recipient of the swap. Required for -d, --simulate, --browser and max. Also read from $SENDER_ADDRESS. Accepts a wallet alias (see actions).
-d, --data Also build the tx: target, calldata, value, gas params, allowance check and an approve tx when needed.
--simulate / --simu Run approve + swap through eth_simulateV1 with a pranked tokenIn balance; reports the tokenOut actually received and any revert reason. Sync venues only.
--browser Open a local RainbowKit page to connect a wallet and sign / send. Covers sync txs, intent orders and Uniswap Permit2 flows. Exclusive with --json / -s.
--allow-async Include intent venues (cow, delta, uniswapx, fusion, ophis). Output is an EIP-712 order to sign and POST, not a tx.
--exact-out amount is the tokenOut to receive; the CLI minimises tokenIn paid. Not allowed with send / wrap / special actions.
-a, --action <name> swap (default), send, addwallet, plus protocol helpers listed in 07.
--to <addr|alias> Recipient for -a send.
--rpc <url> Override the RPC for this run — beats every env var. Handy for a local fork.
--json Structured machine-readable output, one object.
-s, --simple Print only the number: amountOut, or amountIn under --exact-out.
--nofee Zero the partner fee (REFERRAL_FEE_BPS) for this run on every venue.
--debug With --simulate: also list ERC20 transfers landing at REFERRAL_ADDRESS.

03Quoting

The default action races every venue in parallel and prints the winner: route tree, rate, gas, chain, venue, router and token rows, then a bold summary line. With -v all a venues comparison block streams below, sorted by amountOut with on the current leader. When CoinGecko prices both legs, ranking is net of gas.

# best quote, all venues (default)
$ swap 1 WBTC ETH

# pin one venue, or race a subset
$ swap 1 WBTC ETH -v kyber
$ swap 1 WBTC ETH -v kyber,matcha,1inch

# another chain
$ swap 1000 USDT USDC --chain bsc
$ swap 0.5 ETH USDC -c base

# include intent venues (CoW, UniswapX, Velora Delta, 1inch Fusion)
$ swap 2 WETH stETH --all --allow-async

# wider tolerance
$ swap 5000 USDC PEPE --slippage 1

# address instead of symbol
$ swap 1 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 USDC
Keys

Venues that need an API key you haven't set are silently skipped under -v all. Selecting one explicitly (-v matcha) errors with the signup URL. See 09.

04Build & simulate

-d re-quotes with your real sender and prints an approve tx block (only when allowance is insufficient) and a swap tx block with the target, calldata, value and gas parameters, ready to broadcast. The approval target is the venue's spender, which can differ from the tx target.

# calldata + allowance check
$ swap 100 USDC USDT --from 0xYou -d

# swap the whole balance
$ swap max USDC WETH --from 0xYou -d

# dry-run: pranked balance, approve + swap, actual tokenOut received
$ swap 100 USDC USDT --from 0xYou --simulate
$ swap 2000 WETH stETH -v all --from 0xYou --simu -d

# against a local fork
$ swap 100 USDC USDT --from 0xYou --simulate --rpc http://127.0.0.1:8545

--simulate appends a simulation block: gas used, revert reason if any, and the tokenOut that actually landed. Calldata stays hidden unless you also pass -d. Both need an RPC (09).

05Browser signing

--browser builds the swap as for -d, starts a tiny local server on 127.0.0.1:5151 and opens a RainbowKit page in your default browser. The page shows the quote, lets you connect MetaMask, Rabby, WalletConnect, …, offers a simulate button, and hard-blocks signing if the connected wallet is not --from. The tx hash or order id is reported back to the terminal.

$ swap 0.1 WETH USDC --from 0xYou --browser
$ swap 1 ETH WETH --from 0xYou --browser                # wrap
$ swap 100 USDC -a send --to 0xRecip --from 0xYou --browser
$ swap 2 WETH stETH --allow-async --from 0xYou --browser   # sign an intent order

Run swap with no arguments to open the full interactive dApp locally instead — the same UI as swap.9summits.io, served from your machine with your own keys.

06Exact-out (buy)

With --exact-out the amount is the tokenOut you want and venues are ranked by the least tokenIn paid. Venues with a native buy path (velora, matcha, uniswap, cow, ophis) are quoted directly; sell-only venues are refined as exact-in at the best native pay and must still deliver at least your target. A sell-only venue selected alone (-v kyber --exact-out) is rejected.

# receive exactly 1 WBTC, pay as little USDC as possible
$ swap 1 USDC WBTC --exact-out

# build it
$ swap 1 USDC WBTC --exact-out --from 0xYou -d

# just the USDC to pay
$ swap 1 USDC WBTC --exact-out -s

07Wrap, send & other actions

Wrap / unwrap

When the pair is the chain's native ↔ wrapped token (ETH ↔ WETH, BNB ↔ WBNB, AVAX ↔ WAVAX, HYPE ↔ WHYPE) the venue loop is skipped: the rate is 1:1 by construction, so the CLI emits a direct deposit() / withdraw() on WETH9. No approval needed either way.

$ swap 1 ETH WETH -d --from 0xYou              # wrap
$ swap 1 WETH ETH -d --from 0xYou              # unwrap
$ swap 1 BNB WBNB --chain bsc -d --from 0xYou

Send (-a send)

A plain token transfer with the same calldata builder and --browser flow, no DEX involved. ERC20 emits transfer(to, amount); native emits a value-only tx. tokenOut is ignored.

$ swap 100 USDC -a send --to 0xRecip --from 0xYou -d
$ swap 0.5 ETH  -a send --to 0xRecip --from 0xYou --browser
$ swap max USDC -a send --to treasury --from main   # aliases, see below

Wallet aliases (-a addwallet)

Register a readable name for an address once; then pass the alias to --from or --to. Stored in ~/.swap/wallets.json.

$ swap -a addwallet main 0xYourAddress
$ swap -a addwallet treasury 0xTreasuryAddress
$ swap 1 WBTC ETH --from main -d

Protocol helpers

Action Chain What it builds
-a unwrapwrseth Base Kelp wrsETH → rsETH
-a withdrawsparkweth Ethereum Spark spWETH → WETH
-a unstakesavax Avalanche BENQI sAVAX → AVAX requestUnlock
-a claimsavax Avalanche Redeem matured sAVAX unlock requests
$ swap 10 sAVAX -a unstakesavax --chain avax --from 0xYou --browser
$ swap 0 sAVAX  -a claimsavax   --chain avax --from 0xYou --browser

08Venues & chains

Venue Kind Exact-out Key
kyber sync refine optional
velora sync native
matcha sync native ZEROEX_API_KEY
1inch sync refine ONEINCH_API_KEY
curve sync refine
uniswap sync native UNISWAP_API_KEY
openocean sync refine OPENOCEAN_API_KEY
cow intent native
ophis intent native OPHIS_REFERRAL_CODE
delta intent refine
uniswapx intent refine UNISWAP_API_KEY
fusion intent refine ONEINCH_API_KEY
odos, odosv2 disabled API discontinued 2026-07-30

Sync venues return a broadcastable transaction. Intent venues return an EIP-712 order that you sign and POST off-chain; a solver settles it on-chain within the order's validity window. They require --allow-async because the output shape differs.

Availability by chain

Which venues answer on which chain. Under -v all the CLI only races the venues that serve the selected chain; the others are skipped silently. Async venues still need --allow-async, curve needs an RPC.

Venue ethbasearbopunichainbscavaxhyperobinhoodmonadplasma
kyber sync
velora sync ·····
matcha sync ·
1inch sync ··
curve sync ······
uniswap sync ··
openocean sync ·····
cow intent ········
ophis intent ··
delta intent ····
uniswapx intent ·······
fusion intent ··
venues per chain 121212989101753

served   · not served. Snapshot of the adapters' chain tables; the live set for a deployment is GET /api/mode.

Chains

Alias Chain Native
ethEthereum (default)ETH
baseBaseETH
arbArbitrum OneETH
opOptimismETH
unichainUnichainETH
bscBNB ChainBNB
avaxAvalancheAVAX
hypeHyperEVMHYPE
robinhoodRobinhood ChainETH
monadMonadMON
plasmaPlasmaXPL

09RPC, keys & config

RPC

Needed for -d, --simulate, --browser and max. Resolution order, first match wins:

  1. --rpc <url> on the command line
  2. RPC_URL_<chainId> — e.g. RPC_URL_1
  3. <ALIAS>_RPC_URL — e.g. ETH_RPC_URL, BASE_RPC_URL
  4. ALCHEMY_API_KEY — one key covers every supported chain (free tier is enough)
No public RPC fallback (CLI)

Missing RPC config is a hard failure that names the exact variable to set. Public RPCs rate-limit and return inconsistent allowance reads, which would silently break the CLI build path. The interactive dApp server last-resorts to the shared PublicNode table when Alchemy and per-chain overrides are unset.

Where config lives

Shell environment first, then a .env in the current directory, then ~/.swap/config (written by --init / the first-run prompt), then values embedded in the binary at build time. Prebuilt binaries ship venue keys and referral settings; your RPC key is always yours to configure.

Venue API keys

Variable Unlocks Free signup
ZEROEX_API_KEY matcha dashboard.0x.org
ONEINCH_API_KEY 1inch, fusion portal.1inch.dev
UNISWAP_API_KEY uniswap, uniswapx hub.uniswap.org
KYBER_API_KEY kyber API gateway, higher rate limits (optional). KYBER_SOURCE / KYBER_REFERRAL add on-chain attribution business@kyber.network
OPENOCEAN_API_KEY openocean docs.openocean.finance
OPHIS_REFERRAL_CODE ophis (skipped without it) CIP-75 rebate code
SENDER_ADDRESS default for --from
WALLETCONNECT_PROJECT_ID WalletConnect in --browser (injected wallets work without it)

Partner fees

Set REFERRAL_ADDRESS and optionally REFERRAL_FEE_BPS (1 bp = 0.01 %) to attribute a fee on every venue that supports it; the fee is already reflected in the quoted amounts so venues stay comparable. --nofee zeroes it for one run.

10Output & scripting

default

Route tree, rate / gas / venue / router rows, bold summary, and the live venue comparison under -v all.

--json

One object: best (venue name), quotes (keyed by venue), approval, tx, order, simulation. Errors are {"error": "…"} with exit 1.

-s / --simple

Just the human-units number. amountOut by default, amountIn under --exact-out.

# capture the rate in a script
$ RATE=$(swap 1 WBTC ETH -s)

# the winning venue, then its full quote
$ swap 1 WBTC ETH --all --json | jq -r '.best'
$ swap 1 WBTC ETH --all --json | jq '.quotes[.best]'

# calldata only, straight to another tool
$ swap 100 USDC USDT --from 0xYou -d --json | jq -r '.tx.data'

# every venue's amountOut, best first
$ swap 1000 USDC USDT --json | jq -r '.quotes | to_entries[] | select(.value.amountOut) | "\(.key)\t\(.value.amountOut.human)"' | sort -k2 -gr

Human-readable output goes to stdout; warnings and progress go to stderr, so piping --json or -s stays clean.

11Unattended use & agents

The CLI is safe to drive from scripts, CI and AI agents: it never waits on stdin when it is not a terminal, everything is configurable through the environment, and --json gives a stable shape.

Machine-readable copies

This manual as Markdown: /docs.md (also served at /docs with Accept: text/markdown). Installable agent skill: /skills/swap-cli/SKILL.md. Site index for LLMs: /llms.txt and /llms-full.txt.

> back to swap · GitHub · Markdown · OpenAPI · Terms · contact@9summits.io