You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过合约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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 11:10:24