部署

Forge 可以使用 forge create 命令将智能合约部署到指定网络。

Forge CLI 一次只能部署一个合约。

为了一次性部署和验证多个智能合约,Forge 的 Solidity 脚本 将是更有效的方法。

要部署合约,你必须提供 RPC URL(env:ETH_RPC_URL)和部署合约的帐户私钥。

MyContract 部署到网络:

$ forge create --rpc-url <your_rpc_url> --private-key <your_private_key> src/MyContract.sol:MyContract
compiling...
success.
Deployer: 0xa735b3c25f...
Deployed to: 0x4054415432...
Transaction hash: 0x6b4e0ff93a...

Solidity 文件可能包含多个合约。 上面的 :MyContract 指定了从 src/MyContract.sol 文件部署哪个合约。

使用 --constructor-args 标志将参数传递给构造函数:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {ERC20} from "solmate/tokens/ERC20.sol";

contract MyToken is ERC20 {
    constructor(
        string memory name,
        string memory symbol,
        uint8 decimals,
        uint256 initialSupply
    ) ERC20(name, symbol, decimals) {
        _mint(msg.sender, initialSupply);
    }
}

此外,我们可以告诉 Forge 在 Etherscan、Sourcify 或 Blockscout 上验证我们的合约(如果网络支持),方法是传递 --verify

$ forge create --rpc-url <your_rpc_url> \
    --constructor-args "ForgeUSD" "FUSD" 18 1000000000000000000000 \
    --private-key <your_private_key> \
    --etherscan-api-key <your_etherscan_api_key> \
    --verify \
    src/MyToken.sol:MyToken

验证已部署的合约

建议在 forge create 中使用 --verify 标志,以便部署后在 explorer 上自动验证合约。 请注意,对于 Etherscan,必须设置 ETHERSCAN_API_KEY

如果你正在验证已部署的合约,请继续阅读。

你可以使用 forge verify-contract 命令在 Etherscan、Sourcify、oklink 或 Blockscout 上验证合约。

你必须提供:

  • 合约地址
  • 合约名称或合约路径 <path>:<contractname>
  • 你的 Etherscan API 密钥(env:ETHERSCAN_API_KEY)(如果在 Etherscan 上验证)。

此外,你可能需要提供:

  • ABI 编码格式的构造函数参数,如果有的话
  • 编译器版本 用于构建,由提交版本前缀的 8 位十六进制数字组成(提交通常不是 nightly 版本)。 如果未指定,则会自动检测。
  • 优化次数,如果激活了 Solidity 优化器。 如果未指定,则会自动检测。
  • 链 ID,如果合约不在以太坊主网上

假设你想验证 MyToken(见上文)。 你将 优化次数 设置为 100 万,使用 v0.8.10 对其进行编译,并将其部署到如上所示的 Sepolia 测试网(链 ID : 11155111). 请注意,如果在验证时没有设置 --num-of-optimizations 将默认为 0,而如果在部署时没有设置则默认为 200,所以如果你使用默认的编译设置,请确保输入 --num-of-optimizations 200

验证方法如下:

forge verify-contract \
    --chain-id 11155111 \
    --num-of-optimizations 1000000 \
    --watch \
    --constructor-args $(cast abi-encode "constructor(string,string,uint256,uint256)" "ForgeUSD" "FUSD" 18 1000000000000000000000) \
    --etherscan-api-key <your_etherscan_api_key> \
    --compiler-version v0.8.10+commit.fc410830 \
    <the_contract_address> \
    src/MyToken.sol:MyToken 

Submitted contract for verification:
                Response: `OK`
                GUID: `a6yrbjp5prvakia6bqp5qdacczyfhkyi5j1r6qbds1js41ak1a`
                url: https://sepolia.etherscan.io//address/0x6a54…3a4c#code

建议在使用 verify-contract 命令的同时使用 --watch 标志 以便轮询验证结果。

如果未提供 --watch 标志,你可以 使用 forge verify-check 命令检查验证状态:

$ forge verify-check --chain-id 11155111 <GUID> <your_etherscan_api_key>
Contract successfully verified.

💡 提示

使用 Cast 的 abi-encode 对参数进行 ABI 编码。

在这个例子中,我们运行了 cast abi-encode "constructor(string,string,uint8,uint256)" "ForgeUSD" "FUSD" 18 1000000000000000000000 来对参数进行 ABI 编码。


故障排除

十六进制字符串缺少十六进制前缀(“0x”)

确保私钥字符串以 0x 开头。

EIP-1559 not activated

RPC 服务器不支持或未激活 EIP-1559。 传递 --legacy 标志以使用旧交易而不是 EIP-1559 交易。 如果你在本地环境中进行开发,则可以使用 Hardhat 而不是 Ganache。

Failed to parse tokens

确保传递的参数类型正确。

Signature error

确保私钥正确。

Compiler version commit for verify

如果你想检查你在本地运行的确切提交,请尝试:~/.svm/0.x.y/solc-0.x.y --version 其中 xy 分别是主要和次要版本号。 其输出类似于:

solc, the solidity compiler commandline interface
Version: 0.8.12+commit.f00d7308.Darwin.appleclang

注意:你不能只粘贴整个字符串“0.8.12+commit.f00d7308.Darwin.appleclang”作为编译器版本的参数。 但是你可以使用提交的 8 位十六进制数字来准确查找你应该从 编译器版本 复制和粘贴的内容。

已知的问题

验证具有不明确导入路径的合约

Forge 将源目录(srclibtest 等)作为 --include-path 参数传递给编译器。 这意味着给定以下项目树结构

|- src
|-- folder
|--- Contract.sol
|--- IContract.sol

可以使用 folder/IContract.sol 导入路径在 Contract.sol 中导入IContract

Etherscan 无法重新编译此类源代码。 考虑更改导入方式为相对路径。

验证没有字节码哈希的合约

目前,在 Etherscan 上,如果 bytecode_hash 设置为 none,则无法验证合约。 单击 here 了解更多关于元数据哈希如何用于源代码验证的信息。