教程区块链区块链技术ch1313.4 脚本化部署与多链管理

本页目录

手动部署合约已经不可持续。现代开发使用确定性部署脚本,相同的代码在不同链上产生相同地址,配合多签或硬件钱包,构建可信的部署流水线。


13.4.1 部署脚本的架构

graph LR
    subgraph Script[部署脚本]
        S1[编译字节码]
        S2[计算 salt]
        S3[CREATE2 部署]
        S4[记录地址]
        S5[验证源码]
    end
    
    subgraph Chains[目标链]
        C1[Ethereum Mainnet]
        C2[Sepolia Testnet]
        C3[Arbitrum One]
        C4[Polygon PoS]
    end
    
    S1 --> S2 --> S3 --> S4 --> S5
    S5 --> C1
    S5 --> C2
    S5 --> C3
    S5 --> C4
    
    style Script fill:#e3f2fd

CREATE2:确定性地址部署

标准 CREATE 地址 = keccak256(发送者, nonce) —— nonce 变化导致地址变化。CREATE2 使用 salt:

\text{address} = \text{keccak256}(0xFF, \text{deployer}, \text{salt}, \text{keccak256(initCode))[12:]

相同的 initCode + salt → 相同的地址,任何 EVM 链上都一样。

typescript
/**
 * CREATE2 地址计算(纯 TypeScript,EVM 等效)
 */
function computeCreate2Address(
  deployer: string,
  salt: string,
  initCodeHash: string,
): string {
  // 地址 = keccak256(0xFF + deployer(20B) + salt(32B) + initCodeHash(32B))[12:]
  const prefix = "0xFF";
  const deployerPadded = deployer.toLowerCase().replace("0x", "").padStart(40, '0');
  const saltPadded = salt.toLowerCase().replace("0x", "").padStart(64, '0');
  const hashPadded = initCodeHash.toLowerCase().replace("0x", "").padStart(64, '0');
  
  const data = prefix + deployerPadded + saltPadded + hashPadded;
  // 简化的 hash 计算(实际应用 keccak256)
  let hash = 0;
  for (let i = 0; i < data.length; i++) {
    hash = ((hash << 5) - hash + data.charCodeAt(i)) | 0;
  }
  // 取低 20 字节
  const addrHex = (hash >>> 0).toString(16).padStart(40, '0');
  return "0x" + addrHex;
}

// 示例:在以太坊和 Arbitrum 上部署到同一地址
const factory = "0x4e59b44847b379578588920cA78FbF26c0B4956C"; // 标准 CREATE2 工厂
const salt = "0x" + "42".repeat(32);
const initCodeHash = "0x" + "ab".repeat(32); // 实际为 keccak256(creationBytecode + constructorArgs)

const addrEth = computeCreate2Address(factory, salt, initCodeHash);
const addrArb = computeCreate2Address(factory, salt, initCodeHash);
console.log("Same address on both chains:", addrEth === addrArb, addrEth);
// 输出: true, 0x...(相同的地址!)

13.4.2 多链网络配置

typescript
interface NetworkConfig {
  rpcUrl: string;
  chainId: number;
  verificationApi: string;
  deployed: { [contract: string]: string };
  // 安全:多签 / 硬件钱包
  deployerType: "EOA" | "GnosisSafe" | "HardwardWallet";
}

const networks: Record<string, NetworkConfig> = {
  mainnet: {
    rpcUrl: "https://eth-mainnet.g.alchemy.com/v2/...",
    chainId: 1,
    verificationApi: "https://api.etherscan.io/api",
    deployed: {},
    deployerType: "GnosisSafe",
  },
  sepolia: {
    rpcUrl: "https://eth-sepolia.g.alchemy.com/v2/...",
    chainId: 11155111,
    verificationApi: "https://api-sepolia.etherscan.io/api",
    deployed: {},
    deployerType: "EOA", // 测试网用 EOA 方便
  },
  arbitrum: {
    rpcUrl: "https://arb-mainnet.g.alchemy.com/v2/...",
    chainId: 42161,
    verificationApi: "https://api.arbiscan.io/api",
    deployed: {},
    deployerType: "GnosisSafe",
  },
  polygon: {
    rpcUrl: "https://polygon-mainnet.g.alchemy.com/v2/...",
    chainId: 137,
    verificationApi: "https://api.polygonscan.com/api",
    deployed: {},
    deployerType: "GnosisSafe",
  },
};

// 部署任务选择网络
console.log("Available networks:", Object.keys(networks).join(", "));

13.4.3 硬件钱包与多签部署

生产部署绝不使用本地私钥:

场景工具流程
单签硬件Ledger / Trezor脚本广播 → 硬件签回 → 广播
多签Gnosis SafePropose → Signers 确认 → Execute
自动化Defender / OpenZeppelin预设策略,自动执行
sequenceDiagram
    participant Dev as 开发者
    participant Script as 部署脚本
    participant Safe as Gnosis Safe (3/5)
    participant RPC as 节点 RPC
    participant Chain as 区块链
    
    Dev ->> Script: npx hardhat deploy --network mainnet
    Script ->> Safe: 创建 Proposal tx
    Safe ->> Signer1: 请求签名
    Safe ->> Signer2: 请求签名
    Safe ->> Signer3: 请求签名
    Signer1 -->> Safe: 签名 1/3
    Signer2 -->> Safe: 签名 2/3
    Signer3 -->> Safe: 签名 3/3 → 达到阈值
    Safe ->> RPC: broadcast execute
    RPC ->> Chain: 合约已部署
    Chain -->> Safe: receipt

> ← 13.3 测试策略 | 前往 → 13.5 合约验证 |*

评论

0

评论加载中…

发表评论

0/2000