TL;DR; 6月1日那天,我正式决定先续约三个月工作室,同时为了防止在劣币圈里被驱使,最终导致劣化,暂时不接受不合适的工作。我开始为之前的项目收尾,同时继续将个人项目深入开发。这是一个迂回的反复尝试的过程,在进入个人饥饿期中,是一种不错的知识体系升级。 我从4月初开始,认真学习编写Solidity,虽然之前也是通过remix简单玩耍过,在过去的差不多一年时间里,也一直作为代码的reviewer查看合作的小博士写的合约,但真正想要承接核心逻辑,是从4月初才开始的。对各个部分的理解在逐步加深。下面记录一下如何verify发布的合约。
我首先在Base Sepolia的basescan上的在线工具 尝试,在填写了部署好的合约地址后,选取了Solidity Single File,版本为0.8.20+,随后的界面中,需要粘贴合约源代码。 第一次尝试时我粘贴了原始的合约代码,得到结果是:
1 2 3 4 5 ParserError: Source "erc721a/contracts/ERC721A.sol" not found: File import callback not supported --> myc:6:1: | 6 | import "erc721a/contracts/ERC721A.sol" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
原因是这里的源代码不支持import的模块,问询GPT后,发现可以通过flatten 方式,将所有引入的部分进行封装,为了满足验证时的类型说明,调用办法为:
1 npx hardhat flatten contracts/Foo.sol > Flattened.sol
我严格遵守了GPT给出的建议,移除多个interface和library声明的重复SPDX-License-Identifier, 以及pragma solidity, 但是仍然有问题:
1 2 Found the following ContractName(s) in source code : Context, ERC721A, ERC721A__IERC721Receiver, IERC721A, Math, Ownable, SignedMath, Strings But we were unable to locate a matching bytecode (err_code_2)
在flatten之后的代码中,我明明十分清楚地看到了提及名称的定义代码,但是他就是十分执着地视而不见,我决定看看另外的一种办法,利用hardhat工具链中的hardhat-verify。
hardhat-verify
安装工具包
1 npm i --save-dev @nomicfoundation/hardhat-verify
在配置文件,hardhat.config.ts中,增加对应配置,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import '@nomicfoundation/hardhat-verify' ;import '@nomicfoundation/hardhat-toolbox' ;import { HardhatUserConfig } from 'hardhat/config' ;import dotenv from 'dotenv' ;dotenv.config (); const config : HardhatUserConfig = { solidity : { compilers : [{ version : '0.8.20' }, { version : '0.4.18' }], settings : { optimizer : { enabled : true , runs : 1000 , }, }, }, networks : { sepolia : { url : `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_SEPOLIA_API_KEY} ` , accounts : [process.env .SEPOLIA_ACCOUNT_PRIVATE_KEY !], chainId : 11155111 , }, baseSepolia : { url : `https://sepolia.base.org` , accounts : [process.env .SEPOLIA_ACCOUNT_PRIVATE_KEY !], chainId : 84532 , }, }, sourcify : { enabled : true , }, etherscan : { apiKey : { baseSepolia : process.env .BASESCAN_API_KEY !, }, customChains : [ { network : "baseSepolia" , chainId : 84532 , urls : { apiURL : "https://api-sepolia.basescan.org/api" , browserURL : "https://sepolia.basescan.org" } } ] }, }; export default config;
task冲突的问题
这里hardhat自己的工具链中会有冲突,如果直接这样保存运行任何hardhat命令,都会发生如下问题:
1 Error HH209: Redefinition of task verify:get-contract-information failed. Unsupported operation adding mandatory (non optional) param definitions in an overridden task.
进一步查询后很多人说hardhat-verify和hardhat-toolbox中定义的task冲突,后发现npx hardhat verify支持参数 –config,所以可以将配置文件拆分,既然你们冲突,verify的单独建立一个就可以了。以下为verify.config.ts。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import '@nomicfoundation/hardhat-verify' ;import { HardhatUserConfig } from 'hardhat/config' ;import dotenv from 'dotenv' ;dotenv.config (); const config : HardhatUserConfig = { solidity : { compilers : [{ version : '0.8.20' }, { version : '0.4.18' }], settings : { optimizer : { enabled : true , runs : 1000 , }, }, }, networks : { sepolia : { url : `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_SEPOLIA_API_KEY} ` , accounts : [process.env .SEPOLIA_ACCOUNT_PRIVATE_KEY !], chainId : 11155111 , }, baseSepolia : { url : `https://sepolia.base.org` , accounts : [process.env .SEPOLIA_ACCOUNT_PRIVATE_KEY !], chainId : 84532 , } }, sourcify : { enabled : true , }, etherscan : { apiKey : { baseSepolia : process.env .BASESCAN_API_KEY !, }, customChains : [ { network : "baseSepolia" , chainId : 84532 , urls : { apiURL : "https://api-sepolia.basescan.org/api" , browserURL : "https://sepolia.basescan.org" } }, ] }, }; export default config;
准备部署合约时的constructor arguments
hardhat verify可以指定自定义一个arg.js传入参数,对准备创建合约时候的参数十分友好。 一个参数例子:
1 2 3 4 5 6 7 module .exports = [ 'StringArg1' , BigInt (100 ) * 1000n * 10n ** 18n , [ '0x0000' , ], ]
完整调用,加上–verbose方便诊断1 npx hardhat verify --config verify.config.ts --network baseSepolia DEPLOYED_CONTRACT_ADDRESS --constructor-args args.js --verbose
这次调用后,得到了一个新错误:
1 The HTTP server response is not ok. Status code: 500 Response text: {"error":"Invalid chainIds: 84532","message":"Invalid chainIds: 84532"}
因为开启了verbose,可以看到其本质上是一个工具链,其中在调用一个服务时,https://sourcify.dev/server/check-all-by-addresses 时,返回值说明这个chainId并没有被支持。 我们来到其主页时,调用了它的公共api中的https://sourcify.dev/server/chains, 看到其中Base Sepolia不在被支持之列。但是Base自己本身是在的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "name" : "Base" , "chainId" : 8453 , "rpc" : [ "https://mainnet.base.org/" , "https://developer-access-mainnet.base.org/" , "https://base.gateway.tenderly.co" , "wss://base.gateway.tenderly.co" , "https://base-rpc.publicnode.com" , "wss://base-rpc.publicnode.com" ] , "supported" : true , "etherscanAPI" : "https://api.basescan.org/" }
这可如何是好。
借尸还魂/借鸡生蛋 诸多L2的链都对标准的solidity合约兼容,所以说理论上我的合约可以发布到任何一个热门的L2上,只要其可以通过合约验证,说明我们的合约在规范层面是不存在什么问题的。于是我去看了一下热门的L2都有哪些,再去sourcify的支持列表看看支持情况。最终选定了Arbitrum Sepolia,获取对应的测试ETH后,在配置文件中新增network配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 ... networks : { sepolia : { url : `https://eth-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_SEPOLIA_API_KEY} ` , accounts : [process.env .SEPOLIA_ACCOUNT_PRIVATE_KEY !], chainId : 11155111 , }, baseSepolia : { url : `https://sepolia.base.org` , accounts : [process.env .SEPOLIA_ACCOUNT_PRIVATE_KEY !], chainId : 84532 , }, arbitrumSepolia : { url : `https://arb-sepolia.g.alchemy.com/v2/${process.env.ALCHEMY_API_KEY} ` , accounts : [process.env .SEPOLIA_ACCOUNT_PRIVATE_KEY !], chainId : 421614 , }, }, sourcify : { enabled : true , }, etherscan : { apiKey : { baseSepolia : process.env .ETHERSCAN_API_KEY !, arbitrumSepolia : process.env .ARBITRUMSCAN_SEPOLIA_API_KEY , }, customChains : [ { network : "baseSepolia" , chainId : 84532 , urls : { apiURL : "https://api-sepolia.basescan.org/api" , browserURL : "https://sepolia.basescan.org" } }, { network : "arbitrumSepolia" , chainId : 421614 , urls : { apiURL : "https://api-sepolia.arbiscan.io/api" , browserURL : "https://sepolia.arbiscan.io/" } } ] },
随后这次,我们再使用arbitrumSepolia网络调用verify,在工具链最后一步还是会报错,我已经准备放弃了,但是我却看到这么一行。
1 2 The contract 0x0 has already been verified on the block explorer. https://sepolia.arbiscan.io/address/0x0#code
管他的,去查看后,确实发现合约已经被verified了。
未解之谜
继续尝试使用在线工具验证
看看hardhat-verify在验证之后还在搞什么鬼导致最后执行错误。