跳转到内容

合约部署与验证

合约部署与验证

本页内容正在整理中,欢迎贡献

概述

合约部署是将编译后的字节码发布到区块链的过程。源码验证让任何人都可以在 Etherscan 上查看合约的 Solidity 源码,增强透明度和用户信任。本文涵盖 Hardhat 和 Foundry 的部署与验证流程。

主要内容

部署前检查清单

  • 所有测试通过(forge test / npx hardhat test
  • 覆盖率达标(建议 >90%)
  • 经过安全审计(主网部署必须)
  • 构造函数参数确认无误
  • Gas 预算估算充足
  • 多签钱包或 Timelock 作为 Owner(主网推荐)
  • 升级代理模式设计已评估

Hardhat 部署脚本

scripts/deploy.ts
import { ethers, run } from "hardhat";
async function main() {
console.log("开始部署...");
const MyContract = await ethers.getContractFactory("MyContract");
// 估算 Gas
const deployTx = await MyContract.getDeployTransaction(/* 构造参数 */);
const gasEstimate = await ethers.provider.estimateGas(deployTx);
console.log("预估 Gas:", gasEstimate.toString());
// 部署
const contract = await MyContract.deploy(/* 构造参数 */);
await contract.waitForDeployment();
const address = await contract.getAddress();
console.log("合约地址:", address);
// 等待足够区块数再验证(Etherscan 索引需要时间)
console.log("等待 5 个区块确认...");
await contract.deploymentTransaction()?.wait(5);
// 验证
await run("verify:verify", {
address,
constructorArguments: [/* 构造参数 */],
});
console.log("验证成功!");
}
main().catch(console.error);

Foundry 部署与验证

Terminal window
# 单命令部署并验证
forge create src/MyContract.sol:MyContract \
--rpc-url $MAINNET_RPC_URL \
--private-key $PRIVATE_KEY \
--etherscan-api-key $ETHERSCAN_API_KEY \
--verify \
--constructor-args <arg1> <arg2>
# 使用脚本部署(推荐)
forge script script/Deploy.s.sol:DeployScript \
--rpc-url $MAINNET_RPC_URL \
--broadcast \
--verify \
--etherscan-api-key $ETHERSCAN_API_KEY \
-vvvv
# 单独验证已部署合约
forge verify-contract \
<合约地址> \
src/MyContract.sol:MyContract \
--chain mainnet \
--etherscan-api-key $ETHERSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(address,uint256)" $ARG1 $ARG2)

多链验证配置

hardhat.config.ts
etherscan: {
apiKey: {
mainnet: process.env.ETHERSCAN_API_KEY!,
sepolia: process.env.ETHERSCAN_API_KEY!,
optimisticEthereum: process.env.OPTIMISM_API_KEY!,
arbitrumOne: process.env.ARBISCAN_API_KEY!,
base: process.env.BASESCAN_API_KEY!,
polygon: process.env.POLYGONSCAN_API_KEY!,
},
},

代理合约部署

大多数生产合约使用可升级代理模式:

// OpenZeppelin Upgrades Plugin (Hardhat)
import { upgrades } from "hardhat";
// 部署可升级合约
const MyContractV1 = await ethers.getContractFactory("MyContractV1");
const proxy = await upgrades.deployProxy(MyContractV1, [/* 初始化参数 */], {
initializer: "initialize",
});
await proxy.waitForDeployment();
console.log("代理地址:", await proxy.getAddress());
// 升级
const MyContractV2 = await ethers.getContractFactory("MyContractV2");
await upgrades.upgradeProxy(await proxy.getAddress(), MyContractV2);

代理模式类型:

模式优点缺点
Transparent Proxy简单Admin 不能调用实现合约
UUPSGas 更便宜升级逻辑在实现合约中
Beacon Proxy多合约统一升级结构更复杂

部署记录管理

// deployments/sepolia.json(建议提交到 git)
{
"MyToken": {
"address": "0x1234...",
"txHash": "0xabcd...",
"blockNumber": 5000000,
"deployedAt": "2024-01-01T00:00:00Z",
"constructorArgs": ["1000000000000000000000000"]
}
}

安全注意事项

  • 私钥保护:生产部署使用硬件钱包(Ledger/Trezor)
  • 多签控制:合约 Owner 设置为 Gnosis Safe 多签地址
  • Timelock:管理员操作增加时间锁延迟
  • 广播前模拟forge script --simulate 预演部署

深入阅读