onERC721Received 中出现意外的 msg.sender

问题描述

我有一个与建设者签订的拍卖合同,如下所示:

address payable public beneficiary;
ERC721 nftContract;
bool tokenAdded;
uint256 public tokenId;

constructor() public payable {
    beneficiary = msg.sender;
}

我已启用合约以使用 safeTransferFrom 接收代币:

function onERC721Received(address,address _from,uint256 _tokenId,bytes memory) public virtual override returns (bytes4) {
    require(beneficiary == _from,"Only the beneficiary can transfer the token into the auction.");
    require(tokenAdded == false,"The auction already has a token.");
    
    nftContract = ERC721(msg.sender);
    tokenId = _tokenId;
    tokenAdded = true;
    return this.onERC721Received.selector;
}

以下是我铸造代币的方式:

pragma solidity ^0.8.0;

import "./ERC721.sol";
import "./Counters.sol";

contract MyMintingContract is ERC721 {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;

    constructor() ERC721("MyToken","MTK") {}

    function mintToken(address receiver) external returns (uint256) {
        _tokenIds.increment();

        uint256 newTokenId = _tokenIds.current();
        _safeMint(receiver,newTokenId);

        return newTokenId;
    }
}

这个想法是,部署拍卖合约的人应该是唯一可以将代币转移到拍卖合约中的人。

问题是,即使我使用与我部署拍卖合同的同一个帐户来铸造新代币,我在尝试时还是从 Only the beneficiary can transfer the token into the auction. 方法中收到错误 onERC721Received使用构造函数来铸造代币并将其转移到拍卖合约中。

我不确定 msg.sender 是否变为 MyMintingContract,因为它是调用 onERC721Received 方法的直接方法,但是当我检查 Remix 时,它显示调用 {{ 1}} 为 mintToken(这是我用来部署拍卖合约的同一个帐户),这意味着它应该与 from 变量一致。

enter image description here

如果我查询 beneficiary 变量,我会得到 beneficiary,它与上图中 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 中的地址相同。我假设 frommsg.sender 相同是否正确?

解决方法

在给定的上下文中,msg.sender 指向调用链中的直接父级(当前合约的调用者),而 tx.origin 指向调用链的根(入口点)。>

考虑一个调用链:

user
  contract A
    contract B
      contract C

对于合约 C 的上下文,msg.sender 是合约 B,tx.origin 是用户。

屏幕截图中的

from 值是 tx.origin,但不一定是 msg.sender(它只是合约 A 的 msg.sender)。