A cross-platform TypeScript CLI wallet for Ethereum and Solana, designed for AI agent integration.
Read this section before using agent-wallet-cli.
- Experimental software. This tool is provided as-is with no warranty. Use at your own risk.
- Do not use on mainnet with significant funds without reading and understanding the source code.
- Mnemonic is displayed once on
init. Secure your terminal — anyone who sees it controls your funds. - Session tokens grant access to funds. Treat them like passwords. Never log or share them.
- JavaScript cannot guarantee secrets are purged from memory. Buffers are zeroed on a best-effort basis, but the V8 garbage collector may retain copies.
argon2requires native bindings (C compiler toolchain). It will not work in all environments (e.g., some Docker images, serverless runtimes).- Public RPCs may be rate-limited or unreliable. Configure your own RPC endpoints for production use.
- No security audit has been performed on this code.
- Multi-chain: Ethereum (+ Polygon, Arbitrum, Base) and Solana
- BIP-39 HD wallet: 12 or 24-word mnemonic, multiple account indices
- ERC-20 & SPL tokens: balance, transfer, approve, transferFrom, allowance
- Gasless relay: Automatic fallback for ERC-20 transfers when wallet has no ETH for gas (EIP-3009 authorization)
- Strong encryption: Argon2id key derivation + AES-256-GCM
- Session tokens: Time-limited unlock (default 1h, max 24h) so agents don't need your password
- Message signing: Plain text, EIP-712 typed data, raw bytes
- Transaction history: Recent transactions with explorer links
- Approval discovery: Scan recent ERC-20 Approval events
- x402 payments: Automatic HTTP 402 stablecoin payments via EIP-3009
TransferWithAuthorization(no gas required) - JSON-first output: Machine-readable by default, human-readable
--format textoption - Token aliases: Use
usdcinstead of0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
# Create a new wallet
npx agent-wallet-cli init --password "my-secure-password"
# Unlock (creates a session token valid for 1 hour)
npx agent-wallet-cli unlock --password "my-secure-password"
# Check balance
npx agent-wallet-cli balance --token wlt_... --chain ethereum --network mainnet
# Send ETH
npx agent-wallet-cli send --token wlt_... --chain ethereum --to 0x... --amount 0.01
# Lock when done
npx agent-wallet-cli locknpx agent-wallet-cli <command> [options]npm install -g agent-wallet-cli
agent-wallet-cli <command> [options]git clone https://github.com/bvnk/agent-wallet-cli.git
cd agent-wallet-cli
npm install
npm run build
node dist/index.js <command> [options]All commands accept these options:
| Flag | Description | Default |
|---|---|---|
--format <format> |
Output format (json or text) |
json |
--wallet-dir <path> |
Wallet storage directory | ~/.agent-wallet-cli |
--quiet |
Suppress output |
| Command | Description | Key Flags |
|---|---|---|
init |
Create a new wallet | --password (required), --word-count 12|24, --name |
import |
Import from mnemonic | --password (required), --mnemonic (required), --name |
unlock |
Create session token | --password (required), --duration <seconds>, --name |
lock |
Revoke session token | --name |
export |
Export mnemonic phrase | --password (required), --confirm (required), --name |
| Command | Description | Key Flags |
|---|---|---|
address |
Show wallet addresses | --token, --chain, --account-index, --name |
balance |
Query native or token balance | --token, --chain (required), --network, --token-address, --account-index |
| Command | Description | Key Flags |
|---|---|---|
send |
Transfer native coin or token | --token, --chain (required), --to (required), --amount (required), --token-address, --dry-run, --no-relay |
approve |
Approve ERC-20/SPL spender | --token, --chain (required), --token-address (required), --spender (required), --amount (required) |
allowance |
Query approval amount | --chain (required), --token-address (required), --owner (required), --spender (required) |
transfer-from |
Delegated transfer | --token, --chain (required), --token-address (required), --from (required), --to (required), --amount (required) |
approvals |
Discover ERC-20 approvals | --token, --chain, --network, --limit |
| Command | Description | Key Flags |
|---|---|---|
x402 |
HTTP request with automatic payment | <url>, --token, --method, --header, --body, --dry-run, --yes, --max-amount |
| Command | Description | Key Flags |
|---|---|---|
history |
List recent transactions | --token, --chain (required), --network, --limit |
sign |
Sign message or data | --token, --chain (required), --message / --typed-data / --data |
| Command | Description | Key Flags |
|---|---|---|
networks |
List or configure RPCs | --set <chain:network>, --rpc-url <url>, --reset <chain:network> |
Install the agent-wallet-cli skill so Claude Code (or any Agent Skills-compatible tool) knows how to use the wallet:
# Project-scoped (writes to .claude/skills/ in current directory)
npx agent-wallet-cli install-skill
# User-wide (writes to ~/.claude/skills/)
npx agent-wallet-cli install-skill --globalOr use the universal Agent Skills installer:
npx skills add bvnk/agent-wallet-cliCreate a skill file that teaches the agent how to use agent-wallet-cli. Place this as wallet.md in your OpenClaw skills directory:
# Wallet Management Skill
You have access to `agent-wallet-cli`, a CLI wallet for Ethereum and Solana.
## Setup
The wallet is already initialized. To use it, first unlock with:
\`\`\`bash
agent-wallet-cli unlock --password "$WALLET_PASSWORD" --format json
\`\`\`
Save the `token` field from the JSON response. Pass it to all subsequent commands with `--token <token>`.
## Check Balance
\`\`\`bash
agent-wallet-cli balance --token <token> --chain ethereum --network mainnet --format json
\`\`\`
For ERC-20 tokens, add `--token-address <alias-or-address>`:
\`\`\`bash
agent-wallet-cli balance --token <token> --chain ethereum --network base --token-address usdc --format json
\`\`\`
## Send Funds
\`\`\`bash
agent-wallet-cli send --token <token> --chain ethereum --to <address> --amount <amount> --format json
\`\`\`
For tokens:
\`\`\`bash
agent-wallet-cli send --token <token> --chain ethereum --token-address usdc --to <address> --amount <amount> --format json
\`\`\`
Use `--dry-run` to simulate before sending.
Token transfers automatically use a gasless relay when the wallet has no ETH for gas.
The relay fee (e.g. 0.01 USDC) is deducted from the token amount. Check for `"relay_used": true` in the response.
To disable: add `--no-relay` to the send command.
## Show Addresses
\`\`\`bash
agent-wallet-cli address --token <token> --format json
\`\`\`
## Lock When Done
\`\`\`bash
agent-wallet-cli lock
\`\`\`
## Supported Token Aliases
Ethereum mainnet: usdc, usdt, dai, weth, wbtc
Base: usdc
Polygon: usdc, usdt
Arbitrum: usdc, usdt
Solana mainnet: usdc, usdt
## Important
- Always use `--format json` and parse the JSON response.
- Check `"ok": true` in the response before proceeding.
- Never send more than instructed. Always confirm amounts with the user first.
- Use `--dry-run` for sends when uncertain.Reference it in your openclaw.json:
{
"skills": [
{
"name": "wallet",
"file": "skills/wallet.md"
}
]
}OpenClaw agents with shell access can invoke agent-wallet-cli directly. Add instructions to your agent's system prompt:
You can manage crypto wallets using the `agent-wallet-cli` command.
All commands return JSON with an "ok" field. Always check "ok": true before proceeding.
First unlock the wallet: agent-wallet-cli unlock --password "$WALLET_PASSWORD" --format json
Then use the returned token for subsequent commands.
agent-wallet-cli is designed for programmatic use:
JSON output — all commands return structured JSON by default:
{
"ok": true,
"balance": "1.5",
"symbol": "ETH"
}Session token pattern — unlock once, reuse the token:
# Unlock and capture token
TOKEN=$(agent-wallet-cli unlock --password "pass" --format json | jq -r '.token')
# Use token for subsequent commands
agent-wallet-cli balance --token "$TOKEN" --chain ethereum --format json
agent-wallet-cli send --token "$TOKEN" --chain ethereum --to 0x... --amount 0.01Environment variable — set AGENT_WALLET_CLI_TOKEN to avoid passing --token every time:
export AGENT_WALLET_CLI_TOKEN=$(agent-wallet-cli unlock --password "pass" --format json | jq -r '.token')
agent-wallet-cli balance --chain ethereum
agent-wallet-cli send --chain ethereum --to 0x... --amount 0.01When an EVM wallet has no native tokens (ETH/MATIC/etc.) for gas, ERC-20 token transfers normally fail. The gasless relay solves this using EIP-3009 authorization signatures — the user signs a ReceiveWithAuthorization off-chain, a relayer submits the transaction on-chain, and the relay fee is deducted from the token amount itself (in USDC, not ETH).
- The CLI detects that your wallet has insufficient native balance for gas
- It gets a fee quote from the relay API
- You sign an EIP-3009 authorization (off-chain, no gas required)
- The relay submits the transaction on-chain and pays gas on your behalf
- The relay fee is deducted from your token transfer (e.g., 0.01 USDC)
| Chain | Chain ID |
|---|---|
| Ethereum | 1 |
| Base | 8453 |
| Sepolia | 11155111 |
| Base Sepolia | 84532 |
EIP-3009 compatible tokens — primarily USDC.
# Wallet has 20 USDC but 0 ETH — relay kicks in automatically
agent-wallet-cli send --token wlt_... --chain ethereum --network base-sepolia \
--token-address usdc --to 0x... --amount 2
# Output includes relay metadata:
# {
# "ok": true,
# "tx_hash": "0xead7d546...",
# "chain": "ethereum",
# "network": "base-sepolia",
# "dry_run": false,
# "explorer_url": "https://sepolia.basescan.org/tx/0xead7d546...",
# "relay_used": true,
# "relay_request_id": "req_ea1385df2c2e",
# "relay_fee": "0.01",
# "relay_fee_symbol": "USDC",
# "amount_received": "2"
# }# Per-command: use --no-relay flag
agent-wallet-cli send --no-relay --token wlt_... --chain ethereum --to 0x... --amount 2 --token-address usdc
# Via environment variable
export AGENT_WALLET_CLI_RELAY_ENABLED=false
# Via config.json
# Add to ~/.agent-wallet-cli/config.json:
# { "relay": { "enabled": false } }If the wallet has sufficient native balance for gas, the standard transfer path is used regardless of relay settings.
x402 is an open HTTP payment protocol that uses the 402 Payment Required status code for automatic stablecoin payments. When a server returns 402, the CLI signs a gasless EIP-3009 TransferWithAuthorization, retries the request with the payment signature, and the facilitator settles on-chain.
- The CLI makes an HTTP request to the target URL
- If the server returns
402with payment requirements, the CLI parses them - It selects a compatible EVM payment option (scheme
exact, supported chain) - Signs an EIP-3009
TransferWithAuthorization(no gas required — facilitator pays gas) - Retries the request with the
PAYMENT-SIGNATUREheader - Returns the response along with settlement details (tx hash, network)
# Preview payment requirements (no payment)
agent-wallet-cli x402 https://x402stt.dtelecom.org/v1/session \
--token wlt_... --method POST \
--header "Content-Type:application/json" \
--body '{"minutes":5}' --dry-run
# Make the payment
agent-wallet-cli x402 https://x402stt.dtelecom.org/v1/session \
--token wlt_... --method POST \
--header "Content-Type:application/json" \
--body '{"minutes":5}' --yes --max-amount 0.05| Flag | Description | Default |
|---|---|---|
--method <method> |
HTTP method | GET |
--header <header...> |
HTTP headers (Key:Value, repeatable) |
|
--body <body> |
Request body (@filepath to read from file) |
|
--dry-run |
Show payment requirements without paying | |
--yes |
Skip payment confirmation prompt | |
--max-amount <amount> |
Max payment in human-readable units (e.g. 0.10) |
|
--account-index <n> |
Account index | 0 |
x402 payments work on any EVM chain configured in the wallet:
| Chain | CAIP-2 ID | Asset |
|---|---|---|
| Ethereum | eip155:1 |
USDC |
| Base | eip155:8453 |
USDC |
| Base Sepolia | eip155:84532 |
USDC |
| Polygon | eip155:137 |
USDC |
| Arbitrum | eip155:42161 |
USDC |
| Network | Chain ID | RPC | Explorer |
|---|---|---|---|
| mainnet | 1 | https://eth.llamarpc.com | https://etherscan.io |
| sepolia | 11155111 | https://rpc.sepolia.org | https://sepolia.etherscan.io |
| polygon | 137 | https://polygon-rpc.com | https://polygonscan.com |
| arbitrum | 42161 | https://arb1.arbitrum.io/rpc | https://arbiscan.io |
| base | 8453 | https://mainnet.base.org | https://basescan.org |
| base-sepolia | 84532 | https://sepolia.base.org | https://sepolia.basescan.org |
Warning: Solana support is not heavily tested. Use at your own risk.
| Network | RPC | Explorer |
|---|---|---|
| mainnet | https://api.mainnet-beta.solana.com | https://explorer.solana.com |
| devnet | https://api.devnet.solana.com | https://explorer.solana.com |
Wallets are encrypted at rest using a two-layer scheme:
- Key derivation: Argon2id (time_cost=3, memory_cost=64 MB, parallelism=4) derives a 32-byte key from your password + random salt
- Encryption: AES-256-GCM encrypts the mnemonic with a random 12-byte IV and produces a 16-byte authentication tag
Keystore files are stored in ~/.agent-wallet-cli/keystores/ with 0600 permissions.
When you unlock, the CLI:
- Decrypts the mnemonic with your password
- Re-encrypts it with a random session key (via HKDF-SHA256)
- Returns a token (
wlt_prefix) containing token ID + token secret - Validates tokens using HMAC-SHA256
Tokens expire after the configured duration (default 1 hour, max 24 hours). Session files are stored with 0600 permissions.
All sensitive buffers (mnemonic bytes, derived keys, decrypted material) are zeroed after use via try/finally blocks. This is best-effort — the JavaScript runtime cannot guarantee that the garbage collector hasn't copied the data.
- Keystore files:
0600(owner read/write only) - Session files:
0600 - Wallet directories:
0700(owner only)
Use token names instead of contract addresses:
| Alias | Mainnet | Polygon | Arbitrum | Base | Base Sepolia |
|---|---|---|---|---|---|
usdc |
0xA0b8...eB48 |
0x3c49...3359 |
0xaf88...5831 |
0x8335...2913 |
0x036C...cF7e |
usdt |
0xdAC1...1ec7 |
0xc213...8e8F |
0xFd08...cbb9 |
— | — |
dai |
0x6B17...1d0F |
— | — | — | — |
weth |
0xC02a...6Cc2 |
— | — | — | — |
wbtc |
0x2260...C599 |
— | — | — | — |
| Alias | Mainnet | Devnet |
|---|---|---|
usdc |
EPjFW...Dt1v |
4zMMC...ncDU |
usdt |
Es9vM...wNYB |
— |
# Set a custom RPC
agent-wallet-cli networks --set ethereum:mainnet --rpc-url https://your-rpc.example.com
# Reset to default
agent-wallet-cli networks --reset ethereum:mainnet
# List all configured networks
agent-wallet-cli networks| Variable | Description |
|---|---|
AGENT_WALLET_CLI_TOKEN |
Session token (avoids --token flag on every command) |
AGENT_WALLET_CLI_RELAY_ENABLED |
Enable/disable gasless relay (true/false, default true) |
AGENT_WALLET_CLI_RELAY_API_URL |
Custom relay API endpoint |
git clone https://github.com/bvnk/agent-wallet-cli.git
cd agent-wallet-cli
npm install
npm run buildnpm testsrc/
index.ts # CLI entry point (Commander.js)
commands/ # Command implementations (one file per command)
chains/ # Chain adapters (Ethereum via viem, Solana via @solana/web3.js)
relay/ # Gasless relay (API client, EIP-3009 authorization signing, orchestrator)
x402/ # x402 HTTP payment protocol (EIP-3009 signing, header parsing)
core/ # Keystore, session management, mnemonic derivation, config
security/ # Encryption (Argon2id + AES-256-GCM), memory clearing, file permissions
output/ # JSON/text formatters, error codes
tests/
unit/ # Unit tests for encryption, keystore, mnemonic, memory, session, config, relay
integration/ # End-to-end CLI flow tests
MIT — see LICENSE.