Foundry Cast Tutorial: Interact with Smart Contracts from the CLI (2026)
TL;DR: Cast is the Foundry CLI tool for interacting with EVM chains directly from the terminal — no frontend, no SDK, no boilerplate. It covers number/unit conversions, reading contract state with cast call, sending state-changing transactions with cast send, querying on-chain data (ETH balances, blocks, transactions), decoding calldata and event topics, estimating gas, and managing private keys securely via an encrypted keystore. RPC endpoints can be set as CLI flags, environment variables, or in foundry.toml.
Table of Contents
- Cast examples
- Number and unit conversions
- ABI utilities: signatures, calldata, and event topics
- Query blockchain state: balance, block, and transaction
- Call smart contracts to read values
- Write smart contracts to update values
- Estimate gas before sending
- Handle private keys and addresses
- RPC configuration patterns
- Frequently Asked Questions
- Extra resources
Foundry is one of the most widely used smart contract development frameworks in the Ethereum ecosystem. The full suite consists of three tools: Forge (compile, test, deploy), Anvil (local node), and Cast (CLI interaction). This post focuses on Cast.
Cast is a zero-dependency command-line Swiss Army knife for EVM chains. It replaces what would otherwise require a custom script in ethers.js or viem — things like checking an on-chain value, decoding a failed transaction's calldata, computing a function selector, or sending a one-off transaction — with a single terminal command. Cast works against any EVM-compatible network: Ethereum mainnet, L2s (Arbitrum, Optimism, Base, Polygon), testnets, and local Anvil nodes.
In this post we cover the most useful Cast commands with practical examples drawn from real Solidity development workflows.
Cast examples
In this section, we will see some practical examples of how to use Cast for different purposes, such as number conversion, reading smart contract values, writing smart contract values, and handling private keys.
If you want to copy the commands, just click on the command box and it will be copied to your clipboard.
Number and unit conversions
Cast has a rich set of conversion utilities. These are especially useful when reading raw bytes32 storage slots, working with token amounts that have 18 decimals, or computing hash values.
Decimal ↔ hexadecimal
cast to-dec 0x000000000000000000000000000000000000000000000000000000000000002acast to-hex 50Token amount conversions (parse-units / format-units)
When calling an ERC-20 transfer or mint function you almost always work with wei-denominated amounts internally. cast parse-units converts human-readable amounts and cast format-units does the reverse:
cast parse-units 1.5 18cast format-units 1500000000000000000 18The second argument is the number of decimals (18 for most ERC-20 tokens, 6 for USDC).
Ether unit shortcuts
cast to-wei 1 ethercast from-wei 1000000000000000000Hash a value with keccak256 — useful for computing function selectors, TypeHash constants, or storage slot keys by hand:
cast keccak "Transfer(address,address,uint256)"Type conversions
cast to-bytes32 0x1234cast --to-checksum-address 0xd8da6bf26964af9d7eed9e03e53415d37aa96045Those are just a sample — Cast also supports to-ascii, to-utf8, to-rlp, from-rlp, to-base, and more.
ABI utilities: signatures, calldata, and event topics
One of Cast's most powerful but underused feature sets is its ABI tooling. These commands let you work with raw transaction calldata, compute function selectors, and decode events \u2014 without needing a full dev environment.
Compute a function selector (first 4 bytes of keccak256)
cast sig "transfer(address,uint256)"Output: 0xa9059cbb — this is the well-known ERC-20 transfer selector.
Reverse-lookup a selector in the 4byte.directory database
When you see an unknown 0xabcd1234 in a transaction and want to know what function it is:
cast 4byte 0xa9059cbbDecode raw calldata — invaluable when debugging a reverted transaction:
cast decode-calldata "transfer(address,uint256)" 0xa9059cbb000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000de0b6b3a7640000Compute an event topic (keccak256 of the event signature)
cast sig-event "Transfer(address indexed,address indexed,uint256)"Output: 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef — the ERC-20 Transfer topic.
Decode ABI-encoded return data
If you captured raw return data from a cast call and want to decode it manually:
cast abi-decode "balanceOf(address)(uint256)" 0x0000000000000000000000000000000000000000000000000de0b6b3a7640000Query blockchain state: balance, block, and transaction
Cast can query any live or archived on-chain state. These commands are perfect for quick checks during development or incident response without having to open a block explorer.
Check an ETH balance
cast balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --rpc-url $RPC_URLAdd --ether to get the result formatted in ETH instead of wei:
cast balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --ether --rpc-url $RPC_URLInspect the latest block
cast block latest --rpc-url $RPC_URLFetch a specific field only (e.g., timestamp, gasLimit, baseFeePerGas):
cast block latest --field baseFeePerGas --rpc-url $RPC_URLInspect a transaction
cast tx 0xabc123...txhash --rpc-url $RPC_URLRead a raw storage slot — useful for verifying packed storage layouts or inspecting proxy implementation slots:
cast storage [contract_address] 0 --rpc-url $RPC_URLThe EIP-1967 implementation slot for a transparent proxy is a well-known value you can query directly:
cast storage [proxy_address] 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc --rpc-url $RPC_URLGet the bytecode of a deployed contract
cast code [contract_address] --rpc-url $RPC_URLCall smart contracts to read values
One of the most common use cases of Cast is to call smart contract functions to read data from the blockchain. It allows easily querying contract state without needing to write any code.
The aspects that must be considered are:
- The contract address: The address of the smart contract you want to interact with.
- The function signature: The signature of the function you want to call.
- The network RPC URL: The URL of the Ethereum node you want to connect to. You can include it directly in the cast command, read it from a .env file, or configure it in the foundry.toml file.
cast call [contract_address] "number()" --rpc-url [network_rpc_url]
In this second example, we are calling the allowance function of an ERC20 token contract to check the allowance that an address has given to another address. The main difference with the previous example is that this function requires two parameters: the owner address and the spender address. Furthermore, in this case we are passing the response type (uint256).
cast call [contract_address] "allowance(address, address)(uint256)" [param1] [param2] --rpc-url [network_rpc_url]Call at a specific block number — useful for historical state queries, e.g., checking a balance as it was at block 20000000:
cast call [contract_address] "balanceOf(address)(uint256)" [address] --rpc-url $RPC_URL --block 20000000Fetch multiple values at once using shell command chaining — no custom script required:
cast call [token_address] "name()(string)" --rpc-url $RPC_URL ; cast call [token_address] "symbol()(string)" --rpc-url $RPC_URLWrite smart contracts to update values
Another important use case of Cast is to send transactions to smart contracts to update their state. This allows you to interact with contracts and modify their data.
When sending transactions, you need to consider:
- The private key: The private key of the account you want to use to sign the transaction.
- The contract address: The address of the smart contract you want to interact with.
- The function signature: The signature of the function you want to call.
- The network RPC URL: The URL of the Ethereum node you want to connect to. You can include it directly in the cast command, read it from a .env file, or configure it in the foundry.toml file.
In this example, we are calling the mint function of an ERC20 token contract to mint new tokens to a specific address. The function requires two parameters: the recipient address and the amount of tokens to mint.
cast send --private-key $PRIVATE_KEY [contract_address] "mint(address,uint256)" [param1] [param2] --rpc-url $RPC_URLIn this second example, we are using the cast parse-units command to convert a human-readable token amount (5 tokens) into its corresponding smallest unit (wei for Ether or the token's smallest denomination). This is particularly useful when dealing with ERC20 tokens that have decimals.
cast send --private-key $PRIVATE_KEY [contract_address] "mint(address,uint256)" [param1] $(cast parse-units 5) --rpc-url $RPC_URLSend ETH (value transfer)
cast send --private-key $PRIVATE_KEY [recipient_address] --value $(cast to-wei 0.01 ether) --rpc-url $RPC_URLSend with explicit gas price — useful on congested networks or when you want to speed up or slow down a transaction:
cast send --private-key $PRIVATE_KEY [contract_address] "setNumber(uint256)" 42 --gas-price $(cast to-wei 30 gwei) --rpc-url $RPC_URLEstimate gas before sending
Before broadcasting a state-changing transaction it is good practice to estimate the gas cost. cast estimate performs a dry-run using eth_estimateGas and returns the gas units the transaction would consume — without submitting it to the network. No private key required.
cast estimate [contract_address] "mint(address,uint256)" [param1] $(cast parse-units 100 18) --rpc-url $RPC_URLTo convert the gas estimate into an ETH cost, multiply by the current base fee:
cast estimate [contract_address] "transfer(address,uint256)" [param1] 1000000000000000000 --rpc-url $RPC_URLcast block latest --field baseFeePerGas --rpc-url $RPC_URLcast estimate also works against --from a specific address so the simulation reflects the real caller's state (balance, allowances, etc.):
cast estimate --from [caller_address] [contract_address] "approve(address,uint256)" [spender] 1000000000000000000 --rpc-url $RPC_URLHandle private keys and addresses
Cast also provides commands to handle private keys securely. To understand the importance of this, we must understand that in production environments, private keys should never be hardcoded, exposed in the code or even included in a .env file. Instead, they should be managed securely using the keystore.
The keystore is a secure storage mechanism that encrypts private keys and protects them with a password. To store a private key in the keystore, you can use the following command:
cast wallet import [key_name] --interactiveThis command will prompt an interactive input in your terminal where you must paste the private key you want to store.
To see the list of private keys you have stored there, use:
cast wallet listTo use a private key stored in the keystore, for running a script you can use:
forge script script/general/DeploySimpleTest.s.sol --fork-url [rpc_url] --account [key_name] --sender [address_corresponding_to_pk] --broadcast
This command will use the private key associated with the specified key name to sign the transactions.
RPC configuration patterns
Typing --rpc-url on every command becomes tedious quickly. Cast supports three tiers of RPC configuration, applied in order of precedence (highest first):
1 — CLI flag (one-off override)
cast call [contract_address] "totalSupply()(uint256)" --rpc-url https://mainnet.infura.io/v3/YOUR_KEY2 — Environment variable
Set ETH_RPC_URL once for the session and Cast will use it automatically:
export ETH_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/YOUR_KEYcast block latest3 — foundry.toml (project-level default)
Add an [rpc_endpoints] section to configure named networks. Cast picks up the file automatically when run inside the project directory:
foundry.toml
[rpc_endpoints]
mainnet = "$"
polygon = "$"
sepolia = "$"
local = "http://127.0.0.1:8545"
Then reference a named network with --rpc-url:
cast call [contract_address] "owner()(address)" --rpc-url polygonNamed network aliases are resolved via the [rpc_endpoints] map, so your commands stay readable and portable across team members who set their own API keys in .env.
Frequently Asked Questions
What is Cast in Foundry?
Cast is the CLI interaction tool in the Foundry smart contract development suite. It lets you call contract functions, send transactions, query blockchain state (balances, blocks, transactions, storage slots), convert data formats, decode calldata and event topics, estimate gas, and manage signing keys — all from the terminal, without writing JavaScript or Python scripts.
What's the difference between cast call and cast send?
cast call performs a read-only simulation (eth_call) — it does not change blockchain state, does not require a private key, and costs no gas. cast send broadcasts a real signed transaction (eth_sendRawTransaction) that modifies state and consumes gas. Use cast call to inspect data and cast send to execute writes.
How do I read data from a smart contract using Cast?
Use cast call [contract_address] "functionName(paramTypes)(returnTypes)" [params] --rpc-url $RPC_URL. Always include the return type in parentheses after the parameter list so Cast can decode the response. Example for ERC-20 balance: cast call 0xToken "balanceOf(address)(uint256)" 0xHolder --rpc-url $RPC_URL.
How do I convert hexadecimal to decimal with Cast?
Use cast to-dec 0x2a (outputs 42) or cast to-hex 42 (outputs 0x2a). For token amounts use cast format-units 1000000000000000000 18 (outputs 1.000000000000000000). For ETH: cast from-wei 1000000000000000000 (outputs 1.000000000000000000 ETH).
How do I compute a function selector with Cast?
Use cast sig "functionName(paramTypes)". Example: cast sig "transfer(address,uint256)" outputs 0xa9059cbb. To reverse-lookup an unknown selector: cast 4byte 0xa9059cbb queries the 4byte.directory database.
How do I decode calldata from a failed transaction?
Use cast decode-calldata "functionName(paramTypes)" [raw_calldata]. You can get the raw calldata from a block explorer. This is extremely useful for debugging reverts, especially when the frontend does not expose the underlying call parameters.
How should I handle private keys with Cast?
Never hardcode private keys or store them in .env files for production environments. Use Cast's encrypted keystore: cast wallet import [key_name] --interactive stores the key encrypted with a password. Reference it later with --account [key_name] and Cast will prompt for the password at runtime.
How do I estimate gas before sending a transaction?
Use cast estimate [contract_address] "functionName(types)" [params] --rpc-url $RPC_URL. It simulates the transaction and returns gas units. Multiply by cast block latest --field baseFeePerGas to get the ETH cost. Add --from [address] to simulate from a specific caller.
Can Cast work with any EVM network?
Yes. Cast is network-agnostic and works with Ethereum mainnet, testnets (Sepolia, Holesky), L2s (Arbitrum, Optimism, Base, Polygon), and local Anvil nodes. Set the RPC endpoint via --rpc-url, ETH_RPC_URL env var, or named aliases in foundry.toml's [rpc_endpoints] section.
What is cast parse-units and when should I use it?
cast parse-units [amount] [decimals] converts human-readable token amounts to their smallest unit. cast parse-units 1.5 18 outputs 1500000000000000000. Use it inside cast send commands with command substitution: $(cast parse-units 1.5 18) so you never have to count zeros manually.
Do I need to specify return types in cast call signatures?
It is strongly recommended. Without a return type, Cast prints raw hex. With return types (e.g., (uint256), (address,uint256)), Cast decodes and formats the output automatically. For tuple/struct returns, you can specify multiple values: "getReserves()(uint112,uint112,uint32)".
Extra resources
If you want to learn more about Cast and its capabilities, you can check the official documentation at Cast official docs
Furthermore, if you want to learn more about other Foundry tools, you can check the Foundry Anvil tutorial for local Ethereum node, where we explain how to use Anvil, the local Ethereum node from Foundry or if you are interested in the main tool of the suite, you can check the Foundry Forge tutorial for smart contract development and testing, where we explain how to use Forge, the main tool from Foundry for smart contract development, testing and deployment.
On the other hand, if you want to learn more about Solidity development and smart contract programming, you can check the Smart Contract Accounts guide where we explain how smart contract accounts work and how to create your own smart contract wallet with Solidity code examples. Finally, if you want to learn about signing data in smart contracts, you can check the EIP-712 signing data guide where we explain how to use EIP-712 to sign data in a secure and user-friendly way.