Skip to content

Repository files navigation

0x CLI

Trade tokens across Solana and EVM chains from your terminal. Built for both human traders and AI agents.

This CLI is in beta and under active development. While we don't anticipate major breaking changes, commands, flags, and output formats may still change between releases. Pin a version and review release notes before relying on current behavior in production workflows.

Quick Start

# Install (macOS / Linux) — see Installation below for Windows / from source
curl -fsSL https://raw.githubusercontent.com/0xProject/0x-cli/main/scripts/install.sh | sh
# Configure
0x config init
# Check a price
0x price --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
--buy 0x4200000000000000000000000000000000000006 --amount 1000000
# Execute a swap
0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
--buy 0x4200000000000000000000000000000000000006 --amount 1000000

Features

  • 4 APIs: EVM Swap (Allowance Holder), Gasless Swap, Solana Swap, Cross-Chain
  • 22 chains: Ethereum, Base, Arbitrum, Optimism, Polygon, BSC, Avalanche, Linea, Scroll, Blast, Mantle, Berachain, Sonic, Unichain, World Chain, Abstract, Ink, Monad, HyperEVM, Robinhood Chain, Solana, Tron
  • Agent-first: Auto-detect non-TTY for JSON output, structured error codes, stable exit codes, inline RESPONSE: schemas in every --help
  • Pay-per-request (no API key): --pay x402-evm or --pay mpp settles ~$0.01 USDC per request via the 0x agent gateway — for autonomous agents with a funded wallet
  • Safe by default: OS keyring for wallet secrets, transaction simulation before every execution, --dry-run mode, exact token approvals
  • Rich UX: Colored tables, progress spinners, interactive confirmation, shell completions

Installation

Prebuilt binary (recommended)

One command installs the latest release for macOS or Linux (x86_64 and arm64). It downloads the binary from GitHub Releases, verifies its SHA-256 checksum, and drops it in ~/.local/bin:

curl -fsSL https://raw.githubusercontent.com/0xProject/0x-cli/main/scripts/install.sh | sh

Pin a specific version or change the install directory:

# Install a specific version
curl -fsSL https://raw.githubusercontent.com/0xProject/0x-cli/main/scripts/install.sh | ZEROEX_VERSION=v0.1.0 sh
# Install somewhere on your PATH
curl -fsSL https://raw.githubusercontent.com/0xProject/0x-cli/main/scripts/install.sh | ZEROEX_BIN_DIR=/usr/local/bin sh

On Windows, download the .zip for x86_64-pc-windows-msvc from the latest release and put 0x.exe on your PATH.

From source

# Requires Rust 1.75+
git clone https://github.com/0xProject/0x-cli &&cd 0x-cli
cargo install --path .# Verify
0x --version

Configuration

Interactive Setup

0x config init

Guides you through setting your API key, default chain, and wallet.

Manual Setup

# Set your 0x API key (get one at https://dashboard.0x.org)
0x config set api_key <your-key># Set default chain
0x config set defaults.chain base
# Set EVM wallet (private key) — goes to OS keyring by default
0x config set wallet.evm 0xac0974bec...
# Same, but force plaintext storage in the config file
0x config set wallet.evm 0xac0974bec... --plaintext
# Solana wallet: file paths stay in the config file (path isn't secret)
0x config set wallet.solana /path/to/keypair.json
# Solana wallet: base58 secrets go to the keyring
0x config set wallet.solana 4Nd1mBQt...
# Set custom RPC endpoints
0x config set rpc.base https://base.llamarpc.com
0x config set rpc.solana https://api.mainnet-beta.solana.com
# Inspect a single key (secrets redacted)
0x config get wallet.evm
# Remove a key (clears keyring + config file for wallet keys)
0x config unset wallet.evm

Wallet Storage

By default, wallet.evm and wallet.solana (when given key material rather than a file path) are stored in the OS keyring — macOS Keychain, Linux libsecret/secret-tool, or Windows Credential Locker. They are never written to disk in plaintext.

ScenarioStorage
0x config set wallet.evm <key>OS keyring
0x config set wallet.evm <key> --plaintext~/.0x-config/config.toml
0x config set wallet.solana /path/to/file.json~/.0x-config/config.toml (it's a path)
0x config set wallet.solana <base58>OS keyring
ZEROEX_EVM_PRIVATE_KEY / ZEROEX_SOLANA_KEYPAIR env varRead directly, never persisted
0x config set wallet.tron <hex-key>OS keyring
0x config set wallet.tron <hex-key> --plaintext~/.0x-config/config.toml
ZEROEX_TRON_PRIVATE_KEY env varRead directly, never persisted

0x config show reports keyring-stored wallets as <stored in keyring>. If the OS keyring is unavailable (e.g. headless Linux with no DBus), use --plaintext or the env vars.

Environment Variables

Environment variables always take precedence over config file values.

VariableDescription
ZEROEX_API_KEY0x API key
ZEROEX_EVM_PRIVATE_KEYEVM private key (hex)
ZEROEX_SOLANA_KEYPAIRSolana keypair file path or base58
ZEROEX_TRON_PRIVATE_KEYTron private key (hex)
ZEROEX_DEFAULT_CHAINDefault chain name or ID
ZEROEX_RPC_URLOverride RPC URL for any chain
ZEROEX_TELEMETRYSet falsy (0/false/off) to disable usage telemetry
DO_NOT_TRACKSet to 1 to disable usage telemetry
NO_COLORDisable colored output

Config File

Stored at ~/.0x-config/config.toml with 0600 permissions (Unix). Wallet secrets live in the OS keyring by default — the [wallet] section here only contains keys you opted into plaintext for, or Solana file paths.

[api]
api_key = "your-api-key"
[defaults]
chain = "base"slippage_bps = 100approval_type = "exact"
[rpc]
base = "https://base.llamarpc.com"ethereum = "https://eth.llamarpc.com"solana = "https://api.mainnet-beta.solana.com"
[wallet]
# evm = "0xac0974bec..." # only present when --plaintext was usedsolana = "/path/to/keypair.json"# file paths stay here (not secret)

Usage

Price Check

# EVM price (read-only, no wallet needed)
0x price --chain base \
--sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
--buy 0x4200000000000000000000000000000000000006 \
--amount 1000000
# Gasless price
0x price --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --amount 1000000 --gasless
# JSON output for scripting
0x price --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --amount 1000000 -o json
# Exact-out: how much of the sell token to receive exactly this many base units# of the buy token (EVM same-chain only)
0x price --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --buy-amount 1000000000000000

EVM Swap

# Interactive swap with confirmation prompt
0x swap --chain base \
--sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
--buy 0x4200000000000000000000000000000000000006 \
--amount 1000000
# Non-interactive (for agents/scripts)
0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --amount 1000000 --yes -o json
# Dry run (simulate without executing)
0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --amount 1000000 --dry-run
# Custom slippage (200 bps = 2%)
0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --amount 1000000 --slippage 200
# Unlimited token approval (instead of exact amount)
0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --amount 1000000 --approval unlimited
# Exact-out: spend whatever it takes to receive exactly this many base units of# the buy token (use --buy-amount instead of --amount; EVM same-chain only)
0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --buy-amount 500000000000000000

Exact-in vs exact-out. Pass exactly one of --amount (exact-in: sell this much) or --buy-amount (exact-out: receive this much, spending whatever it takes). Exact-out is supported for EVM same-chain swaps via Allowance Holder — not Solana, gasless, or cross-chain. In exact-out mode the buy amount is fixed and the response reports an estimated sell plus a max_sell_amount (the worst-case spend after slippage, which the token approval covers).

Gasless Swap

No gas fees required. The 0x protocol handles gas on your behalf.

0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0x4200000000000000000000000000000000000006 --amount 1000000 --gasless

Solana Swap

0x swap --chain solana \
--sell So11111111111111111111111111111111111111112 \
--buy EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v \
--amount 1000000000

Cross-Chain Swap

Note: Tron is supported for bridging only — it is not available in swap, price, or gasless. Use --from tron or --to tron with cross-chain.

# Interactive (shows quote table, lets you pick)
0x cross-chain \
--from base --to arbitrum \
--sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
--buy 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 \
--amount 1000000
# Auto-select best price quote
0x cross-chain --from base --to arbitrum \
--sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 --amount 1000000 \
--select-quote best-price --yes
# Sort by fastest bridge
0x cross-chain --from base --to arbitrum \
--sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 --amount 1000000 --sort speed
# Stream quotes as they're discovered (SSE)
0x cross-chain --from base --to arbitrum \
--sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 --buy 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 --amount 1000000 --stream

--stream fetches quotes progressively via Server-Sent Events instead of waiting for all bridges to respond. Progress appears on stderr; the final output is identical to the non-streaming mode, with quotes re-sorted best price first before selection. Cannot be combined with --sort; --max-quotes defaults to 5 (1-10) instead of 3.

Solana-origin swaps automatically include routes that need an extra one-shot transaction signer (e.g. Circle CCTP): the CLI generates a fresh keypair per quote request, sends its pubkey with the quote, and co-signs at submission. Nothing to configure — the keypair lives in memory only.

Status Tracking

# Check gasless trade status
0x status 0xabc123... --type gasless --chain base
# Poll cross-chain bridge status until complete
0x status 0xdef456... --type cross-chain --chain base --poll
# Custom poll interval (10 seconds)
0x status 0xdef456... --type cross-chain --chain base --poll --poll-interval 10

Pay per request (x402 / MPP)

Instead of a 0x-api-key, price and swap can pay ~$0.01 USDC per request through the 0x agent gateway — useful for an autonomous agent with a funded wallet and no key. Add --pay with one of two payment rails:

--payRailWallet needs
x402-evmx402 over Base — signs an EIP-3009 USDC authorization (off-chain, no gas)USDC on Base
mppMPP over Tempo (chainId 4217) — broadcasts a USDC.e transferUSDC.e and native gas on Tempo
# Pay for a price check with x402 (EVM wallet signs; no API key needed)
0x price --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
--buy 0x4200000000000000000000000000000000000006 --amount 1000000 \
--pay x402-evm --max-payment 0.05
# Pay for a swap quote via MPP/Tempo, then execute on-chain as usual
0x swap --chain base --sell 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 \
--buy 0x4200000000000000000000000000000000000006 --amount 1000000 \
--pay mpp --yes
  • EVM AllowanceHolder only. Rejected (free, INPUT_INVALID) with --gasless, Solana/Tron, or --buy-amount (exact-out).
  • --max-payment <USD> (default 0.05) caps the spend. If the gateway asks for more, the CLI refuses before signing/broadcastingPAYMENT_EXCEEDS_LIMIT (exit 41), nothing spent.
  • The payment is real, non-refundable money charged per request — including when a later on-chain swap reverts. Don't poll price --pay in a loop. The settlement (tx hash, payer, amount) is reported under metadata.payment in JSON output.
  • swap --pay pays only for the quote; the on-chain swap still uses your wallet and RPC. See exit codes 40–44 and the PAYMENT_* rows under Error Codes.
  • For --pay mpp, point the Tempo RPC wherever you like with --tempo-rpc <url> or 0x config set rpc.tempo <url> (defaults to https://rpc.tempo.xyz).

AI Agent Integration

The CLI is designed as a first-class tool for AI agents and scripts.

Auto-Detection

When stdout is not a TTY (piped or redirected), output automatically switches to json-envelope format. Agents calling from a tool harness should still pass -o json-envelope explicitly for stability — don't rely on TTY detection inside an agent loop.

# These produce identical JSON output:
0x chains -o json-envelope
0x chains | cat # auto-detects non-TTY

Inline Schemas

Every command's --help ends with a RESPONSE: block documenting the data payload it returns. Run 0x swap --help, 0x cross-chain --help, etc. to see field names, types, and which fields are optional. Agents can read this without invoking the command.

Bundled Agent Skill

The CLI bundles an agent skill (compiled into the binary, always in sync with the running version): one SKILL.md entry point plus deep-dive references (gasless, cross-chain, solana, config, tokens, errors) that agents read on demand.

# Install SKILL.md + references/ into ./.claude/skills/0x-trade/
0x skill install
# Install into a custom skills directory (e.g. user-level)
0x skill install --dir ~/.claude/skills
# Print the main skill to stdout
0x skill print
# Print one reference topic
0x skill print --topic errors

The skill explains exit codes, output envelope shape, dry-run patterns, and per-chain token references. -o/--output is ignored for skill print — output is always raw markdown. The canonical source lives in skills/0x-trade/ in this repo.

JSON Envelope

Every command produces a consistent envelope:

{
"version": "1",
"command": "price",
"timestamp": "2026-03-22T14:30:00.000Z",
"duration_ms": 423,
"exit_code": 0,
"status": "success",
"data": { ... },
"warnings": [],
"metadata": {
"chain_id": 8453,
"chain_name": "Base",
"api_version": "v2"
}
}

On error:

{
"version": "1",
"command": "swap",
"status": "error",
"exit_code": 5,
"error": {
"code": "API_KEY_MISSING",
"message": "No API key configured",
"category": "config",
"retryable": false,
"suggestion": "Run '0x config set api_key <your-key>' or set ZEROEX_API_KEY env var"
}
}

Exit Codes

CodeMeaningAgent Action
0SuccessProceed
1General errorInspect error.code
2Input error (malformed args, unsupported chain)Fix the command
3Config errorRun 0x config init
4Network errorRetry with backoff
5Auth errorUpdate API key
6Validation failed (no liquidity, insufficient balance, token not supported)Fix parameters or fund wallet
10Simulation failedInspect the error — may be transient (RPC) or real (revert); one retry ok, never loop
11Transaction revertedDo NOT retry as-is
12Transaction pendingPoll with 0x status
20User cancelledStop; don't re-run
25Preview emitted, confirmation requiredRe-run with --yes or show the quote
30Dry-run completedInformational

Error Codes

Each error includes a stable code string, category, and retryable boolean:

CodeCategoryRetryable
CONFIG_NOT_FOUNDconfigno
API_KEY_MISSINGconfigno
WALLET_NOT_FOUNDconfigno
KEYRING_UNAVAILABLEconfigno
CHAIN_NOT_SUPPORTEDinputno
INSUFFICIENT_BALANCEvalidationno
NO_LIQUIDITYvalidationno
API_RATE_LIMITEDnetworkyes
NETWORK_TIMEOUTnetworkyes
SIMULATION_FAILEDexecutionno
TRANSACTION_REVERTEDexecutionno
BRIDGE_FAILEDbridgeno
USER_CANCELLEDinputno

Non-Interactive Flags

Every interactive prompt has a flag equivalent:

PromptFlag
Confirm trade--yes / -y
Select cross-chain quote--select-quote <n|best-price|fastest>
Approval strategy--approval exact|unlimited
Suppress progress--quiet / -q

Stdout/Stderr Contract

  • stdout: Only machine-parseable output (tables in human mode, JSON in json modes)
  • stderr: Progress spinners, status messages, debug logs — suppressed with --quiet

Global Flags

FlagShortDescriptionDefault
--output-ohuman, json, json-envelopeAuto-detect
--yes-ySkip confirmation promptsfalse
--quiet-qSuppress stderr outputfalse
--verbose-vDebug output on stderrfalse
--dry-runSimulate without executingfalse
--api-keyOverride API keyFrom config
--rpc-urlOverride RPC URLFrom config
--wallet-wOverride walletFrom config
--timeoutHTTP timeout (seconds)30
--no-colorDisable colorsAuto-detect

Supported Chains

IDNameNetworkNative Token
1ethereumEthereumETH
10optimismOptimismETH
56bscBNB ChainBNB
130unichainUnichainETH
137polygonPolygonPOL
143monadMonadMON
146sonicSonicS
480worldchainWorld ChainETH
999hyperevmHyperEVMHYPE
2741abstractAbstractETH
4663robinhoodRobinhood ChainETH
5000mantleMantleMNT
8453baseBaseETH
42161arbitrumArbitrumETH
43114avalancheAvalancheAVAX
57073inkInkETH
59144lineaLineaETH
80094berachainBerachainBERA
81457blastBlastETH
534352scrollScrollETH
solanasolanaSolanaSOL
trontronTronTRX

Security

  • OS keyring by default: Wallet secrets (wallet.evm, wallet.solana key material) are stored in the OS keyring — macOS Keychain, Linux libsecret, Windows Credential Locker. Use --plaintext to opt out only when the keyring isn't available.
  • Config file: Created with 0600 permissions (owner read/write only)
  • Config directory: Created with 0700 permissions
  • Redaction: 0x config show and 0x config get never reveal secret material. Wallets stored in the keyring show as <stored in keyring>; plaintext wallets show as ***redacted***; Solana file paths show verbatim because the path itself isn't sensitive.
  • Transaction simulation: EVM and Solana transactions are simulated via eth_call or simulate_transaction before submission. Tron cross-chain transactions are not pre-simulated.
  • Approval strategy: Default is exact (only approve the needed amount). Use --approval unlimited for max approval.
  • Environment variables: Sensitive values like private keys can be set via env vars (ZEROEX_EVM_PRIVATE_KEY, ZEROEX_SOLANA_KEYPAIR) to avoid persisting them at all — read-once, never written to disk or keyring.

Telemetry

The CLI sends anonymous, opt-out usage statistics (via Amplitude) to help us prioritize chains, surface common errors, and track version adoption. It's designed to be minimal and never in your way.

What's sent, one event per command:

FieldExample
commandswap, cross-chain, price
exit_code0, 6
error_codeINSUFFICIENT_BALANCE (stable code, never the message)
duration_ms423
chainbase (chain name only)
gasless / dry_runtrue / false
output_formathuman / json / json-envelope
ciwhether CI is set
app_version, os_name, platform0.1.0, macos, aarch64
install_ida random UUID generated once — not a device or hardware identifier

Never sent: token addresses, amounts, transaction/trade hashes, wallet addresses, API keys, RPC URLs, error messages, or your IP.

Opt out any of three ways:

0x config set telemetry.enabled false# persistentexport ZEROEX_TELEMETRY=0 # per-shellexport DO_NOT_TRACK=1 # cross-tool standard

How it works: on the first tracked run you'll see a one-time notice. Events spool to ~/.0x-config/telemetry-queue.jsonl and are flushed in the background during the next command plus a ≤300ms best-effort flush at exit — so telemetry never adds latency to your command. Builds without a compiled-in Amplitude key (all local/dev builds) send nothing at all.

Development

# Build
cargo build
# Run tests
cargo test# Lint
cargo clippy
# Run directly
cargo run -- --help
cargo run -- chains -o human

Project Structure

src/
main.rs # Entry point, GlobalOpts, command dispatch
cli.rs # clap derive definitions
error.rs # Error types, codes, exit codes
confirm.rs # Trade confirmation prompt
config/ # ~/.0x-config management
api/ # 0x API clients (evm_swap, gasless, solana, cross_chain)
wallet/ # Key loading (EVM PrivateKeySigner, Solana Keypair)
chain/ # Chain operations (EVM provider + ERC-20, Solana tx building)
output/ # Output formatting (human tables, JSON envelope)
commands/ # Command implementations
tests/
cli_output.rs # Integration tests for CLI output

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages