🧱 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 腳本 | 統一管理地址、密鑰、網絡 |