🧱 Solidity 合约开发全流程(Foundry 版)
✅ 适合对象:已经能写合约但不清楚如何测试、部署、交互的开发者
✅ 工具链:Foundry(forge, anvil, cast)
📌 开发流程总览
1️⃣ 初始化项目
2️⃣ 编写合约
3️⃣ 编译合约
4️⃣ 编写测试文件
5️⃣ 运行测试
6️⃣ 编写部署脚本
7️⃣ 在本地链部署
8️⃣ 部署到测试网(如 Sepolia)
9️⃣ 编写交互脚本
1️⃣ 初始化 Foundry 项目
forge init my-foundry-project
cd my-foundry-project
结构自动生成:
my-foundry-project/
├── src/ # 合约代码
│ └── MyContract.sol
├── script/ # 部署脚本
│ └── DeployMyContract.s.sol
├── test/ # 测试文件
│ └── MyContract.t.sol
├── foundry.toml # 配置文件
└── lib/ # 依赖
2️⃣ 编写合约(src/ 目录)
src/SimpleStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;contract SimpleStorage {uint256 private favoriteNumber;function store(uint256 _number) public {favoriteNumber = _number;}function retrieve() public view returns (uint256) {return favoriteNumber;}
}
3️⃣ 编译合约
forge build # 推荐
# 或者
forge compile
输出生成在 /out 和 /artifacts 中。
4️⃣ 编写测试文件(test/)
test/SimpleStorage.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;import "forge-std/Test.sol";
import "../src/SimpleStorage.sol";contract SimpleStorageTest is Test {SimpleStorage public simpleStorage;function setUp() public {simpleStorage = new SimpleStorage();}function testStoreAndRetrieve() public {simpleStorage.store(42);uint256 value = simpleStorage.retrieve();assertEq(value, 42);}
}
5️⃣ 运行测试
forge test
可加参数:
forge test -vvv # 输出更详细日志(v越多越详细)
6️⃣ 编写部署脚本(script/)
script/DeploySimpleStorage.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;import "../src/SimpleStorage.sol";
import "forge-std/Script.sol";contract DeploySimpleStorage is Script {function run() external returns (SimpleStorage) {vm.startBroadcast();SimpleStorage deployed = new SimpleStorage();vm.stopBroadcast();return deployed;}
}
7️⃣ 部署到本地链(Anvil)
启动本地链:
anvil
新窗口运行部署脚本:
forge script script/DeploySimpleStorage.s.sol:DeploySimpleStorage \--rpc-url http://127.0.0.1:8545 \--broadcast
8️⃣ 部署到测试网(Sepolia)
先获取测试 ETH:
🛠 Faucet: https://cloud.google.com/application/web3/faucet/ethereum/sepolia
准备
.env
文件:
.env(不要上传 GitHub)
PRIVATE_KEY=你的私钥(0x开头)
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/你的API密钥
执行部署脚本:
source .envforge script script/DeploySimpleStorage.s.sol:DeploySimpleStorage \--rpc-url $SEPOLIA_RPC_URL \--private-key $PRIVATE_KEY \--broadcast \--verify # 如果配置了 Etherscan 验证
9️⃣ 编写交互脚本(如调用函数)
script/InteractSimpleStorage.s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;import "../src/SimpleStorage.sol";
import "forge-std/Script.sol";contract InteractSimpleStorage is Script {function run() external {address contractAddr = vm.envAddress("CONTRACT_ADDRESS");vm.startBroadcast();SimpleStorage instance = SimpleStorage(contractAddr);instance.store(777);vm.stopBroadcast();}
}
执行:
CONTRACT_ADDRESS=0xabc... forge script script/InteractSimpleStorage.s.sol:InteractSimpleStorage \--rpc-url $SEPOLIA_RPC_URL \--private-key $PRIVATE_KEY \--broadcast
📦 常用命令汇总
操作 | 命令 |
---|---|
初始化项目 | forge init |
编译 | forge build 或 forge compile |
测试 | forge test -vvv |
启动本地链 | anvil |
部署本地 | forge script ... --rpc-url http://127.0.0.1:8545 --broadcast |
部署测试网 | forge script ... --rpc-url $RPC --private-key $PK --broadcast |
调用合约 | cast send / 编写交互脚本 |
查看 ABI | cast interface |
🧪 标准测试方法模板
function testXXXX() public {// Arrange(准备测试环境)...// Act(调用函数)...// Assert(断言检查)...
}
✅ 总结建议
阶段 | 建议工具 | 重点 |
---|---|---|
写合约 | VSCode + Hardhat 插件 | 注释清晰,分层设计 |
测试 | forge-std/Test.sol | 覆盖所有函数逻辑、边界条件 |
部署 | .s.sol + broadcast | 本地验证 OK 再上测试网 |
交互 | cast or 脚本 | 统一管理地址、密钥、网络 |