Skip to main content
Version: 1.13.1

Configuration

RPC Endpoints

All commands require RPC endpoints for the networks involved. The CLI accepts both http[s] and ws[s] URLs.

Where to Get RPCs

ProviderDescription
QuickNodeMulti-chain support with free tier
AlchemyEnterprise-grade with free tier
Chainlist.orgFree public RPCs for EVM networks
InfuraReliable EVM endpoints with free tier
NoderealAptos and EVM support with free tier
Tip: For quick testing, Chainlist.org provides free public RPCs. For production, use Alchemy or Infura for better rate limits.

Providing RPCs

Command line: Use --rpc or --rpcs to specify endpoints directly:

Bash
ccip-cli show 0x123... \
--rpc https://eth-sepolia.example.com \
--rpc https://arb-sepolia.example.com

You can also pass comma-separated values:

Bash
ccip-cli show 0x123... \
--rpcs "https://eth-sepolia.example.com,https://arb-sepolia.example.com"

Environment variables: Export variables prefixed with RPC_. See Environment Variables for details.

Configuration file: Use --rpcs-file to load from a file (default: ./.env):

Bash
ccip-cli show 0x123... --rpcs-file ./my-rpcs.txt

File Format

The parser extracts URLs from any format. Lines can contain prefixes, suffixes, or comments:

https://eth-sepolia.g.alchemy.com/v2/demo
ARB_SEPOLIA_RPC: https://arbitrum-sepolia.drpc.org
RPC_AVALANCHE_TESTNET=https://avalanche-fuji-c-chain-rpc.publicnode.com
https://api.devnet.solana.com # solana devnet
https://api.testnet.aptoslabs.com/v1

The CLI connects to all endpoints in parallel and uses the fastest responding RPC for each network.

Environment Variables

The CLI supports environment variables for configuration. Command-line flags override environment variables.

RPC Configuration

VariableDescriptionExample
RPC_*RPC endpoints (any suffix)RPC_SEPOLIA=https://...

Wallet Configuration

The CLI checks these environment variables in order: PRIVATE_KEY, USER_KEY, OWNER_KEY.

VariableDescription
PRIVATE_KEYPrivate key (EVM: hex, Solana: base58)
USER_KEYAlias for PRIVATE_KEY
OWNER_KEYAlias for PRIVATE_KEY
USER_KEY_PASSWORDPassword for encrypted JSON keystore file or keystore fallback
FOUNDRY_KEYSTORE_PASSWORDPassword for Foundry keystore (takes priority over USER_KEY_PASSWORD)
HARDHAT_KEYSTORE_PASSWORDPassword for Hardhat keystore (takes priority over USER_KEY_PASSWORD)
FOUNDRY_DIROverride Foundry home directory (default: ~/.foundry)

Output Preferences

VariableDescriptionDefault
CCIP_FORMATOutput format (pretty, log, json)pretty
CCIP_VERBOSEEnable debug logging (true/false)false
CCIP_PAGEPagination size for getLogs queries-
CCIP_APICCIP API endpoint URL, or false/no to disable API calls (decentralized mode). true/yes to enable with default URL.Enabled (https://api.ccip.chain.link)

Example .env file:

Bash
# RPC Endpoints
RPC_SEPOLIA=https://eth-sepolia.example.com
RPC_ARB_SEPOLIA=https://arb-sepolia.example.com
RPC_AVALANCHE_FUJI=https://avalanche-fuji.example.com
RPC_SOLANA_DEVNET=https://api.devnet.solana.com
RPC_APTOS_TESTNET=https://api.testnet.aptoslabs.com/v1

# Wallet (for send/manual-exec commands)
USER_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
# Or use a named keystore (pass --wallet foundry:<name> or --wallet hardhat:<name>)
# FOUNDRY_KEYSTORE_PASSWORD=yourFoundryKeystorePassword
# HARDHAT_KEYSTORE_PASSWORD=yourHardhatKeystorePassword # hardhat type requires running from inside a Hardhat project

# Output preferences
CCIP_FORMAT=json
CCIP_VERBOSE=false

Use --rpcs-file to load a different file: ccip-cli show 0x... --rpcs-file ./prod.env

Wallet Configuration

Commands that send transactions require a wallet. The CLI checks these sources in order:

Auto-Detection

If --wallet is omitted, the CLI checks environment variables first (PRIVATE_KEY, USER_KEY, OWNER_KEY in that order), then falls back to scanning your --rpcs-file (default: ./.env):

Bash
# .env file
RPC_SEPOLIA=https://eth-sepolia.example.com
USER_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

# CLI will use USER_KEY automatically
ccip-cli send ethereum-testnet-sepolia 0x... dest --receiver 0x...

--wallet Option

Pass directly or specify a file path:

ChainAccepted Formats
EVMHex private key, path to encrypted JSON keystore, ledger[:index], foundry:<name>, or hardhat:<name>
SolanaBase58 private key, or path to id.json file (default: ~/.config/solana/id.json)
AptosHex private key, or path to text file containing it
SuiHex or base64 private key
TON64-byte hex private key (0x-prefixed), mnemonic phrase (space-separated), path to key file, or ledger[:index]
CantonNot required — party ID comes from --canton-config; transactions submit via JWT

Foundry Cast Keystore

If you manage keys with Foundry Cast, use foundry:<name>:

Bash
# Import a key into the Foundry keystore (one-time setup)
cast wallet import sender --interactive

# Use it with the CLI
ccip-cli send ... --wallet foundry:sender

Password resolution order:

  1. $FOUNDRY_KEYSTORE_PASSWORD env var
  2. $USER_KEY_PASSWORD env var
  3. Interactive prompt

The keystore directory defaults to ~/.foundry/keystores/ and can be overridden with $FOUNDRY_DIR.

Hardhat Keystore

If you manage keys with Hardhat's built-in keystore, use hardhat:<name>. The CLI runs node_modules/.bin/hardhat keystore get directly, so Hardhat must be installed as a dev dependency in your project:

Bash
# Import a key into the Hardhat keystore (one-time setup)
npx hardhat keystore set sender

# Use it with the CLI (run from inside your Hardhat project)
ccip-cli send ... --wallet hardhat:sender

Password resolution order:

  1. $HARDHAT_KEYSTORE_PASSWORD env var (piped silently to Hardhat)
  2. $USER_KEY_PASSWORD env var (piped silently to Hardhat)
  3. Interactive prompt (ccip-cli prompts, answer is piped to Hardhat)

Ledger Hardware Wallet

Connect a Ledger device:

Bash
ccip-cli send ... --wallet ledger

Use a specific derivation index:

Bash
ccip-cli send ... --wallet ledger:1 # Uses m/44'/60'/1'/0/0 for EVM

Global Options

These options are available on all commands:

OptionAliasTypeDefaultDescription
--rpcs--rpcstring[]-RPC endpoint URLs
--rpcs-file-string./.envFile containing RPC endpoints
--format-fstringprettyOutput format: pretty, log, or json
--verbose-vboolean-Enable debug logging
--page-number-Pagination size for getLogs queries
--api-stringhttps://api.ccip.chain.linkCCIP API endpoint URL. Enabled by default. Pass a URL for a custom endpoint. Use --no-api to disable (decentralized RPC-only mode)
--canton-config-string-Path to Canton config JSON file (required for Canton operations)
--indexer-string[]-CCIP v2 indexer URLs for CCV verifications (used when lane involves Canton)
--help-hboolean-Show help
--version-Vboolean-Show version

Output formats:

FormatUse Case
prettyHuman-readable tables (default)
logConsole output with additional details
jsonMachine-readable, suitable for scripting — see Reading JSON Output

Network Identifiers

Networks can be specified by name, chain ID, or CCIP chain selector. The CLI uses chain-selectors for resolution.

Chain FamilyIdentifier FormatExample
AllCCIP chain selector16015286601757825753 (Sepolia)
AllNetwork nameethereum-mainnet, ethereum-testnet-sepolia
EVMNumeric chain ID1 (Ethereum), 11155111 (Sepolia)
SolanaGenesis hash5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d
AptosPrefixed chain IDaptos:1 (mainnet), aptos:2 (testnet)
SuiPrefixed chain IDsui:1
CantonPrefixed chain IDcanton:TestNet, canton:DevNet, canton:MainNet

Canton Configuration

Canton operations require a JSON config file passed via --canton-config <path>. The Canton Ledger API URL is provided through the normal --rpc / --rpcs mechanism (detected by /api/json, /api/ledger, or port 7575).

Config file format:

JSON
{
"party": "u_7c1f39da042a::1220c250c23c...",
"ccipParty": "ccipOwner::1220e382f4e5...",
"auth": {
"type": "clientCredentials",
"authUrl": "https://auth.example.com/oauth2/default"
},
"edsUrl": "https://eds.example.com",
"transferInstructionUrl": "https://transfer-instruction.example.com",
"indexerUrl": "https://indexer.example.com",
"chainId": "canton:TestNet",
"packages": {
"perPartyRouter": "ccip-runtime-v2",
"ccipReceiver": "ccip-receiver-v2",
"ccipSender": "ccip-sender-v2"
},
"senderInstanceId": "prod-ccipsender",
"ccvs": ["0x5b92820da106..."]
}

Set CANTON_CLIENT_ID and CANTON_CLIENT_SECRET env vars for the clientCredentials flow, or use "jwt": "eyJ..." in place of the auth block for a pre-obtained token. See Canton Authentication for all flows.

FieldRequiredDescription
partyYesUser ledger party for actAs and transaction visibility
ccipPartyYesCCIP operator party (CCIPSender signatory / fee recipient)
jwtNo*JSON Web Token for Canton Ledger API authentication
authNo*OIDC auth config (alternative to jwt — see below)
edsUrlYesBase URL for the Explicit Disclosure Service (EDS)
transferInstructionUrlYesBase URL for the Transfer Instruction API
externalEdsUrlsByOwnerNoMap of owner party → external EDS URL
indexerUrlNoCCIP v2 indexer URL for CCV verifications (required for Canton manual execution)
chainIdNoCCIP Canton chain ID (e.g. canton:TestNet); skips auto-detection
senderInstanceIdNoCCIPSender instance id used as router on Canton source (CLI -r overrides)
defaultSendGasLimitNoDefault gas limit for Canton → destination sends
feeTransferFactoryAmountNoTransfer-factory preview amount for fee payments (default: "1.0")
ccvsNoCCV instance addresses for execute disclosures and send defaults
packagesNoDAR package names for ACS template filters

* Either jwt or auth is required. If both are present, jwt takes precedence.

[!NOTE] The top-level jwt field is shorthand for auth: { type: "static", jwt } — both are equivalent. If both are present, jwt takes precedence.

Canton Authentication

The auth object supports three flows. The static flow wraps a pre-obtained JWT (equivalent to the top-level jwt field); clientCredentials and authorizationCode obtain a JWT automatically via OpenID Connect (OIDC):

auth.typeUse caseRequired auth fields
staticPre-obtained JWTjwt
clientCredentialsMachine-to-machine (CI/CD)authUrl, clientId†, clientSecret
authorizationCodeInteractive browser login (PKCE)authUrl, clientId

clientId and clientSecret may be omitted from the config file and resolved from CANTON_CLIENT_ID / CANTON_CLIENT_SECRET env vars instead. Keep secrets in env vars, not in config files.

Client credentials example (CI/CD, machine-to-machine):

JSON
{
"auth": {
"type": "clientCredentials",
"authUrl": "https://auth.example.com"
}
}
Bash
export CANTON_CLIENT_ID="my-client-id"
export CANTON_CLIENT_SECRET="my-client-secret"

Authorization code example (interactive browser login for human users):

JSON
{
"auth": {
"type": "authorizationCode",
"authUrl": "https://auth.example.com",
"callbackUrl": "http://localhost:8400/callback"
}
}
Bash
export CANTON_CLIENT_ID="my-client-id"

The authorizationCode flow opens a browser for login and starts a local callback server to receive the authorization code. The callbackUrl defaults to http://localhost:8400/callback — override it if port 8400 is in use or your OIDC provider requires a different redirect URI. PKCE with S256 is required.

When auth is set, the CLI resolves a JWT upfront (before connecting to the ledger) via the SDK's runtime-agnostic OAuth 2.0 protocol helpers (backed by oauth4webapi). The SDK itself never orchestrates an OAuth flow — it only consumes what it's given (jwt, which accepts either a string or a () => Promise<string> getter). For clientCredentials and authorizationCode, the CLI injects a getter so tokens are refreshed automatically per request. Optional auth fields: audience (Auth0-specific), scopes (defaults to daml_ledger_api for client credentials, openid daml_ledger_api for authorization code), callbackUrl (authorization code only, defaults to http://localhost:8400/callback).

[!NOTE] The authorizationCode flow is orchestrated by the CLI: it starts a local callback server (node:http) and opens the default browser (open/xdg-open). These Node-specific steps live in the CLI, not the SDK, so the SDK stays runtime-agnostic (no node:* imports) and can be embedded in web/Electron apps. Web embedders compose the SDK's protocol helpers (buildAuthorizationRequest, validateAuthorizationCallback, exchangeAuthorizationCode) with their own redirect/callback handling.

Canton Wallet

On Canton, the party ID comes from config and transactions are submitted directly using the JWT from config (either the static jwt field or a token resolved from auth). The --wallet flag is not required for Canton operations.

Bash
ccip-cli send \
-s canton-testnet \
-d ethereum-testnet-sepolia \
-r prod-ccipsender \
--canton-config ./canton-config.json \
--rpc https://ledger.example.com/api/json \
--rpc https://ethereum-sepolia-rpc.example.com \
--to 0xReceiverContract \
-t link-token=1.0 \
--no-estimate-gas-limit

Shell Completion

Enable tab-completion for commands and options by adding the completion script to your shell profile:

Bash
# bash
ccip-cli completion >> ~/.bashrc

# zsh
ccip-cli completion >> ~/.zshrc

Restart your shell or run source ~/.bashrc (or ~/.zshrc) to activate. Once enabled, press Tab to autocomplete commands, subcommands, and flags.

See Also

  • show - Track cross-chain messages
  • send - Send messages with wallet configuration