调用含结构体数组参数的智能合约工厂触发Revert错误求助
问题:通过CampaignFactory创建Campaign实例时触发Revert错误
调用CampaignFactory的createCampaign方法创建新Campaign实例时,Remix返回以下错误:
[vm]from: 0x5B3...eddC4to: CampaignFactory.createCampaign((uint256,uint256,string)[]) 0xd91...39138value: 0 weidata: 0x6d9...00000logs: 0hash: 0xa4d...ad5fd transact to CampaignFactory.createCampaign errored: VM error: revert.
原代码
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.15; struct Reward { uint256 contribution; uint256 maxNumber; string ImageLink; } contract CampaignFactory { Campaign[] public deployedCampaigns; function createCampaign(Reward[] memory _rewards) public { Campaign newCampaign = new Campaign(msg.sender); for (uint256 i = 0; i < _rewards.length; i++) { newCampaign.createReward( _rewards[i].contribution, _rewards[i].maxNumber, _rewards[i].ImageLink ); } deployedCampaigns.push(newCampaign); } function getDeployedCampaigns() public view returns (Campaign[] memory) { return deployedCampaigns; } } contract Campaign { Reward[] public rewards; address public manager; modifier restricted() { require(msg.sender == manager); _; } constructor(address creator) { manager = creator; } function createReward( uint256 _contribution, uint256 _maxNumber, string memory _imageLink ) public restricted { Reward memory newReward = Reward({ contribution: _contribution, maxNumber: _maxNumber, ImageLink: _imageLink }); rewards.push(newReward); } }
问题原因
错误根源在于权限校验:
- 创建Campaign实例时,
manager被设置为调用createCampaign的用户地址(msg.sender)。 - 随后CampaignFactory调用Campaign的
createReward方法时,此时的msg.sender是Factory合约地址,而非Campaign的manager地址。 createReward方法的restricted修饰器要求调用者必须是manager,因此触发revert。
修复方案
最直接高效的方式是在Campaign的构造函数中直接初始化rewards数组,避免后续跨合约调用的权限问题:
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.15; struct Reward { uint256 contribution; uint256 maxNumber; string ImageLink; } contract CampaignFactory { Campaign[] public deployedCampaigns; function createCampaign(Reward[] memory _rewards) public { // 直接将_rewards传入Campaign构造函数初始化 Campaign newCampaign = new Campaign(msg.sender, _rewards); deployedCampaigns.push(newCampaign); } function getDeployedCampaigns() public view returns (Campaign[] memory) { return deployedCampaigns; } } contract Campaign { Reward[] public rewards; address public manager; modifier restricted() { require(msg.sender == manager); _; } // 修改构造函数,接收rewards数组并初始化 constructor(address creator, Reward[] memory _rewards) { manager = creator; // 批量添加奖励 for (uint256 i = 0; i < _rewards.length; i++) { rewards.push(_rewards[i]); } } // 保留原方法用于后续添加奖励(可选) function createReward( uint256 _contribution, uint256 _maxNumber, string memory _imageLink ) public restricted { Reward memory newReward = Reward({ contribution: _contribution, maxNumber: _maxNumber, ImageLink: _imageLink }); rewards.push(newReward); } }
说明
- 构造函数初始化rewards数组的方式减少了一次跨合约调用,既避免了权限问题,也降低了gas消耗。
- 原
createReward方法仍可保留,供后续manager添加新奖励使用。
内容的提问来源于stack exchange,提问作者Jeks
相关产品推荐
相关产品推荐

