如何在Hardhat中正确测试EIP-1167克隆合约的初始化逻辑?
问题排查与修复方案
嘿,我一眼就发现了导致你克隆合约初始化失败的核心问题,另外也给你优化下测试代码的写法:
1. 合约代码的致命错误:变量名不匹配
看你CloneFactory合约里的createClone函数,参数明明定义的是_whoopyCreator,但调用initialize的时候却用了一个完全没定义的_creator变量!在Solidity里未赋值的地址变量默认是address(0),这就是为什么测试里拿到的creator是空地址。
错误代码片段:
function createClone(address _whoopyCreator) payable external returns(address instance) { instance = Clones.clone(implementationContract); // 这里的_creator根本没定义!应该用_whoopyCreator (bool success, ) = instance.call{value: msg.value}(abi.encodeWithSignature("initialize(address)", _creator)); // ... 其他代码 }
修复只需要把调用里的_creator改成_whoopyCreator就行:
(bool success, ) = instance.call{value: msg.value}(abi.encodeWithSignature("initialize(address)", _whoopyCreator));
2. 测试代码的优化建议(非核心错误,但能让代码更可靠)
你的测试代码有些冗余的地方,优化后会更简洁且不易出错:
- 不需要手动读取JSON文件拿ABI,直接用合约工厂的
Main.interface.abi就能获取 - 不需要重新创建
Web3Provider,Hardhat测试环境里的ethers已经自带了正确的 provider,直接用签名者连接合约即可 - 通过事件名而非索引获取克隆地址,避免事件顺序变化导致的错误
优化后的测试代码:
it("Initialises contract correctly", async function () { // 部署实现合约 const Main = await ethers.getContractFactory("Main"); const main = await Main.deploy(); await main.deployed(); // 部署克隆工厂 const CloneFactory = await ethers.getContractFactory("CloneFactory"); const cf = await CloneFactory.deploy(main.address); await cf.deployed(); const [addr1] = await ethers.getSigners(); // 调用创建克隆合约 const tx = await cf.createClone(addr1.address, { value: ethers.utils.parseEther("0") }); const txReceipt = await tx.wait(1); // 通过事件名精准获取克隆地址 const newCloneEvent = txReceipt.events.find(evt => evt.event === "NewClone"); const cloneAddress = newCloneEvent.args._instance; // 直接用Main的ABI创建克隆合约实例,并用addr1连接 const clonedContract = new ethers.Contract(cloneAddress, Main.interface.abi, addr1); const creator = await clonedContract.getCreator(); expect(addr1.address).to.equal(creator); });
另外确认下你的initialize函数已经用了initializer修饰符(看起来你已经加了),这个能确保初始化函数只能被调用一次,是正确的做法。
修复完合约里的变量名问题,再用上优化后的测试代码,你的测试应该就能顺利通过了!
内容的提问来源于stack exchange,提问作者ethereumboy
相关产品推荐
相关产品推荐

