Foundry
Introduction
Section titled “Introduction”Foundry is a blazing fast, portable, and modular toolkit for Ethereum application development written in Rust. It consists of:
- Forge: Command-line tool to test, build, and deploy smart contracts
- Cast: Swiss army knife for interacting with contracts, sending transactions, and getting chain data
- Anvil: Local Ethereum node for development and testing
- Chisel: Solidity REPL for testing code snippets
This page demonstrates how to set up Foundry to work with Polkadot Hub, including installation, compilation, deployment, and verification.
Prerequisites
Section titled “Prerequisites”Before setting up Foundry, make sure you have:
- A Unix-based operating system (Linux or macOS) or Windows with WSL
- Git installed
- A funded account on Polkadot Hub (see the Connect to Polkadot guide to get TestNet tokens)
Install Foundry
Section titled “Install Foundry”To install the Foundry nightly build, run:
curl -L https://foundry.paradigm.xyz | bashThis installs foundryup, the Foundry toolchain installer. Then, run:
foundryup --version nightlyThis installs the latest nightly versions of forge, cast, anvil, and chisel.
To verify the installation:
forge Version: 1.6.0-nightly Commit SHA: 8b4f318e6a3e83a06dc4e989b9aba87894dca88e Build Timestamp: 2026-01-28T06:06:35.086737000Z (1769580395) Build Profile: dist
Initialize a Foundry Project
Section titled “Initialize a Foundry Project”Create a new Foundry project:
forge init my-foundry-projectcd my-foundry-projectThis creates a new directory with the following structure:
src/: Contains your Solidity smart contractsscript/: Holds deployment scriptstest/: Contains test files written in Soliditylib/: Stores project dependenciesfoundry.toml: Configuration file for Foundry settings
A sample Counter.sol contract will be created in the src/ directory along with a corresponding test file.
Compile Contracts
Section titled “Compile Contracts”To compile your contracts, run:
forge buildYou should see output similar to:
[⠊] Compiling... [⠒] Compiling 3 files with Solc 0.8.28 [⠢] Solc 0.8.28 finished in 1.23s Compiler run successful!
Forge compiles all contracts in the src/ directory and outputs the artifacts to the out/ directory.
Configure Foundry for Polkadot Hub
Section titled “Configure Foundry for Polkadot Hub”Foundry's nightly build includes native support for Polkadot chains with polkadot-testnet, polkadot, and kusama as recognized chains with default RPC endpoints.
Create or modify your foundry.toml file:
[profile.default]src = "src"out = "out"libs = ["lib"]solc_version = "0.8.28"
[etherscan] # Contract verification configurationpolkadot-testnet = { key = "", url = "https://blockscout-testnet.polkadot.io/api?" }[profile.default]src = "src"out = "out"libs = ["lib"]solc_version = "0.8.28"
[etherscan] # Contract verification configurationpolkadot-testnet = { key = "verifyContract", url = "https://api.routescan.io/v2/network/testnet/evm/420420417/etherscan" }With this configuration, you can use --chain polkadot-testnet in your commands without specifying the RPC URL explicitly.
Available Networks and RPC Endpoints
Section titled “Available Networks and RPC Endpoints”Foundry's nightly build supports three Polkadot chains:
| Network | Chain Flag | Built-in RPC Endpoint | Chain ID |
|---|---|---|---|
| Polkadot TestNet | --chain polkadot-testnet | https://eth-rpc-testnet.polkadot.io | 420420417 |
| Polkadot | --chain polkadot | https://eth-rpc.polkadot.io | 420420419 |
| Kusama | --chain kusama | https://kusama-asset-hub-eth-rpc.polkadot.io | 420420418 |
Deploy a Contract
Section titled “Deploy a Contract”Set Up Environment Variables
Section titled “Set Up Environment Variables”Create a .env file in your project root (make sure to add it to .gitignore):
PRIVATE_KEY=INSERT_PRIVATE_KEY_HERELoad the environment variables:
source .envDeploy Using Forge
Section titled “Deploy Using Forge”To deploy a contract to Polkadot Hub TestNet:
forge create src/Counter.sol:Counter \ --chain polkadot-testnet \ --rpc-url https://eth-rpc-testnet.polkadot.io \ --private-key $PRIVATE_KEY \ --broadcastYou'll see output with the deployed contract address:
--chain polkadot-testnet --rpc-url https://eth-rpc-testnet.polkadot.io --private-key $PRIVATE_KEY --broadcast [⠊] Compiling... No files changed, compilation skipped Deployer: 0x3427D90f1Ee5c5D3627c2EBb37f90393526066fd Deployed to: 0xF1fbAf96A16458A512A33b31c4414C4a81f50EF4 Transaction hash: 0x1cba7b61c771192b297024766bed8b6e607f218e12899739fe61a3eed2690779
Deploy Using Scripts
Section titled “Deploy Using Scripts”For more complex deployments, create a deployment script in the script/ directory:
// SPDX-License-Identifier: MITpragma solidity ^0.8.28;
import {Script} from "forge-std/Script.sol";import {Counter} from "../src/Counter.sol";
contract CounterScript is Script { function run() external { // Get the deployer's private key from environment uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
// Start broadcasting transactions vm.startBroadcast(deployerPrivateKey);
// Deploy the contract Counter counter = new Counter();
// Stop broadcasting vm.stopBroadcast(); }}Run the deployment script:
forge script script/Counter.s.sol:CounterScript \ --chain polkadot-testnet \ --broadcastThe --broadcast flag tells Forge to submit the transactions to the network.
Verify a Contract
Section titled “Verify a Contract”To verify your deployed contract on Polkadot Hub, use the verification feature with the Polkadot Hub explorer verifier.
Basic Verification
Section titled “Basic Verification”forge verify-contract INSERT_CONTRACT_ADDRESS \ src/Counter.sol:Counter \ --chain polkadot-testnetBlockscout does not require an API key. With Foundry's native Polkadot support, --verifier and --verifier-url are not needed.
You should see output similar to:
--chain polkadot-testnet Start verifying contract
0xc29C4ebCdd1c49bc77362A13Ab921f22005828A0 deployed on polkadot-testnet
Submitting verification for [src/Counter.sol:Counter] 0xc29C4ebCdd1c49bc77362A13Ab921f22005828A0.
Submitted contract for verification:
Response: OK
GUID: c29c4ebcdd1c49bc77362a13ab921f22005828a0698f2622
URL: https://blockscout-testnet.polkadot.io/address/0xc29c4ebcdd1c49bc77362a13ab921f22005828a0
forge verify-contract INSERT_CONTRACT_ADDRESS \ src/Counter.sol:Counter \ --verifier-url 'https://api.routescan.io/v2/network/testnet/evm/420420417/etherscan' \ --etherscan-api-key "verifyContract" \ --chain polkadot-testnetThe Routescan API v2 structure is https://api.routescan.io/v2/network/{testnet|mainnet}/evm/{CHAIN_ID}/etherscan. The --verifier-url is the URL of the Polkadot Hub explorer verifier.
You should see output similar to:
--verifier-url 'https://api.routescan.io/v2/network/testnet/evm/420420417/etherscan' --etherscan-api-key "verifyContract" --chain polkadot-testnet Start verifying contract
0xF1fbAf96A16458A512A33b31c4414C4a81f50EF4 deployed on polkadot-testnet
Submitting verification for [src/Counter.sol:Counter] 0xF1fbAf96A16458A512A33b31c4414C4a81f50EF4.
Submitted contract for verification:
Response: OK
GUID: 71d14e5b-eda1-5e85-98c5-2faf93306526
URL: https://polkadot.testnet.routescan.io/address/0xf1fbaf96a16458a512a33b31c4414c4a81f50ef4
Replace INSERT_CONTRACT_ADDRESS with your deployed contract's address.
Verification with Constructor Arguments
Section titled “Verification with Constructor Arguments”For contracts with constructor arguments:
forge verify-contract INSERT_CONTRACT_ADDRESS \ src/Counter.sol:Counter \ --chain polkadot-testnet \ --constructor-args $(cast abi-encode "constructor(uint256,address)" 42 INSERT_DEPLOYER_ADDRESS)forge verify-contract INSERT_CONTRACT_ADDRESS \ src/Counter.sol:Counter \ --verifier-url 'https://api.routescan.io/v2/network/testnet/evm/420420417/etherscan' \ --etherscan-api-key "verifyContract" \ --chain polkadot-testnet \ --constructor-args $(cast abi-encode "constructor(uint256,address)" 42 INSERT_DEPLOYER_ADDRESS)Replace INSERT_CONTRACT_ADDRESS with your deployed contract's address.
Interact with Contracts
Section titled “Interact with Contracts”Using Cast
Section titled “Using Cast”Cast is a powerful command-line tool for interacting with deployed contracts.
Read from a Contract
Section titled “Read from a Contract”cast call INSERT_CONTRACT_ADDRESS "number()(uint256)" \ --chain polkadot-testnetWrite to a Contract
Section titled “Write to a Contract”cast send INSERT_CONTRACT_ADDRESS "setNumber(uint256)" 42 \ --chain polkadot-testnet \ --private-key $PRIVATE_KEYGet Account Balance
Section titled “Get Account Balance”cast balance INSERT_ACCOUNT_ADDRESS --chain polkadot-testnetUsing Forge Scripts
Section titled “Using Forge Scripts”For more complex interactions, create scripts in the script/ directory that can read and write contract state programmatically.
Run Tests
Section titled “Run Tests”Foundry uses Solidity for writing tests, allowing you to test your contracts in the same language they're written in:
forge testFor verbose output showing gas usage and detailed logs:
forge test -vvvRun specific tests:
forge test --match-test testIncrementRun tests with gas reporting:
forge test --gas-reportAdditional Resources
Section titled “Additional Resources”- Foundry Documentation: Comprehensive Foundry documentation
- Forge Documentation: Detailed guide to the Forge tool
- Cast Documentation: Learn about Cast commands
- Foundry GitHub: Source code and issue tracker
Where to Go Next
Section titled “Where to Go Next”-
Connect to Polkadot Hub
View network details and learn how to connect your development tools to Polkadot Hub.
-
For Ethereum Developers
Learn how smart contracts work on Polkadot Hub.