Sem 7

Foundry and Anvil

Lab deck 9 and the Anvil Setup Guide: why local testnets, the Foundry toolkit (forge, cast, anvil, chisel), installing Foundry on Ubuntu WSL, running an Anvil node, querying it with cast, the JSON-RPC to cast mapping, and sending ETH between Anvil accounts through MetaMask.

Where do we run blockchain code?Search on YouTube

A traditional program and a smart contract run in different places.

Traditional programSmart contract
Python codeSolidity
Python interpreterCompiler
Your computerEVM bytecode
Ethereum / EVM-compatible blockchain
The EVM executes the bytecode

Should we deploy every experiment to mainnet?Search on YouTube

Contract development is a loop: write contract A, deploy, call a function, modify state, see a test fail, deploy again. On mainnet every step costs real ETH and gas, state changes are irreversible, and there is network latency. It also exposes vulnerable or experimental code to the public.

Public testnets (Sepolia) and simulated testnets (Tenderly) help, but both have drawbacks discussed in L10. This creates the need for a local testnet, where you can experiment freely.

Foundry: a development toolkitSearch on YouTube

Foundry is a modular smart-contract development toolchain for Ethereum and EVM chains, written in Rust. It gives tools for building, testing, deploying and interacting with smart contracts. Older frameworks such as Hardhat and Truffle rely on Node.js and JavaScript or TypeScript. Foundry lets you write, test and debug contracts directly in Solidity.

ToolPurposeThink of it as
ForgeBuild, test, deploy smart contractsDevelopment and testing
CastInteract with EVM blockchainsBlockchain command-line interface
AnvilRun a local Ethereum node / blockchainLocal Ethereum laboratory
ChiselInteractive Solidity / EVM experimentationSolidity REPL

"Four Cats Ate Chips": Forge, Cast, Anvil, Chisel.

AnvilSearch on YouTube

Anvil is a fast, lightweight local Ethereum node and test environment built in Rust as part of Foundry. It acts as your own private Ethereum testnet running locally. You get:

  • instant transactions
  • instant block creation
  • deterministic accounts
  • free development ETH
  • complete control
  • rapid experimentation
  • easy reset

Anvil gives us a blockchain to deploy and execute contracts on. It provides an Ethereum-compatible local development environment.

CastSearch on YouTube

Cast is a command-line interface for reading from and writing to any EVM-compatible chain. It removes the need to open a browser wallet or block explorer for basic checks. It is a "Swiss-army knife": make calls, query balances, encode and decode calldata, and send transactions from the terminal.

User → Cast → JSON-RPC → Anvil → Blockchain / EVM

ForgeSearch on YouTube

Forge is Foundry's main smart-contract development and testing tool. It compiles Solidity, runs unit and fuzz tests, and deploys contracts. Unlike Truffle or Hardhat, where tests are in JavaScript, Forge lets you write all unit and integration tests in Solidity.

ChiselSearch on YouTube

Chisel is a Read-Eval-Print Loop (REPL) for Solidity. You test isolated pieces of Solidity syntax, arithmetic or opcode behaviour in the terminal, without a full project or a throwaway contract.

Installing Foundry on Windows (WSL)Search on YouTube

Foundry provides the foundryup installer. There are two methods, Git and WSL; the lab uses WSL. You may already have WSL for Docker, but use a clean Ubuntu WSL for this.

Step 1. Check current WSL distributions (PowerShell):

wsl --list          # shows docker-desktop (Default)

Step 2. Install Ubuntu:

wsl --install -d Ubuntu

It may take a few minutes and may ask you to restart Windows. Ubuntu then asks you to create a Linux username and password (the deck uses user ether). These are separate from your Windows credentials.

Step 3. Update Ubuntu and install prerequisites (upgrading is optional and skipped):

sudo apt update
sudo apt install curl git build-essential -y

Step 4. Install Foundry's installer:

curl -L https://foundry.paradigm.xyz | bash

This does not install forge or anvil yet. It installs foundryup, Foundry's version manager and installer, into ~/.foundry/bin.

Step 5. Add Foundry to the current PATH and check the installer:

export PATH="$PATH:/home/ether/.foundry/bin"
foundryup --version        # foundryup 0.0.8 ...

Step 6. Install Foundry (downloads the current binaries; the deck gets v1.8.3):

foundryup

The output verifies forge, cast, anvil, chisel and solar, then prints "foundryup is up to date".

Step 7. Verify Anvil:

anvil --version            # anvil Version: 1.8.3, Commit SHA, Build Timestamp, Build Profile: dist

What is installed now:

Ubuntu (WSL 2)
└── Foundry v1.8.3
    ├── forge
    ├── cast
    ├── anvil   ← what we are going to use
    ├── chisel
    └── solar

What exactly is Anvil?Search on YouTube

Think of Anvil as a small Ethereum-compatible blockchain node running on your computer. When you run anvil, it starts a blockchain inside Ubuntu WSL. It provides Ethereum accounts, private keys for them, ETH balances, blocks, transactions, gas accounting, EVM execution and a JSON-RPC endpoint. It is not merely a "blockchain simulator".

YOUR WINDOWS PC
      │
WSL 2 / Ubuntu
      │
    ANVIL
 ┌────┴────┐
Ethereum   EVM
accounts
 └────┬────┘
Local blockchain
      │
JSON-RPC API
      │
127.0.0.1:8545

Is it a real Ethereum blockchain? Anvil implements an Ethereum-compatible development environment, but it is not Ethereum Mainnet. You own the entire network. There are no external validators or miners to talk to.

What happens at start? Anvil creates the first block and gives pre-funded wallets and their keys for development. These are not real ETH, only local balances kept by your Anvil chain.

What is the RPC endpoint? Anvil exposes Ethereum JSON-RPC, usually at http://127.0.0.1:8545. Applications do not "talk to the blockchain" directly; they go through RPC. You can send the same requests as on Sepolia: eth_blockNumber, eth_getBalance, eth_getBlockByNumber, eth_getTransactionByHash, eth_sendRawTransaction.

Start the local Ethereum networkSearch on YouTube

anvil

What the output means:

  • 10 accounts are created. They are real Ethereum-style addresses but exist only inside your Anvil network. Each holds 10,000 ETH.
  • Each account has a private key. The key lets someone sign transactions for the account. These are Anvil's standard development keys: intentionally public and known. Never use them with real funds.
  • The wallet mnemonic is test test test test test test test test test test test junk.
  • Only the genesis block exists. The chain starts at block 0. Anvil creates later blocks as transactions are processed.
  • Chain ID 31337.
  • Endpoint 127.0.0.1:8545. 8545 is the standard HTTP JSON-RPC port.

Keep this terminal open. Do not press Ctrl+C, or the chain stops and its state is lost. Use a separate Ubuntu terminal for cast.

Interacting with the chain using castSearch on YouTube

Cast is the client that talks to the Anvil node. It submits JSON-RPC requests to Anvil on the exposed port; Anvil answers; cast displays the result.

cast balance → JSON-RPC request → 127.0.0.1:8545 → Anvil → local blockchain state

In the new terminal, cast is not found at first: the earlier export PATH applied only to the old terminal. Make it permanent:

echo 'export PATH="$PATH:$HOME/.foundry/bin"' >> ~/.bashrc
source ~/.bashrc
which cast

Basic queriesSearch on YouTube

cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:8545
# 10000000000000000000000   (wei)

cast chain-id --rpc-url http://127.0.0.1:8545       # 31337
cast block-number --rpc-url http://127.0.0.1:8545   # 0
cast block latest --rpc-url http://127.0.0.1:8545

Ethereum stores balances in the smallest unit, wei: 1 ETH=10181\ \text{ETH} = 10^{18} wei. So 102210^{22} wei = 10,000 ETH, matching the Anvil terminal. Cast handles the lower-level communication for you.

Cast reads the ETH_RPC_URL environment variable. export ETH_RPC_URL=http://127.0.0.1:8545 lets you drop --rpc-url from every command. Cast also defaults to localhost:8545, which is why the guide's cast nonce works without it.

JSON-RPC to cast cheat sheetSearch on YouTube

JSON-RPC methodCast commandExplanation
eth_chainIdcast chain-idThe chain ID
eth_blockNumbercast block-numberLatest block number
eth_getBlockByNumbercast block <block>Block by number or tag such as latest
eth_getBlockByHashcast block <block-hash>Block by its hash
eth_getBalancecast balance <address>ETH balance of an address
eth_getTransactionCountcast nonce <address>Transaction count / nonce of an account
eth_getCodecast code <address>Bytecode at an address; 0x means no contract code
eth_getStorageAtcast storage <address> <slot>Raw value of a contract storage slot
eth_getTransactionByHashcast tx <tx-hash>Transaction details by hash
eth_getTransactionReceiptcast receipt <tx-hash>Receipt: status, gas used, logs, block
eth_gasPricecast gas-priceNode's suggested gas price
eth_callcast call <address> <data>Message call without a transaction or state change
eth_sendRawTransactioncast publish <signed-tx>Send an already-signed raw transaction
eth_sendTransactioncast send ...Create and send a transaction through the node or wallet
eth_estimateGascast estimate ...Estimate gas for a transaction
eth_getLogscast logs ...Event logs matching filters
web3_clientVersioncast clientClient / node software info
eth_accountscast rpc eth_accountsAccounts exposed by the node
eth_getBlockTransactionCountByNumbercast rpc eth_getBlockTransactionCountByNumber ...Number of txs in a block
eth_getBlockTransactionCountByHashcast rpc eth_getBlockTransactionCountByHash ...Number of txs in a block, by hash
eth_getTransactionByBlockNumberAndIndexcast rpc eth_getTransactionByBlockNumberAndIndex ...Tx by block number and index
eth_getTransactionByBlockHashAndIndexcast rpc eth_getTransactionByBlockHashAndIndex ...Tx by block hash and index
eth_feeHistorycast rpc eth_feeHistory ...Historical gas fees, for EIP-1559 analysis
eth_maxPriorityFeePerGascast rpc eth_maxPriorityFeePerGasSuggested max priority fee per gas
eth_syncingcast rpc eth_syncingWhether the node is syncing
eth_miningcast rpc eth_miningWhether the node reports mining
eth_hashratecast rpc eth_hashrateReported mining hash rate
net_versioncast rpc net_versionNetwork ID
net_peerCountcast rpc net_peerCountNumber of connected peers
net_listeningcast rpc net_listeningWhether the node listens for connections
rpc_modulescast rpc rpc_modulesRPC modules the node supports

cast rpc <method> [params] sends any raw JSON-RPC method. Use it when cast has no dedicated command.

Connecting Anvil to MetaMaskSearch on YouTube

Step 1. Add the network. In MetaMask: menu → Networks → Add a custom network:

FieldValue
Network nameAnvil Local
Default RPC URLhttp://127.0.0.1:8545
Chain ID31337
Currency symbolETH

MetaMask may warn that the name does not match its records for chain 31337 (it suggests "GoChain Testnet"). Ignore it and Save. "Anvil Local" now shows under Custom networks.

Step 2. Import Anvil accounts #0 and #1. Accounts → Add wallet → Import an account → paste the private key.

#AddressPrivate key
00xf39Fd6e51aad88F6F4ce6aB8827279cffFb922660xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
10x70997970C51812dc3A010C7d01b50e0d17dc79C80x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d

The imported account shows 10,000 ETH on Anvil Local. The top balance reads $0.00 because this ETH has no fiat value.

Step 3. Send 10 ETH from #0 to #1. Select Account #0 → Send → choose network Anvil Local and asset Ethereum → To: Account #1 → Amount 10 → Continue. The review shows Network Anvil Local, a network fee under 0.0001 ETH and Nonce 0. Confirm.

BeforeAfter
Account #010,000 ETH9,990 ETH
Account #110,000 ETH10,010 ETH

(Account #0 also pays a tiny gas fee.) Activity shows "Sent ETH to Account #1, −10 ETH".

Step 4. Inspect with cast.

cast tx 0xab6bea4c9c2450c3bd34a5ea4d5ebba4685fbc367e6813bc59fa061679872fd5 --rpc-url http://127.0.0.1:8545
cast nonce 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266                       # now 1
cast receipt 0xab6bea4c9c2450c3bd34a5ea4d5ebba4685fbc367e6813bc59fa061679872fd5 --rpc-url http://127.0.0.1:8545
cast block 1 --rpc-url http://127.0.0.1:8545                                # the block that holds the tx

An EOA has an address, a balance and a nonce. A contract account has an address, a balance, code and storage.

Other Foundry commandsSearch on YouTube

The decks describe forge and chisel but run only anvil and cast. These standard commands round out the toolkit:

forge init myproject            # new project: src/, test/, script/, foundry.toml
forge build                     # compile contracts in src/
forge test                      # run Solidity tests in test/
forge create src/Counter.sol:Counter --rpc-url http://127.0.0.1:8545 \
     --private-key <anvil-key> --broadcast   # deploy a contract
chisel                          # open the Solidity REPL (!help for commands, !quit to exit)
cast send 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 --value 1ether \
     --private-key <anvil-key> --rpc-url http://127.0.0.1:8545
cast to-dec 0xaa36a7            # 11155111 (hex to decimal)
cast from-wei 10000000000000000000000   # 10000 (wei to ether)

What to do and check in the lab:

  1. wsl --install -d Ubuntu, create the Linux user, sudo apt update, install curl git build-essential.
  2. Run the foundryup installer, fix PATH, run foundryup, check anvil --version.
  3. Start anvil; note 10 accounts with 10,000 ETH, chain ID 31337, block 0, port 8545.
  4. In a second terminal fix PATH in ~/.bashrc; run cast balance, cast chain-id, cast block-number, cast block latest.
  5. Add "Anvil Local" to MetaMask, import accounts #0 and #1, send 10 ETH.
  6. Check the tx with cast tx, cast receipt, cast nonce (now 1) and cast block 1.

Quick self-testSearch on YouTube

Why develop on a local testnet instead of mainnet?

Mainnet needs real ETH and gas, its state changes are irreversible, it has network latency, and it exposes experimental or vulnerable code. A local chain is free, instant and resettable.

Name the four Foundry tools and the role of each.

Forge builds, tests and deploys contracts. Cast is the CLI to interact with EVM chains. Anvil runs a local Ethereum node. Chisel is a Solidity REPL.

Viva: how does Forge differ from Hardhat or Truffle?

Foundry is written in Rust, and Forge tests are written in Solidity. Hardhat and Truffle run on Node.js with tests in JavaScript or TypeScript.

What does curl -L https://foundry.paradigm.xyz | bash install?

Only foundryup, Foundry's version manager and installer. You then run foundryup to install forge, cast, anvil, chisel and solar.

What do you get when you run anvil?

A local chain at block 0 with chain ID 31337, JSON-RPC on 127.0.0.1:8545, and 10 pre-funded accounts (10,000 ETH each) with known private keys.

Viva: why must Anvil's private keys never be used on mainnet?

They come from a public, well-known mnemonic. Anyone can derive them, so any real funds sent to those addresses would be stolen.

cast balance returns 10000000000000000000000. How much ETH is that?

10,000 ETH, because 1 ETH=10181\ \text{ETH} = 10^{18} wei and the value is 102210^{22} wei.

Why did cast fail in the second terminal, and how was it fixed?

export PATH only affected the first terminal. Appending the export line to ~/.bashrc and running source ~/.bashrc makes it permanent.

Give the cast equivalents of eth_getTransactionCount, eth_getCode and eth_getTransactionReceipt.

cast nonce <address>, cast code <address> and cast receipt <tx-hash>.

What MetaMask settings connect to Anvil?

Network name Anvil Local, RPC URL http://127.0.0.1:8545, chain ID 31337, currency symbol ETH.

  • Local testnets avoid real ETH, gas, irreversible state, latency and public exposure during development.
  • Foundry (Rust) has forge (build/test/deploy), cast (CLI to EVM chains), anvil (local node) and chisel (Solidity REPL).
  • Install: Ubuntu WSL, apt install curl git build-essential, curl -L https://foundry.paradigm.xyz | bash, fix PATH, foundryup.
  • anvil starts chain ID 31337 at block 0 on 127.0.0.1:8545 with 10 accounts of 10,000 ETH and public dev keys.
  • Cast sends JSON-RPC for you: cast balance, chain-id, block-number, block, nonce, code, tx, receipt, rpc <method>.
  • Connect MetaMask with a custom network, import accounts by private key, and send ETH; the nonce goes from 0 to 1.
  • EOA = address + balance + nonce; contract account = address + balance + code + storage.