Foundry Solidity Development Complete guide for building secure, efficient smart contracts with Foundry 1.5.0 and Solidity 0.8.30 . When to Use This Skill Developing Ethereum/EVM smart contracts Writing Forge tests (unit, fuzz, invariant, fork) Deploying contracts with scripts Using Foundry tools (forge, cast, anvil, chisel) Working with foundry.toml , .t.sol , .s.sol files Debugging transactions and contract interactions Quick Start
Create new project
forge init my-project && cd my-project
Build contracts
forge build
Run tests
forge test
Deploy (dry-run)
forge script script/Deploy.s.sol --rpc-url sepolia
Deploy (broadcast)
forge script script/Deploy.s.sol --rpc-url sepolia --broadcast --verify Project Structure my-project/ ├── foundry.toml # Configuration ├── src/ # Contracts │ └── Counter.sol ├── test/ # Tests (.t.sol) │ └── Counter.t.sol ├── script/ # Deploy scripts (.s.sol) │ └── Deploy.s.sol └── lib/ # Dependencies └── forge-std/ Core Commands Build & Test forge build
Compile
forge test
Run all tests
forge test -vvvv
With traces
forge test --match-test testDeposit
Filter by test name
forge test --match-contract Vault
Filter by contract
forge test --fork-url $RPC_URL
Fork testing
forge test --gas-report
Gas usage report
Deployment
Single contract
forge create src/Token.sol:Token --rpc-url sepolia --private-key $KEY --broadcast
Script deployment (recommended)
forge script script/Deploy.s.sol:Deploy --rpc-url sepolia --broadcast --verify
Verify existing contract
forge verify-contract $ADDRESS src/Token.sol:Token --chain sepolia Cast - Blockchain Interactions cast call $CONTRACT "balanceOf(address)" $USER --rpc-url mainnet cast send $CONTRACT "transfer(address,uint256)" $TO $AMOUNT --private-key $KEY cast decode-tx $TX_HASH cast storage $CONTRACT 0 --rpc-url mainnet Anvil - Local Node anvil
Start local node
anvil --fork-url $RPC_URL
Fork mainnet
- anvil --fork-block-number
- 18000000
- Basic Test Contract
- // SPDX-License-Identifier: MIT
- pragma
- solidity
- ^
- 0.8.30
- ;
- import
- {
- Test
- ,
- console
- }
- from
- "forge-std/Test.sol"
- ;
- import
- {
- Counter
- }
- from
- "../src/Counter.sol"
- ;
- contract
- CounterTest
- is
- Test
- {
- Counter
- public
- counter
- ;
- address
- public
- user
- ;
- function
- setUp
- (
- )
- public
- {
- counter
- =
- new
- Counter
- (
- )
- ;
- user
- =
- makeAddr
- (
- "user"
- )
- ;
- deal
- (
- user
- ,
- 10
- ether
- )
- ;
- }
- function
- test_Increment
- (
- )
- public
- {
- counter
- .
- increment
- (
- )
- ;
- assertEq
- (
- counter
- .
- number
- (
- )
- ,
- 1
- )
- ;
- }
- function
- test_RevertWhen_Unauthorized
- (
- )
- public
- {
- vm
- .
- expectRevert
- (
- "Unauthorized"
- )
- ;
- vm
- .
- prank
- (
- user
- )
- ;
- counter
- .
- adminFunction
- (
- )
- ;
- }
- function
- testFuzz_SetNumber
- (
- uint256
- x
- )
- public
- {
- x
- =
- bound
- (
- x
- ,
- 0
- ,
- 1000
- )
- ;
- counter
- .
- setNumber
- (
- x
- )
- ;
- assertEq
- (
- counter
- .
- number
- (
- )
- ,
- x
- )
- ;
- }
- }
- Essential Cheatcodes
- // Identity & ETH
- address
- alice
- =
- makeAddr
- (
- "alice"
- )
- ;
- // Create labeled address
- deal
- (
- alice
- ,
- 10
- ether
- )
- ;
- // Give ETH
- deal
- (
- address
- (
- token
- )
- ,
- alice
- ,
- 1000e18
- )
- ;
- // Give ERC20
- // Impersonation
- vm
- .
- prank
- (
- alice
- )
- ;
- // Next call as alice
- vm
- .
- startPrank
- (
- alice
- )
- ;
- // All calls as alice
- vm
- .
- stopPrank
- (
- )
- ;
- // Time & Block
- vm
- .
- warp
- (
- block
- .
- timestamp
- +
- 1
- days
- )
- ;
- // Set timestamp
- vm
- .
- roll
- (
- block
- .
- number
- +
- 100
- )
- ;
- // Set block number
- // Assertions
- vm
- .
- expectRevert
- (
- "Error message"
- )
- ;
- // Expect revert
- vm
- .
- expectRevert
- (
- CustomError
- .
- selector
- )
- ;
- // Custom error
- vm
- .
- expectEmit
- (
- true
- ,
- true
- ,
- false
- ,
- true
- )
- ;
- // Expect event
- emit
- Transfer
- (
- from
- ,
- to
- ,
- amount
- )
- ;
- // Must match next emit
- // Storage
- vm
- .
- store
- (
- addr
- ,
- slot
- ,
- value
- )
- ;
- // Write storage
- vm
- .
- load
- (
- addr
- ,
- slot
- )
- ;
- // Read storage
- Deploy Script
- // SPDX-License-Identifier: MIT
- pragma
- solidity
- ^
- 0.8.30
- ;
- import
- {
- Script
- ,
- console
- }
- from
- "forge-std/Script.sol"
- ;
- import
- {
- Counter
- }
- from
- "../src/Counter.sol"
- ;
- contract
- Deploy
- is
- Script
- {
- function
- run
- (
- )
- external
- {
- uint256
- deployerKey
- =
- vm
- .
- envUint
- (
- "PRIVATE_KEY"
- )
- ;
- vm
- .
- startBroadcast
- (
- deployerKey
- )
- ;
- Counter counter
- =
- new
- Counter
- (
- )
- ;
- counter
- .
- setNumber
- (
- 42
- )
- ;
- vm
- .
- stopBroadcast
- (
- )
- ;
- console
- .
- log
- (
- "Deployed to:"
- ,
- address
- (
- counter
- )
- )
- ;
- }
- }
- Modern Solidity Patterns (0.8.30)
- // Custom errors (gas efficient)
- error
- InsufficientBalance
- (
- uint256
- available
- ,
- uint256
- required
- )
- ;
- // Transient storage (0.8.28+) - cheap reentrancy guard
- bool
- transient locked
- ;
- modifier
- nonReentrant
- (
- )
- {
- require
- (
- !
- locked
- ,
- "Reentrancy"
- )
- ;
- locked
- =
- true
- ;
- _
- ;
- locked
- =
- false
- ;
- }
- // Immutable variables (cheap reads)
- address
- public
- immutable owner
- ;
- // Named mapping parameters
- mapping
- (
- address
- user
- =>
- uint256
- balance
- )
- public
- balances
- ;
- // require with custom error (0.8.26+)
- require
- (
- amount
- <=
- balance
- ,
- InsufficientBalance
- (
- balance
- ,
- amount
- )
- )
- ;
- Configuration (foundry.toml)
- [
- profile.default
- ]
- src
- =
- "src"
- out
- =
- "out"
- libs
- =
- [
- "lib"
- ]
- solc
- =
- "0.8.30"
- optimizer
- =
- true
- optimizer_runs
- =
- 200
- evm_version
- =
- "prague"
- fuzz.runs
- =
- 256
- invariant.runs
- =
- 256
- invariant.depth
- =
- 50
- [
- rpc_endpoints
- ]
- mainnet
- =
- "${MAINNET_RPC_URL}"
- sepolia
- =
- "${SEPOLIA_RPC_URL}"
- [
- etherscan
- ]
- mainnet
- =
- {
- key
- =
- "${ETHERSCAN_API_KEY}"
- }
- sepolia
- =
- {
- key
- =
- "${ETHERSCAN_API_KEY}"
- }
- [
- profile.ci
- ]
- fuzz.runs
- =
- 10000
- invariant.runs
- =
- 1000
- References
- For detailed guides, see:
- Testing
-
- See
- references/testing.md
- for complete testing patterns (unit, fuzz, invariant, fork), all cheatcodes, and best practices
- forge-std API
-
- See
- references/forge-std-api.md
- for complete library reference (150+ functions)
- Solidity 0.8.30
-
- See
- references/solidity-modern.md
- for new features and modern syntax
- Deployment
-
- See
- references/deployment.md
- for scripting, verification, and multi-chain deployment
- Configuration
-
- See
- references/configuration.md
- for all foundry.toml options
- Gas Optimization
-
- See
- references/gas-optimization.md
- for storage packing, compiler settings, and profiling
- Patterns
-
- See
- references/patterns.md
- for access control, reentrancy guards, factories, and common idioms
- Security
-
- See
- references/security.md
- for vulnerabilities, defensive patterns, and audit preparation
- Resources
-
- See
- references/resources.md
- for official docs, libraries, security tools, and learning paths
- Debugging
-
- See
- references/debugging.md
- for traces, breakpoints, console.log, and the interactive debugger
- Dependencies
-
- See
- references/dependencies.md
- for forge install, remappings, and Soldeer package manager
- CI/CD
-
- See
- references/cicd.md
- for GitHub Actions workflows, caching, and gas tracking
- Chisel
-
- See
- references/chisel.md
- for the interactive Solidity REPL
- Cast Advanced
-
- See
- references/cast-advanced.md
- for decoding, encoding, wallet management, and batch operations
- Anvil Advanced
- See references/anvil-advanced.md for impersonation, state manipulation, and mining modes