Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

gate-evm-tools

anan12345678793MIT1.0.15TypeScript support: included

Gate 智能合约工具集 - 字节码检查、合约升级验证、合约状态同步

bytecode, hardhat, ethereum, solidity, verification, cli, upgrade, uups, proxy, openzeppelin

readme

Gate Smart Contract Tools

🛠️ Gate 智能合约工具集 - 字节码检查、合约升级验证、合约状态同步

功能特性

🔧 配置修复(fix)

  • ✅ 自动检测 Hardhat 配置文件的兼容性问题
  • ✅ 智能修复 ESM 模块导入错误
  • ✅ 交互式确认修复操作
  • ✅ 自动备份原配置文件
  • ✅ 支持仅检查模式

🔍 字节码检查(check)

  • ✅ 检查链下合约代码和链上合约代码是否一致
  • ✅ 支持检查单个合约、指定网络或所有合约
  • 自动检测可升级合约(ERC1967代理),获取实现合约地址进行比对
  • ✅ 智能识别 Constructor 参数差异和 Immutable 变量差异
  • ✅ 自动移除元数据进行比较
  • ✅ 生成详细的 JSON 报告
  • ✅ 支持增量更新报告
  • ✅ 检测到配置错误时提供自动修复选项

🔄 合约状态同步(sync)

  • ✅ 同步链上合约状态到本地 .openzeppelin 文件
  • ✅ 自动读取链上实现合约地址
  • ✅ 获取并更新存储布局信息

✅ 升级验证(validate)

  • 自动检测合约类型(代理合约 or 实现合约)
  • 代理模式:验证升级安全性并生成 upgradeCalldata
  • 实现模式:验证存储布局兼容性并部署新合约
  • 支持通过工厂合约 Create2 部署新实现(可选 salt)
  • ✅ 检查存储布局兼容性
  • ✅ 自动部署新实现合约
  • ✅ 生成 upgradeToAndCall 的 calldata
  • ✅ 支持同一合约和不同合约的升级模式
  • ✅ 支持带构造函数参数的合约

📋 Calldata 解析(parse)

  • ✅ 解析 EVM calldata,显示函数名称和参数
  • ✅ 支持从 Hardhat artifacts 自动查找 ABI
  • ✅ 支持指定自定义 ABI 文件路径
  • ✅ 支持直接提供 ABI 数组
  • ✅ 支持批量解析多个 calldata
  • ✅ 友好的彩色输出和 JSON 导出

一、发布 NPM 包

1. 准备发布

# 进入项目目录
cd evm-checkcode-cli

# 安装依赖
npm install

# 编译 TypeScript
npm run build

2. 配置 NPM 账户

# 登录 NPM(如果还未登录)
npm login

# 输入用户名、密码、邮箱

3. 发布到 NPM

# 检查包信息
npm pack --dry-run

# 发布包
npm publish

# 如果包名已被占用,可以发布到作用域下
# 先修改 package.json 中的 name 为 "@your-username/bytecode-checker-cli"
# 然后执行:
npm publish --access public

4. 更新版本

# 更新补丁版本(1.0.0 -> 1.0.1)
npm version patch

# 更新小版本(1.0.0 -> 1.1.0)
npm version minor

# 更新大版本(1.0.0 -> 2.0.0)
npm version major

# 发布新版本
npm publish

二、使用 NPM 包

1. 安装

在你的 Hardhat 项目中安装:

npm install --save-dev gate-evm-tools

或全局安装:

npm install -g gate-evm-tools

2. 创建配置文件

在项目根目录创建 contractInfo.json 文件:

{
  "eth": {
    "Vault": "0x80aaf2e4636c510e067a5d300d8bafd48027addf",
    "VaultCrossChainRelay": "0x060194eec4556096baaabd6bf553d2658d6a66ab"
  },
  "bsc": {
    "Vault": "0x2cb7d2603a5f43b9fe79e98f09fe3eec40b6765d",
    "VaultCrossChainRelay": "0x23ae3a565e0896866e7725fe6d49fd777359c162"
  }
}

格式说明:

  • 第一层 key 是网络名称(必须与 hardhat.config.js 中的网络名称一致)
  • 第二层 key 是合约名称(必须与编译的合约名称一致)
  • value 是合约地址(可以是代理合约地址,工具会自动检测并获取实现合约地址)

支持可升级合约: 如果配置中的地址是 ERC1967 代理合约,工具会自动:

  1. 检测该地址是否为代理合约
  2. 读取实现合约地址(从 ERC1967 存储槽)
  3. 使用实现合约地址进行字节码比对

这意味着你可以直接在配置文件中填写代理合约地址,无需手动查找实现合约地址。

3. 配置 Hardhat

确保 hardhat.config.js 中配置了相应的网络:

module.exports = {
  networks: {
    eth: {
      url: "https://eth-mainnet.g.alchemy.com/v2/YOUR-API-KEY",
    },
    bsc: {
      url: "https://bsc-dataseed.binance.org/",
    }
  }
};

4. 编译合约

npx hardhat compile

5. 使用工具

📋 查看帮助

npx gate-tool --help

🔧 配置修复(推荐首次使用)

如果在使用过程中遇到 Hardhat 配置导入错误,可以使用 fix 命令自动修复:

# 自动检测并修复配置问题(交互式)
npx gate-tool fix

# 仅检查问题,不执行修复
npx gate-tool fix --check

# 跳过确认,直接修复
npx gate-tool fix --yes

常见问题:

  • Cannot find module 'hardhat/config' - 导入语句需要使用 type 关键字
  • Did you mean to import "hardhat/config.js"? - ESM 模块兼容性问题

fix 命令会自动将:

import { HardhatUserConfig } from "hardhat/config";

修复为:

import type { HardhatUserConfig } from "hardhat/config";

🔍 字节码检查

# 检查所有合约
npx gate-tool check

# 检查指定合约
npx gate-tool check --contract Vault

# 检查指定网络
npx gate-tool check --network eth

# 指定配置文件路径
npx gate-tool check --config ./config/contracts.json

# 指定输出报告路径
npx gate-tool check --output ./reports/result.json

🔄 同步链上合约状态

当合约通过 calldata 方式由其他人(如多签钱包)执行升级后,本地的 .openzeppelin 文件不会自动更新。使用此命令可以从链上读取最新状态并更新本地文件。

# 同步合约状态
npx gate-tool sync \
  --proxy 0x1234... \
  --contract CounterUUPS \
  --network sepolia

✅ 验证升级安全性并生成 calldata

验证合约升级的安全性,并生成 upgradeToAndCall 的 calldata。

支持两种模式:

  1. 代理合约模式:验证升级安全性并生成 upgradeCalldata
  2. 实现合约模式:验证代码一致性并部署新合约
模式 1: 代理合约升级验证
# 不同合约升级(从 CounterUUPS 升级到 CounterUUPSV2)
npx gate-tool validate \
  --proxy 0x1234... \
  --old CounterUUPS \
  --new CounterUUPSV2 \
  --network sepolia

# 同一合约升级(修改现有合约后升级)
npx gate-tool validate \
  --proxy 0x1234... \
  --old CounterUUPS \
  --new CounterUUPS \
  --network sepolia

# 指定输出文件路径
npx gate-tool validate \
  --proxy 0x1234... \
  --old CounterUUPS \
  --new CounterUUPSV2 \
  --network sepolia \
  --output ./upgrade-info.json

输出文件: upgradeCalldata.json

包含:

  • 代理合约地址
  • 旧实现合约地址
  • 新实现合约地址
  • upgradeToAndCall calldata
模式 2: 实现合约验证与部署

验证新合约与链上实现合约的存储布局兼容性,并部署新的实现合约。

# 验证存储布局兼容性并部署新合约
npx gate-tool validate \
  --proxy 0xImplementationAddress \
  --new LedgerImplA \
  --network mainnet

# 注意:实现合约模式不需要 --old 参数

工作流程:

  1. 🔍 自动检测地址类型(代理 or 实现)
  2. 📦 编译合约
  3. 🔐 验证存储布局兼容性(使用 Hardhat Upgrades 插件)
  4. ✅ 验证通过后部署新的实现合约
  5. 💾 保存部署信息到 implementationDeploy.json

输出文件: implementationDeploy.json

包含:

  • 旧实现合约地址
  • 新实现合约地址(新部署的)
  • 存储布局兼容状态
  • 时间戳和网络信息

使用场景:

  • ✅ 验证新合约能否安全替换旧实现合约
  • ✅ 确认存储槽位布局兼容
  • ✅ 在验证通过后立即部署新的实现合约
  • ✅ 获取新部署的实现合约地址用于后续升级

重要说明:

  • 该模式不是比较代码完全一致
  • 而是验证存储布局兼容性
  • 即使代码有修改(如新增函数、修改逻辑),只要存储布局兼容就可以升级
  • 这是可升级合约的核心安全机制
构造函数参数
# 如果新合约的构造函数需要参数
npx gate-tool validate \
  --proxy 0x1234... \
  --old CounterUUPS \
  --new CounterUUPSV2 \
  --network sepolia \
  --constructor-args '["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", 100]'

# 构造函数参数示例
# 单个地址参数
--constructor-args '["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"]'

# 多个参数(地址 + 数值)
--constructor-args '["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", 1000000]'

# 复杂参数(地址 + 字符串 + 数值 + 布尔值)
--constructor-args '["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", "MyToken", 18, true]'
工厂部署(可选)

如果需要通过工厂合约进行 Create2 部署,可以传入工厂地址(可选 salt)。

# 使用工厂合约部署新实现
npx gate-tool validate \
  --proxy 0x1234... \
  --old CounterUUPS \
  --new CounterUUPSV2 \
  --network sepolia \
  --factory 0xFactoryAddress

# 指定 salt(bytes32)
npx gate-tool validate \
  --proxy 0x1234... \
  --old CounterUUPS \
  --new CounterUUPSV2 \
  --network sepolia \
  --factory 0xFactoryAddress \
  --factory-salt 0x0000000000000000000000000000000000000000000000000000000000001234

说明:

  • 不传 --factory 时,默认走 EOA 部署逻辑
  • --factory-salt 为可选,未传时默认使用全 0

注意:

  • 代理模式:会部署新实现合约(仅用于验证),但不会升级代理合约。请使用生成的 calldata 通过多签钱包执行升级。
  • 实现模式:会部署新实现合约并返回地址,可用于后续的手动升级操作。

构造函数参数格式说明:

--constructor-args 参数接受 JSON 数组格式的字符串。参数类型会自动根据合约定义进行匹配。

常见类型示例:

  • 地址 (address): "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
  • 数值 (uint256/uint): 1000000"1000000"
  • 字符串 (string): "MyToken"
  • 布尔值 (bool): truefalse
  • 字节 (bytes): "0x1234..."

示例:

// 合约构造函数
constructor(
    address _token,
    string memory _name,
    uint256 _decimals,
    bool _isPaused
) {
    // ...
}

对应的命令:

npx gate-tool validate \
  --proxy 0x... \
  --old OldContract \
  --new NewContract \
  --network mainnet \
  --constructor-args '["0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", "MyToken", 18, false]'

📋 解析 Calldata

解析 EVM calldata,将其转换为人类可读的函数调用信息。

# 从 JSON 文件读取(推荐)
npx gate-tool parse --input parseCalldata.example.json

# 直接从命令行参数(使用合约名称从 artifacts 查找 ABI)
npx gate-tool parse \
  --to 0x5FbDB2315678afecb367f032d93F642f64180aa3 \
  --contract Counter \
  --calldata 0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000064

# 使用自定义 ABI 文件
npx gate-tool parse \
  --to 0x1234... \
  --abi-path ./custom-abi/MyContract.json \
  --calldata 0x...

# 批量解析并保存结果
npx gate-tool parse \
  --input batch-calldata.json \
  --output results.json

输入文件格式示例:

{
  "to": "0x5FbDB2315678afecb367f032d93F642f64180aa3",
  "contractName": "Counter",
  "calldata": "0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000064"
}

批量解析格式(数组 包含三种形式):

[
  {
    "to": "0x...",
    "contractName": "Counter",
    "calldata": "0x..."
  },
  {
    "to": "0x...",
    "abiPath": "./abi.json",
    "calldata": "0x..."
  },
  {
    "": "0x...",
    "abi": [
      {
        "inputs": [
          {"name": "spender", "type": "address"},
          {"name": "amount", "type": "uint256"}
        ],
        "name": "approve",
        "outputs": [{"name": "", "type": "bool"}],
        "stateMutability": "nonpayable",
        "type": "function"
      }
    ],
    "calldata": "0x..."
  }
]

支持三种 ABI 来源方式:

  1. contractName - 从 Hardhat artifacts 自动查找(需要先编译合约)
  2. abiPath - 指定 ABI 文件路径
  3. abi - 直接在 JSON 中提供 ABI 数组

6. 命令选项

check 命令

选项 简写 说明 默认值
--contract <name> -c 指定要检查的合约名称 -
--network <name> -n 指定要检查的网络名称 -
--config <path> - 指定配置文件路径 ./contractInfo.json
--output <path> -o 指定输出报告文件路径 ./bytecode-check-report.json

sync 命令

选项 简写 说明 必需
--proxy <address> - 代理合约地址
--contract <name> - 合约名称
--network <name> -n 网络名称 -

validate 命令

选项 简写 说明 必需
--proxy <address> - 代理合约地址
--old <name> - 旧合约名称(代理模式时使用) -
--new <name> - 新合约名称
--network <name> -n 网络名称 -
--output <path> -o 输出文件路径 ./upgradeCalldata.json
--constructor-args <args> - 新合约构造函数参数(JSON数组格式) -
--factory <address> - 工厂合约地址(可选,Create2 部署) -
--factory-salt <salt> - 工厂部署 salt(bytes32,可选) -

parse 命令

选项 简写 说明 默认值
--input <path> -i 输入 JSON 文件路径 -
--to <address> - 目标合约地址(命令行模式) -
--calldata <data> - Calldata 十六进制数据(命令行模式) -
--contract <name> -c 合约名称(从 artifacts 查找 ABI) -
--abi-path <path> - 自定义 ABI 文件路径 -
--output <path> -o 输出 JSON 文件路径 -
ABI 来源优先级:直接提供的 abi > abiPath > contractName

五、完整使用示例

场景 1: 验证实现合约存储布局并部署新版本

假设你有一个已部署的实现合约,需要验证新合约的存储布局兼容性并部署新版本:

# 1. 从 .openzeppelin 文件中找到实现合约地址
cat .openzeppelin/unknown-10088.json | grep "address"

# 2. 验证存储布局兼容性并部署新合约
npx gate-tool validate \
  --proxy 0x40397e8F64561AabC793514F1b28B01A2ebE6875 \
  --new LedgerImplA \
  --network gateLayer

# 输出示例:
# ✅ 验证成功!
# 
# 存储布局验证与部署结果:
# ────────────────────────────────────────────────────────────
# 旧实现合约: 0x40397e8F64561AabC793514F1b28B01A2ebE6875
# 新实现合约: 0x1234567890abcdef1234567890abcdef12345678
# 存储布局: ✅ 兼容
# 
# 输出文件: /path/to/implementationDeploy.json
# ────────────────────────────────────────────────────────────

# 3. 查看部署信息
cat implementationDeploy.json

输出文件内容:

{
  "type": "implementation",
  "oldImplementationAddress": "0x40397e8F64561AabC793514F1b28B01A2ebE6875",
  "newImplementationAddress": "0x1234567890abcdef1234567890abcdef12345678",
  "contractName": "LedgerImplA",
  "storageLayoutCompatible": true,
  "timestamp": "2024-01-01T00:00:00.000Z",
  "network": "gateLayer"
}

场景 2: 代理合约升级流程

# 1. 验证升级安全性并生成 calldata
npx gate-tool validate \
  --proxy 0xProxyAddress \
  --old CounterUUPS \
  --new CounterUUPSV2 \
  --network mainnet

# 输出示例:
# ✅ 验证成功!
# 
# 升级信息摘要:
# ────────────────────────────────────────────────────────────
# 代理合约: 0xProxyAddress
# 旧实现: 0xOldImpl
# 新实现: 0xNewImpl
# 
# Calldata: 0x4f1ef286000000000000000000000000...
# 
# 输出文件: /path/to/upgradeCalldata.json
# ────────────────────────────────────────────────────────────

# 2. 使用生成的 calldata 在多签钱包中执行升级
# - 打开多签钱包(如 Gnosis Safe)
# - 使用 upgradeCalldata.json 中的 target 和 calldata
# - 提交交易并收集签名

# 3. 升级完成后,同步本地状态
npx gate-tool sync \
  --proxy 0xProxyAddress \
  --contract CounterUUPSV2 \
  --network mainnet

场景 3: 检查多个合约的字节码

# 1. 准备配置文件 contractInfo.json
cat > contractInfo.json << EOF
{
  "contracts": {
    "mainnet": {
      "Vault": "0x1234...",
      "Token": "0x5678..."
    },
    "sepolia": {
      "Vault": "0xabcd..."
    }
  }
}
EOF

# 2. 执行检查
npx gate-tool check

# 3. 查看报告
cat bytecode-check-report.json

场景 4: 解析升级交易的 calldata

# 1. 从多签钱包获取待执行的 calldata
# 2. 解析 calldata 查看具体操作
npx gate-tool parse \
  --to 0xProxyAddress \
  --contract CounterUUPS \
  --calldata 0x4f1ef286000000000000000000000000...

# 输出示例:
# 📋 Calldata 解析结果
# ════════════════════════════════════════════════
# 目标合约: 0xProxyAddress
# 合约名称: CounterUUPS
# 
# 函数名称: upgradeToAndCall
# 函数签名: upgradeToAndCall(address,bytes)
# 
# 参数列表:
# ────────────────────────────────────────────────
# 1. newImplementation (address)
#    0x1234567890abcdef1234567890abcdef12345678
# 
# 2. data (bytes)
#    0x
# ════════════════════════════════════════════════