foundry-solidity

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Foundry Solidity Development

Foundry Solidity 智能合约开发

Complete guide for building secure, efficient smart contracts with Foundry 1.5.0 and Solidity 0.8.30.
这是一份使用Foundry 1.5.0Solidity 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
  • 开发以太坊/EVM智能合约
  • 编写Forge测试(单元测试、模糊测试、不变量测试、分叉测试)
  • 通过脚本部署合约
  • 使用Foundry工具(forge、cast、anvil、chisel)
  • 处理
    foundry.toml
    *.t.sol
    *.s.sol
    文件
  • 调试交易和合约交互

Quick Start

快速开始

bash
undefined
bash
undefined

Create new project

Create new project

forge init my-project && cd my-project
forge init my-project && cd my-project

Build contracts

Build contracts

forge build
forge build

Run tests

Run tests

forge test
forge test

Deploy (dry-run)

Deploy (dry-run)

forge script script/Deploy.s.sol --rpc-url sepolia
forge script script/Deploy.s.sol --rpc-url sepolia

Deploy (broadcast)

Deploy (broadcast)

forge script script/Deploy.s.sol --rpc-url sepolia --broadcast --verify
undefined
forge script script/Deploy.s.sol --rpc-url sepolia --broadcast --verify
undefined

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/
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

构建与测试

bash
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
bash
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

部署

bash
undefined
bash
undefined

Single contract

Single contract

forge create src/Token.sol:Token --rpc-url sepolia --private-key $KEY --broadcast
forge create src/Token.sol:Token --rpc-url sepolia --private-key $KEY --broadcast

Script deployment (recommended)

Script deployment (recommended)

forge script script/Deploy.s.sol:Deploy --rpc-url sepolia --broadcast --verify
forge script script/Deploy.s.sol:Deploy --rpc-url sepolia --broadcast --verify

Verify existing contract

Verify existing contract

forge verify-contract $ADDRESS src/Token.sol:Token --chain sepolia
undefined
forge verify-contract $ADDRESS src/Token.sol:Token --chain sepolia
undefined

Cast - Blockchain Interactions

Cast - 区块链交互

bash
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
bash
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 - 本地节点

bash
anvil                           # Start local node
anvil --fork-url $RPC_URL       # Fork mainnet
anvil --fork-block-number 18000000
bash
anvil                           # Start local node
anvil --fork-url $RPC_URL       # Fork mainnet
anvil --fork-block-number 18000000

Basic Test Contract

基础测试合约

solidity
// 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);
    }
}
solidity
// 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

核心 Cheatcode

solidity
// 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
solidity
// 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

部署脚本

solidity
// 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));
    }
}
solidity
// 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)

现代Solidity模式(0.8.30版本)

solidity
// 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));
solidity
// 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)

配置(foundry.toml)

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
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
如需详细指南,请参阅:
  • 测试:详见
    references/testing.md
    ,包含完整的测试模式(单元、模糊、不变量、分叉测试)、所有cheatcode及最佳实践
  • forge-std API:详见
    references/forge-std-api.md
    ,包含完整的库参考(150+个函数)
  • Solidity 0.8.30:详见
    references/solidity-modern.md
    ,包含新特性和现代语法
  • 部署:详见
    references/deployment.md
    ,包含脚本编写、验证及多链部署内容
  • 配置:详见
    references/configuration.md
    ,包含foundry.toml的所有配置选项
  • Gas优化:详见
    references/gas-optimization.md
    ,包含存储打包、编译器设置及性能分析内容
  • 设计模式:详见
    references/patterns.md
    ,包含访问控制、重入防护、工厂模式及常见设计范式
  • 安全:详见
    references/security.md
    ,包含漏洞、防御模式及审计准备内容
  • 资源:详见
    references/resources.md
    ,包含官方文档、库、安全工具及学习路径
  • 调试:详见
    references/debugging.md
    ,包含追踪、断点、console.log及交互式调试器使用方法
  • 依赖管理:详见
    references/dependencies.md
    ,包含forge install、重映射及Soldeer包管理器使用方法
  • CI/CD:详见
    references/cicd.md
    ,包含GitHub Actions工作流、缓存及Gas追踪内容
  • Chisel:详见
    references/chisel.md
    ,包含交互式Solidity REPL使用方法
  • Cast进阶:详见
    references/cast-advanced.md
    ,包含解码、编码、钱包管理及批量操作内容
  • Anvil进阶:详见
    references/anvil-advanced.md
    ,包含地址 impersonation、状态操纵及挖矿模式内容