cast only works with EVM-compatible chains, which covers Ethereum and BNB Smart Chain (ETH, USDT-ERC20, USDT-BEP20). TRON (USDT-TRC20) is not EVM-compatible and cannot be used with cast.
Security note: A keystore/hot wallet on a general-purpose machine is meaningfully riskier than hardware signing. For anything beyond small, disposable amounts, pair
castwith a hardware wallet instead of a raw private key — mostcastwallet commands (send,wallet address,wallet list, etc.) support-l/--ledgerand-t/--trezorflags. Always verify RPC endpoints and token contract addresses before broadcasting, and test with tiny amounts first.
curl -L https://foundry.paradigm.xyz | bash
# restart your shell, or run the source command it prints
foundryupVerify:
cast --versionUse cast wallet new, pointed at a directory, to generate a keypair and immediately encrypt it into a keystore file. Hidden password prompting is the default behavior now (the old -p/--password flag is deprecated and unnecessary — omit it). You can also name the account directly in the same command instead of getting a random filename:
mkdir -p ~/.foundry/keystores
cast wallet new ~/.foundry/keystores my-walletYou'll be prompted:
Enter password:
Output shows only the account name and address (e.g. Created new encrypted keystore file: /home/you/.foundry/keystores/my-wallet and Address: 0x...). No private key or mnemonic ever touches your screen or shell history.
This same keystore works for ETH, USDT-ERC20, and USDT-BEP20 — it's one Ethereum-format key/address usable on any EVM chain; you just point it at different RPC URLs and token contracts.
If you already have the keystore file/name:
cast wallet address --account my-wallet(Prompts for your password, does not display it.)
Or list all keystores in the default keystore directory (~/.foundry/keystores):
cast wallet listAdd --dir <path> to list a different directory, or --ledger/--trezor to list hardware wallet accounts instead.
Native ETH balance:
cast balance <YOUR_ADDRESS> --rpc-url https://ethereum-rpc.publicnode.comNative BNB balance (for BEP20 gas):
cast balance <YOUR_ADDRESS> --rpc-url https://bsc-dataseed.binance.orgUSDT-ERC20 balance (Ethereum mainnet USDT contract: 0xdAC17F958D2ee523a2206206994597C13D831ec7):
cast call 0xdAC17F958D2ee523a2206206994597C13D831ec7 \
"balanceOf(address)(uint256)" <YOUR_ADDRESS> \
--rpc-url https://ethereum-rpc.publicnode.comResult is in the token's smallest unit — USDT-ERC20 uses 6 decimals, so divide by 1,000,000.
USDT-BEP20 balance (Binance-Peg BSC-USD contract: 0x55d398326f99059fF775485246999027B3197955):
cast call 0x55d398326f99059fF775485246999027B3197955 \
"balanceOf(address)(uint256)" <YOUR_ADDRESS> \
--rpc-url https://bsc-dataseed.binance.orgUSDT-BEP20 uses 18 decimals.
Always double-check current official contract addresses on Etherscan/BscScan before relying on any address from a third-party source — token contract addresses are a common phishing target.
Send ETH:
cast send <RECIPIENT_ADDRESS> \
--value 0.01ether \
--rpc-url https://ethereum-rpc.publicnode.com \
--account my-walletSend USDT-ERC20:
cast send 0xdAC17F958D2ee523a2206206994597C13D831ec7 \
"transfer(address,uint256)" <RECIPIENT_ADDRESS> 1000000 \
--rpc-url https://ethereum-rpc.publicnode.com \
--account my-wallet1000000 = 1 USDT (6 decimals).
0xdAC17F958D2ee523a2206206994597C13D831ec7 is the USDT contract address on Ethereum network.
Send USDT-BEP20:
cast send 0x55d398326f99059fF775485246999027B3197955 \
"transfer(address,uint256)" <RECIPIENT_ADDRESS> 1000000000000000000 \
--rpc-url https://bsc-dataseed.binance.org \
--account my-walletThat long number (18 decimals) = 1 USDT.
0x55d398326f99059fF775485246999027B3197955 is the USDT contract address on BNB network.
--account <name> uses a keystore from the default ~/.foundry/keystores folder by filename and only ever prompts for the password interactively — it's never passed as a plaintext flag or echoed to screen. If your keystore file lives somewhere else, use --keystore <path> (pointing at the file or its folder) instead of --account.
The keystore file is the exportable, re-importable wallet — it's already an encrypted JSON file. No separate export step is needed.
# Find and copy the keystore file itself
ls ~/.foundry/keystores/
cp ~/.foundry/keystores/my-wallet /path/to/secure/backup/locationStore that JSON file somewhere safe (encrypted external drive, offline storage). It's useless to anyone without your password, but treat it as sensitive.
To use it again later (e.g., on a new machine, or after moving the file back), you have two options — do not use cast wallet import for this, since that command creates a brand-new keystore from a raw private key you paste/type in, it does not load an existing encrypted keystore file:
-
Option A — put it back in the default location and reference it by name as before:
cp /path/to/backup/location/my-wallet ~/.foundry/keystores/ cast wallet address --account my-wallet -
Option B — leave it where it is and point commands at it directly with
--keystore:cast wallet address --keystore /path/to/backup/location/my-wallet cast send <RECIPIENT_ADDRESS> --value 0.01ether \ --rpc-url https://ethereum-rpc.publicnode.com \ --keystore /path/to/backup/location/my-wallet
Either way you'll be asked for the password to decrypt it — the raw key is never displayed. If you ever genuinely need the raw private key back out (e.g., to load it into a different, non-Foundry tool), use:
cast wallet decrypt-keystore --keystore /path/to/keystore-fileThis is the one command that will display the private key on screen, so only run it on a trusted, offline machine.