以太坊開發工具完整指南
從開發環境搭建到部署上線,系統介紹 Hardhat、Foundry、調試工具、測試框架等實務內容。
以太坊開發工具完整指南:從環境搭建到部署上線
概述
以太坊智慧合約開發是一個涉及多個工具和流程的複雜工程。從本地開發環境的搭建、智慧合約的編寫和調試、自動化測試的執行、到最終的部署上線,每個環節都有專門的工具支援。本文系統性地介紹以太坊開發的工具生態系,涵蓋開發環境、調試工具、測試框架、部署流程等實務內容,幫助開發者建立完整的開發工作流。
本文適合已經掌握程式設計基礎、對區塊鏈有基本了解的開發者。無論你是從傳統軟體開發轉型而來,還是 Web2 開發者想要擴展到 Web3,這篇文章都會幫助你快速上手以太坊開發。
開發環境搭建
開發環境的選擇
以太坊智慧合約主要使用 Solidity 語言編寫,這是一種類似 JavaScript 的高階語言,專為智慧合約設計。開發 Solidity 合約需要以下基礎設施:
Node.js 環境:以太坊開發工具大多基於 Node.js構建。安裝 Node.js 的推薦方式是使用 nvm(Node Version Manager),因為不同專案可能需要不同版本的 Node.js。
# 安裝 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
# 安裝 Node.js LTS 版本
nvm install --lts
nvm use --lts
# 驗證安裝
node --version # 應該顯示 v18.x.x 或更高
npm --version
Git:版本控制是現代軟體開發的必備工具。
# Ubuntu/Debian
sudo apt install git
# macOS
brew install git
# 驗證
git --version
程式碼編輯器配置
Visual Studio Code(VS Code)是以太坊開發最受歡迎的編輯器。建議安裝以下擴展:
Solidity 擴展:
- Solidity by Juan Blanco:提供語法高亮、編譯、調試功能
- Hardhat Solidity:提供 Hardhat 專案的智能提示
輔助擴展:
- Prettier:代碼格式化
- ESLint:代碼品質檢查
- GitLens:Git 視覺化
VS Code 配置示例(settings.json):
{
"solidity.compileUsingRemoteVersion": "v0.8.20",
"solidity.defaultCompiler": "remote",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"prettier.requireConfig": true
}
Hardhat 開發框架
Hardhat 是目前最主流的以太坊開發框架,提供本地測試網、編譯、調試、部署等功能。
安裝 Hardhat:
# 建立專案目錄
mkdir my-eth-project
cd my-eth-project
# 初始化 npm 專案
npm init -y
# 安裝 Hardhat
npm install --save-dev hardhat
# 初始化 Hardhat 配置
npx hardhat init
選擇「Create a JavaScript project」或「Create a TypeScript project」,Hardhat 會自動生成專案結構:
my-eth-project/
├── contracts/ # 智慧合約原始碼
│ └── Lock.sol
├── scripts/ # 部署腳本
│ └── deploy.js
├── test/ # 測試檔案
│ └── Lock.js
├── hardhat.config.js # Hardhat 配置
└── package.json
Hardhat 配置詳解(hardhat.config.js):
require("@nomicfoundation/hardhat-toolbox");
require("@nomiclabs/hardhat-ethers");
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: {
version: "0.8.20",
settings: {
optimizer: {
enabled: true,
runs: 200
}
}
},
networks: {
hardhat: {
chainId: 31337
},
localhost: {
url: "http://127.0.0.1:8545"
},
sepolia: {
url: process.env.SEPOLIA_RPC_URL,
accounts: [process.env.PRIVATE_KEY]
}
},
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
}
};
本地測試網絡
Hardhat 內建了一個本地 Ethereum 網絡稱為 Hardhat Network。這是一個內存中的測試網絡,啟動速度快,每次重啟都是全新的乾淨狀態。
啟動本地網絡:
npx hardhat node
這會啟動一個本地節點,預設監聽 http://localhost:8545,並生成 20 個測試帳戶,每個帳戶有 10000 ETH 的測試資金。
連接到本地網絡:
在 JavaScript/TypeScript 中使用 ethers.js 連接:
const { ethers } = require("hardhat");
async function main() {
// 連接到本地節點
const provider = new ethers.JsonRpcProvider("http://localhost:8545");
// 獲取帳戶列表(Hardhat node 啟動時會顯示)
const [signer] = await ethers.getSigners();
console.log("Connected account:", signer.address);
// 餘額查詢
const balance = await provider.getBalance(signer.address);
console.log("Balance:", ethers.formatEther(balance), "ETH");
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
其他開發框架
Foundry:Foundry 是由 Paradigm 推出的高性能開發框架,使用 Rust 編寫,特點是測試執行速度極快。
# 安裝 Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# 初始化專案
forge init my-project
Foundry 的優勢:
- Forge 測試速度比 Hardhat 快 10-100 倍
- 支持Invariant Testing(不變量測試)
- 內置模糊測試工具
- 完整的開發工具鏈(Forge、Cast、Anvil)
Truffle:較早期的開發框架,現在維護頻率較低,但仍有不少 legacy 專案使用。
npm install -g truffle
truffle init
智慧合約編寫
Solidity 語言基礎
Solidity 是以太坊智慧合約的主要編程語言。理解其核心概念對開發安全合約至關重要。
基本合約結構:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract SimpleStorage {
// 狀態變量
uint256 private storedData;
// 事件
event DataStored(uint256 value, address indexed owner);
// 修飾器
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
address public owner;
// 構造函數
constructor() {
owner = msg.sender;
}
// 函數
function set(uint256 x) public {
storedData = x;
emit DataStored(x, msg.sender);
}
function get() public view returns (uint256) {
return storedData;
}
}
資料類型:
- 數值類型:uint(無符號整數)、int(有符號整數)
- 位元組類型:bytes1-bytes32、bytes(動態長度)
- 地址類型:address(20 位元組)、address payable
- 布林類型:bool
- 合約類型:代表其他合約
函數可見性:
- public:任何人都可以調用
- external:只能從合約外部調用
- internal:只能從合約內部或派生合約調用
- private:只能從定義它的合約內部調用
常用程式庫
OpenZeppelin:智慧合約開發的必備庫,提供經過審計的安全實現。
npm install @openzeppelin/contracts
常用合約示例:
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {
// 鑄造初始供應量
_mint(msg.sender, 1000000 * 10 ** decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function burn(uint256 amount) public {
_burn(msg.sender, amount);
}
}
OpenZeppelin 提供的模組包括:
- ERC-20、ERC-721、ERC-1155 代幣標準
- Ownable、AccessControl 存取控制
- Pausable 暫停功能
- ReentrancyGuard 重入保護
- SafeMath 安全數學運算
編譯與錯誤處理
編譯合約:
npx hardhat compile
編譯成功後,artifacts 目錄會生成合約的 ABI 和位元組碼。
常見編譯錯誤:
- Type Error:類型不匹配
// 錯誤:嘗試將 address 賦值給 uint256
uint256 x = msg.sender;
// 正確:使用 address 類型
address x = msg.sender;
- Visibility Error:可見性錯誤
// 錯誤:狀態變量預設是 internal,不能從外部訪問
uint256 private data;
// 需要添加 getter 或改為 public
uint256 public data;
- Stack Too Deep:棧溢出
當函數內部使用過多局部變量時會出現。可以通過將相關變量打包成 struct 來解決。
調試工具
Hardhat 調試功能
Hardhat 提供了強大的調試功能,幫助開發者定位問題。
Stack Traces:
當交易失敗時,Hardhat 會顯示詳細的堆棧追蹤,定位到具體的源代碼行:
npx hardhat test
失敗輸出示例:
Error: Transaction reverted without a reason
at SimpleStore.set (contracts/SimpleStore.sol:16)
at processTicksAndRejections (node:internal/process/task_queues:95)
Console.log:
Solidity 0.8.20+ 支持在合約中使用 console.log:
import "hardhat/console.sol";
function set(uint256 x) public {
console.log("Setting value to:", x);
storedData = x;
console.log("Value set successfully");
}
Ethers.js 與合約交互
ethers.js 是與以太坊網絡交互的主要庫。
讀取合約:
const { ethers } = require("hardhat");
async function readContract() {
// 合約地址(在部署後獲得)
const contractAddress = "0x...";
// ABI(編譯後生成)
const abi = [
"function get() view returns (uint256)",
"function storedData() view returns (uint256)"
];
// 創建合約實例
const contract = new ethers.Contract(contractAddress, abi, provider);
// 調用 view 函數(不需要簽名)
const value = await contract.get();
console.log("Stored value:", value);
}
寫入合約:
async function writeContract() {
const [signer] = await ethers.getSigners();
const contract = new ethers.Contract(contractAddress, abi, signer);
// 發送交易
const tx = await contract.set(42);
console.log("Transaction sent:", tx.hash);
// 等待交易確認
const receipt = await tx.wait();
console.log("Transaction confirmed in block:", receipt.blockNumber);
}
Tenderly 進階調試
Tenderly 是一個專業的智慧合約監控和調試平台。
功能特點:
- 交易模擬:在實際部署前模擬交易執行
- 調試追蹤:視覺化交易執行過程
- Gas 分析:優化 Gas 消耗
- 監控告警:即時通知合約事件
使用示例:
const { tenderly } = require("@tenderly/hardhat-tenderly");
// 配置 Tenderly
tenderly.init({
username: "your-username",
project: "your-project",
accessKey: "your-access-key"
});
// 模擬交易
const simulation = await tenderly.simulate(
contractAddress,
"set",
[42],
{ from: userAddress }
);
常見錯誤與解決方案
交易失敗常見原因:
- Gas 不足
// 指定 Gas 限制
const tx = await contract.set(42, { gasLimit: 100000 });
- Nonce 錯誤
// 獲取當前 Nonce
const nonce = await signer.getNonce();
const tx = await contract.set(42, { nonce: nonce });
- Revert 錯誤
try {
await contract.set(42);
} catch (error) {
// 解析 revert 原因
if (error.data) {
const reason = ethers.toUtf8String(error.data.slice(10));
console.log("Revert reason:", reason);
}
}
測試框架
測試的重要性
智慧合約一旦部署就很難修改,任何漏洞都可能導致巨大的資金損失。充分的測試是確保合約安全的第一道防線。
測試覆蓋率目標:
- 語句覆蓋率(Statement Coverage):> 95%
- 分支覆蓋率(Branch Coverage):> 90%
- 函數覆蓋率(Function Coverage):100%
Hardhat 測試框架
Hardhat 使用 Mocha 測試框架,結合 Chai 斷言庫。
基本測試結構:
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("SimpleStorage", function() {
let contract;
let owner;
let otherAccount;
// 部署合約
beforeEach(async function() {
const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
contract = await SimpleStorage.deploy();
[owner, otherAccount] = await ethers.getSigners();
});
describe("Deployment", function() {
it("should set the right owner", async function() {
expect(await contract.owner()).to.equal(owner.address);
});
it("should have initial value of 0", async function() {
expect(await contract.get()).to.equal(0);
});
});
describe("set()", function() {
it("should store the value", async function() {
const tx = await contract.set(42);
await tx.wait();
expect(await contract.get()).to.equal(42);
});
it("should emit event", async function() {
const tx = await contract.set(42);
const receipt = await tx.wait();
const event = receipt.logs[0];
expect(event.args.value).to.equal(42);
expect(event.args.owner).to.equal(owner.address);
});
});
});
運行測試:
# 運行所有測試
npx hardhat test
# 運行特定測試檔案
npx hardhat test test/SimpleStorage.js
# 運行特定 describe 區塊
npx hardhat test --grep "should store the value"
Foundry 測試
Foundry 的 Forge 測試框架以其極快的執行速度著稱。
Solidity 測試:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
contract SimpleStorageTest is Test {
SimpleStorage public simpleStorage;
function setUp() public {
simpleStorage = new SimpleStorage();
}
function testSetValue() public {
simpleStorage.set(42);
assertEq(simpleStorage.get(), 42);
}
function testOnlyOwner() public {
vm.prank(address(1));
vm.expectRevert();
simpleStorage.set(100);
}
}
運行測試:
# 運行測試
forge test
# 顯示詳細輸出
forge test -vvvv
# 生成覆蓋率報告
forge coverage
進階測試技術
不變量測試(Invariant Testing):
不變量測試透過隨機化輸入來驗證合約狀態機的正確性。
contract Handler is Test {
SimpleStorage public target;
function callSet(uint256 val) public {
target.set(val);
}
// 定義不變量
function invariantValueNotNegative() public view {
assert(target.get() >= 0);
}
}
contract InvariantTest is Test {
function testInvariants() public {
Handler handler = new Handler();
target.honeypot(handler);
handler.run(1000);
}
}
模糊測試(Fuzz Testing):
function testFuzzSetValue(uint256 val) public {
simpleStorage.set(val);
assertEq(simpleStorage.get(), val);
}
Foundry 會自動生成大量隨機輸入來測試這個函數,發現邊界情況。
測試最佳實踐
- AAA 模式:Arrange(準備)、Act(執行)、Assert(斷言)
- 獨立性:每個測試應該獨立運行,不依賴其他測試的狀態
- 命名規範:清晰的測試名稱描述預期行為
- 邊界測試:測試零值、最大值、邊界條件
- 負面測試:測試錯誤輸入、權限檢查、Revert 情況
部署流程
部署到測試網絡
在部署到主網之前,應該先在測試網絡上驗證。
常見測試網絡:
- Sepolia:目前推薦的測試網絡
- Goerli:即將棄用
- Holesky:新的測試網絡
獲取測試 ETH:
- 水龍頭網站(如 Sepolia Faucet)
- 質押節點獎勵
- 中心化交易所測試網充值
部署腳本(scripts/deploy.js):
const hre = require("hardhat");
async function main() {
console.log("Deploying SimpleStorage...");
const SimpleStorage = await hre.ethers.getContractFactory("SimpleStorage");
const contract = await SimpleStorage.deploy();
await contract.waitForDeployment();
const address = await contract.getAddress();
console.log("SimpleStorage deployed to:", address);
// 驗證合約(需要 Etherscan API Key)
if (process.env.ETHERSCAN_API_KEY) {
try {
await hre.run("verify:verify", {
address: address,
constructorArguments: []
});
console.log("Contract verified on Etherscan");
} catch (error) {
console.log("Verification failed:", error.message);
}
}
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
部署命令:
# 部署到本地網絡
npx hardhat run scripts/deploy.js --network localhost
# 部署到 Sepolia
npx hardhat run scripts/deploy.js --network sepolia
部署到主網
部署到以太坊主網需要實際的 ETH 作為 Gas 費用。
環境變量配置:
# .env 文件
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_PROJECT_ID
PRIVATE_KEY=0xyour_private_key
ETHERSCAN_API_KEY=your_etherscan_api_key
# 載入環境變量
npm install dotenv
在 hardhat.config.js 中引入:
require("dotenv").config();
部署檢查清單:
- 測試網絡驗證完成
- 合約審計通過
- Gas 費用估算合理
- 多重簽名或時間鎖配置(如果是治理合約)
- 緊急暫停機制測試
- 合約地址記錄和備案
合約驗證
部署後應該在 Etherscan 上驗證合約原始碼。
手動驗證:
- 打開 Etherscan 合約頁面
- 點擊「Verify and Publish」
- 填入編譯器版本和優化設置
- 粘貼合約原始碼
- 點擊「Verify」
自動驗證(Hardhat):
npx hardhat verify --network mainnet DEPLOYED_CONTRACT_ADDRESS
主網部署後的注意事項
- 記錄合約地址:在多個安全的地方記錄
- 初始化参数:如果需要初始化,盡快執行
- 權限檢查:確認所有者權限正確設置
- 初始餘額:確保有足夠的 ETH 支付未來 Gas
- 監控設置:配置 Tenderly 等監控工具
自動化與 CI/CD
GitHub Actions 集成
建立自動化部署流程可以減少人為錯誤。
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npx hardhat test
- name: Run coverage
run: npx hardhat coverage
自動化部署
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: npm ci
- name: Deploy to Sepolia
run: npx hardhat run scripts/deploy.js --network sepolia
env:
SEPOLIA_RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
開發工具生態系總覽
工具選擇指南
| 需求 | 推薦工具 |
|---|---|
| 快速原型 | Hardhat |
| 大規模測試 | Foundry |
| 企業級支持 | Truffle + Ganache |
| 形式化驗證 | Certora |
| 調試追蹤 | Tenderly |
| Gas 優化 | Tenderly, OpenZeppelin Defender |
學習路徑建議
- 第一階段:環境搭建 + 編寫第一個合約
- 第二階段:Hardhat 測試框架 + 單元測試
- 第三階段:部署到測試網絡 + Etherscan 驗證
- 第四階段:Foundry 進階測試 + 不變量測試
- 第五階段:安全審計 + 主網部署
結論
以太坊開發工具生態系已經相當成熟,從基礎的開發框架到專業的安全工具,各種需求都有對應的解決方案。掌握這些工具的使用方法,是成為合格智慧合約開發者的必經之路。
關鍵建議:
- 選擇一個框架深入:Hardhat 或 Foundry,兩者都能滿足大多數需求
- 重視測試:測試是安全的第一道防線,不要跳過
- 學會調試:善用 Hardhat Console 和 Tenderly
- 保持更新:以太坊工具更新頻繁,關注版本變化
- 安全優先:始終假設合約會被攻擊,設計相應的安全機制
常見問題
Hardhat 和 Foundry 應該選擇哪個?
兩者各有優勢。Hardhat 生態更成熟,文檔更完善,適合團隊協作。Foundry 測試速度極快,適合需要大量測試案例的項目。建議兩者都學習,根據專案需求選擇。
如何估算部署成本?
使用 Gas Reporter 插件:
npm install --save-dev hardhat-gas-reporter
配置後,每次部署和函數調用都會顯示預估成本。
合約審計是否必要?
對於涉及資金的合約,強烈建議進行專業審計。常見審計公司包括 Trail of Bits、OpenZeppelin、Certora 等。審計費用從數千到數十萬美元不等,取決於合約複雜度。
如何處理合約升級?
使用代理模式(Proxy Pattern):
// 部署邏輯合約
implementation = new LogicContract();
// 部署代理合約,指向邏輯合約
proxy = new UpgradeableProxy(implementation);
升級時只更新代理指向的新邏輯合約地址,用戶資金存儲在代理合約中不受影響。
相關文章
- 智慧合約測試方法論完整指南 — 系統介紹單元測試、整合測試、模糊測試與形式化驗證的智慧合約測試策略。
- EIP-1559 深度解析:以太坊費用市場的範式轉移 — 深入解析 EIP-1559 的費用結構、ETH 燃燒機制、經濟學意涵,以及對用戶、驗證者和生態系統的影響。
- Tornado Cash 事件分析與隱私協議教訓 — 深入分析 2022 年 OFAC 制裁事件、技術機制與對加密隱私領域的深遠影響。
- 混幣協議風險評估與安全使用指南 — 系統分析混幣協議的智慧合約、法律合規與資產安全風險。
- 搶先交易與三明治攻擊防範完整指南 — 深入分析 MEV 搶先交易與三明治攻擊的技術機制及用戶、開發者防範策略。
延伸閱讀與來源
- Ethereum.org Developers 官方開發者入口與技術文件
- EIPs 以太坊改進提案
這篇文章對您有幫助嗎?
請告訴我們如何改進:
評論
發表評論
注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。
目前尚無評論,成為第一個發表評論的人吧!