Skip to main content
The CCTP CLI supports flexible configuration through multiple sources, allowing you to customize defaults, RPC endpoints, and wallet authentication.

Configuration Sources

The CLI uses Viper to load configuration from multiple sources with clear precedence:
1

Command-line flags

Highest priority - overrides all other sources
cctp transfer --testnet --keystore /custom/path
2

Environment variables

Second priority - prefix with CCTP_
export CCTP_TESTNET=true
export CCTP_KEYSTORE_PATH=/path/to/keystore
3

Configuration file

Third priority - ~/.cctp/config.yaml or ./config.yaml
network: testnet
keystore_path: ~/.ethereum/keystore
4

Default values

Lowest priority - built-in defaults

Configuration File

The CLI looks for configuration files in these locations (in order):
  1. Path specified by --config flag
  2. $HOME/.cctp/config.yaml
  3. ./config.yaml (current directory)

Creating a Config File

# Network preference
network: mainnet  # or "testnet"

# Keystore path (optional - uses OS-specific defaults if omitted)
keystore_path: ~/.ethereum/keystore

# Custom RPC endpoints (optional)
rpc_urls:
  Ethereum: https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
  Arbitrum: https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY
  Base: https://base-mainnet.g.alchemy.com/v2/YOUR_KEY
  Polygon PoS: https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY

# Default transfer values (optional)
defaults:
  amount: "100"
  recipient: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"

# Saved addresses for quick access (optional)
saved_addresses:
  - name: "My Wallet"
    address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
  - name: "Treasury"
    address: "0x1234567890123456789012345678901234567890"
  - name: "Partner"
    address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"

Configuration Options

OptionTypeDescriptionDefault
networkstringmainnet or testnetmainnet
keystore_pathstringPath to Ethereum keystore directoryOS-specific
rpc_urlsmapCustom RPC endpoints by chain nameBuilt-in defaults
defaults.amountstringDefault transfer amount(none)
defaults.recipientstringDefault recipient address(none)
saved_addressesarrayNamed addresses for quick access(none)
Chain names in rpc_urls must match exactly (case-sensitive). Use the full chain names like Ethereum, Arbitrum, OP Mainnet, etc.

Wallet Authentication

The CLI supports two methods for wallet authentication:

1. Private Key (Environment Variable)

The simplest method for programmatic usage or testing:
export PRIVATE_KEY=0x1234567890abcdef...
cctp transfer
Security Warning: Never commit private keys to version control or share them. Use this method only for development or in secure environments.
When to use:
  • Automated scripts
  • CI/CD pipelines (with secret management)
  • Development and testing
  • Single-account scenarios

2. Keystore File

More secure method using encrypted keystore files with password protection:
cctp transfer --keystore ~/.ethereum/keystore
The CLI will:
  1. List available accounts from the keystore directory
  2. Prompt you to select an account
  3. Ask for the password to decrypt the keystore
When to use:
  • Production environments
  • Multiple account management
  • Enhanced security with password protection
  • When sharing wallets across applications (e.g., with Geth, Metamask export)

Default Keystore Locations

~/Library/Ethereum/keystore
The CLI automatically checks this location if no --keystore flag is provided.

Setting Up a Keystore

1

Create keystore directory

mkdir -p ~/.ethereum/keystore
2

Add keystore files

Copy your existing keystore files to the directory, or create a new one using Geth:
geth account new --keystore ~/.ethereum/keystore
You can also export from MetaMask:
  1. Open MetaMask
  2. Go to Account Details
  3. Export Private Key
  4. Use a tool like MyCrypto to convert to keystore format
3

Test the keystore

cctp transfer --keystore ~/.ethereum/keystore
The CLI should list your accounts and prompt for a password.
Keystore files are JSON files with encrypted private keys. Example structure:
{
  "address": "742d35cc6634c0532925a3b844bc9e7595f0beb",
  "crypto": {
    "cipher": "aes-128-ctr",
    "ciphertext": "...",
    "cipherparams": {
      "iv": "..."
    },
    "kdf": "scrypt",
    "kdfparams": {
      "dklen": 32,
      "n": 262144,
      "p": 1,
      "r": 8,
      "salt": "..."
    },
    "mac": "..."
  },
  "id": "...",
  "version": 3
}
The file is typically named: UTC--<timestamp>--<address>

Environment Variables

Set environment variables with the CCTP_ prefix (uppercased, with underscores):

Available Variables

VariableTypeDescriptionExample
CCTP_TESTNETbooleanUse testnettrue, false
CCTP_KEYSTORE_PATHstringKeystore directory path/path/to/keystore
PRIVATE_KEYstringPrivate key for wallet0x1234...

Examples

export CCTP_TESTNET=true
export CCTP_KEYSTORE_PATH=~/.ethereum/keystore
export PRIVATE_KEY=0x1234567890abcdef...

# Run transfer
cctp transfer
Never commit .env files containing PRIVATE_KEY to version control. Add .env to your .gitignore.

Custom RPC Endpoints

Override default RPC endpoints to use your own infrastructure or preferred providers.

Configuration File

rpc_urls:
  # Mainnet chains
  Ethereum: https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
  Arbitrum: https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY
  Base: https://base-mainnet.g.alchemy.com/v2/YOUR_KEY
  Polygon PoS: https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEY
  Avalanche: https://api.avax.network/ext/bc/C/rpc
  OP Mainnet: https://opt-mainnet.g.alchemy.com/v2/YOUR_KEY
  
  # Testnet chains
  Ethereum Sepolia: https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY
  Arbitrum Sepolia: https://arb-sepolia.g.alchemy.com/v2/YOUR_KEY

Chain Names for RPC URLs

Use these exact names (case-sensitive):
  • Ethereum
  • Avalanche
  • OP Mainnet
  • Arbitrum
  • Base
  • Polygon PoS
  • Unichain
  • Linea
  • Codex
  • Sonic
  • World Chain
  • Sei
  • XDC
  • HyperEVM
  • Ink
  • Plume
Use these exact names (case-sensitive):
  • Ethereum Sepolia
  • Avalanche Fuji
  • OP Sepolia
  • Arbitrum Sepolia
  • Base Sepolia
  • Polygon PoS Amoy
  • Unichain Sepolia
  • Linea Sepolia
  • Codex Testnet
  • Sonic Testnet
  • World Chain Sepolia
  • Sei Testnet
  • XDC Apothem
  • HyperEVM Testnet
  • Ink Testnet
  • Plume Testnet
  • Arc Testnet

Alchemy

Infura

  • Wide chain support
  • Enterprise options
  • infura.io

QuickNode

Ankr

  • Public endpoints
  • Free and premium
  • ankr.com

LlamaRPC

  • Community-driven
  • No registration needed
  • Free public RPCs

Self-hosted

  • Full control
  • Run Geth, Erigon, etc.
  • Best for privacy

Default Values

Set default values to speed up the transfer process:
defaults:
  amount: "100"  # Default USDC amount
  recipient: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"  # Default recipient
How defaults work:
  • Pre-populate TUI fields (you can still edit them)
  • Override with command-line flags: --amount 500
  • Useful for repetitive transfers to the same recipient
Defaults are convenient but optional. The TUI always allows you to modify these values before confirming the transfer.

Saved Addresses

Store frequently used addresses with friendly names:
saved_addresses:
  - name: "My Wallet"
    address: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
  - name: "Treasury"
    address: "0x1234567890123456789012345678901234567890"
  - name: "Partner Wallet"
    address: "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"
  - name: "Exchange Deposit"
    address: "0x9876543210987654321098765432109876543210"
While saved addresses are stored in the config, the current TUI version doesn’t automatically present them yet. This feature is planned for future enhancements.

Configuration Examples

# Production configuration
network: mainnet

# Use custom high-performance RPCs
rpc_urls:
  Ethereum: https://eth-mainnet.g.alchemy.com/v2/PROD_KEY
  Arbitrum: https://arb-mainnet.g.alchemy.com/v2/PROD_KEY
  Base: https://base-mainnet.g.alchemy.com/v2/PROD_KEY

# No defaults - require explicit input for safety
# Development configuration
network: testnet
keystore_path: ./dev-keystore

rpc_urls:
  Ethereum Sepolia: https://eth-sepolia.g.alchemy.com/v2/DEV_KEY
  Arbitrum Sepolia: https://arb-sepolia.g.alchemy.com/v2/DEV_KEY

defaults:
  amount: "10"
  recipient: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
Create separate config files for each environment:config.mainnet.yaml:
network: mainnet
rpc_urls:
  Ethereum: https://eth-mainnet.g.alchemy.com/v2/MAINNET_KEY
config.testnet.yaml:
network: testnet
rpc_urls:
  Ethereum Sepolia: https://eth-sepolia.g.alchemy.com/v2/TESTNET_KEY
Use with:
cctp transfer --config ./config.mainnet.yaml
cctp transfer --config ./config.testnet.yaml

Configuration Precedence Example

Understanding how different sources combine: 1. Config file (~/.cctp/config.yaml):
network: mainnet
keystore_path: ~/.ethereum/keystore
2. Environment variable:
export CCTP_TESTNET=true
3. Command:
cctp transfer --keystore /custom/path
Final configuration:
  • network: testnet (env var overrides config file)
  • keystore_path: /custom/path (flag overrides env and config)

Security Best Practices

1

Protect Private Keys

  • Never commit PRIVATE_KEY to version control
  • Use environment variables or secure secret management
  • Consider using keystore files for better security
2

Secure Config Files

  • Don’t commit config files with sensitive data
  • Set appropriate file permissions:
chmod 600 ~/.cctp/config.yaml
3

Secure Keystore Files

  • Use strong passwords for keystore encryption
  • Store keystore files in secure locations
  • Backup keystore files securely
4

Use Testnet First

  • Always test with testnet before mainnet
  • Verify recipient addresses carefully
  • Test with small amounts first
5

Monitor RPC Endpoints

  • Use trusted RPC providers
  • Consider self-hosting for sensitive operations
  • Rotate API keys regularly

Troubleshooting

Error: no wallet source available: set PRIVATE_KEY env variable or provide --keystore pathCause: Neither private key nor keystore is configured.Solution:
# Option 1: Use private key
export PRIVATE_KEY=0x...

# Option 2: Use keystore
cctp transfer --keystore ~/.ethereum/keystore
Not an error: Config files are optional. The CLI works fine without one.To suppress the warning: Create an empty config file:
mkdir -p ~/.cctp
touch ~/.cctp/config.yaml
Error: keystore path does not exist: /path/to/keystoreCause: The specified keystore directory doesn’t exist.Solution:
# Create directory
mkdir -p ~/.ethereum/keystore

# Or use correct path
cctp transfer --keystore /correct/path
Error: Custom RPC not being used.Cause: Chain name doesn’t match exactly (case-sensitive).Solution: Use exact chain names:
rpc_urls:
  Ethereum: https://...        # Correct
  # ethereum: https://...     # Wrong - lowercase
  # ETH: https://...          # Wrong - abbreviation
Cause: Missing CCTP_ prefix or not exported.Solution:
# Wrong
TESTNET=true

# Correct
export CCTP_TESTNET=true

# Verify
echo $CCTP_TESTNET
Symptoms: Slow transfers or RPC errors.Cause: Hitting free tier rate limits.Solution:
  • Upgrade to paid RPC plan
  • Use multiple RPC providers
  • Self-host a node

Next Steps

Commands

Learn all available CLI commands and flags

Quick Start

Complete your first cross-chain transfer

SDK Integration

Integrate CCTP into your application

Chain Reference

View all supported chains and capabilities

Build docs developers (and LLMs) love