通过合约B调用合约A的setApprovalForAll成功但未生效,求排查
ERC721合约间调用setApprovalForAll授权失败排查
问题描述
我有两个继承自ERC721的智能合约A和B,想在合约B中实现一个函数,让用户Z通过B调用合约A的setApprovalForAll,给B授权。我在合约B中写了如下函数,以用户Z身份调用testApprove(A):
function testApprove(address _contract) public payable { bytes memory payload = abi.encodeWithSignature("setApprovalForAll(address,bool)", address(this), true); (bool success,) = address(_contract).delegatecall(payload); require(success); bool result = ERC721(_contract).isApprovedForAll(msg.sender, address(this)); require(result, "Approve not set!"); }
执行时success返回true且无报错,但检查发现合约B并未获得A的授权,请问哪里操作有误?
错误原因
你用错了调用方式:delegatecall的核心特性是在当前合约(B)的存储上下文里执行目标合约(A)的代码。也就是说,当你用delegatecall调用A的setApprovalForAll时,实际修改的是B合约内的ERC721授权存储数据,完全没有触及A合约的授权记录。这就相当于你在B合约里给用户Z授权了B自己,自然无法在A合约中查到对应的授权信息。
解决方法
把delegatecall替换为普通的call调用,这样会以用户Z的身份(msg.sender仍为Z)执行A合约的setApprovalForAll函数,直接修改A合约的授权存储:
function testApprove(address _contract) public payable { bytes memory payload = abi.encodeWithSignature("setApprovalForAll(address,bool)", address(this), true); // 替换delegatecall为call (bool success,) = address(_contract).call(payload); require(success, "Approval call failed"); bool result = ERC721(_contract).isApprovedForAll(msg.sender, address(this)); require(result, "Approve not set!"); }
也可以直接调用ERC721的接口函数,写法更简洁,效果和call完全一致:
function testApprove(address _contract) public { ERC721(_contract).setApprovalForAll(address(this), true); bool result = ERC721(_contract).isApprovedForAll(msg.sender, address(this)); require(result, "Approve not set!"); }
内容的提问来源于stack exchange,提问作者Zartosht Sepideman
相关产品推荐
相关产品推荐

