Contract-Design

為什麼在執行 transfer() 後檢查 require()

  • March 7, 2021

來自 OpenZeppelin 的 ERC721 合約:

   function _safeTransfer(address from, address to, uint256 tokenId, bytes memory _data) internal virtual {
       _transfer(from, to, tokenId);
       require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
   }

在上面的程式碼中,require(...)伺服器_transfer()無論如何都會轉移令牌的目的是什麼?我想詳細說明為什麼使用這種方法。

此外,如果to是契約,則_checkOnERC721Received始終返回 true。這意味著什麼?是否有任何乙太坊合約兼容以安全地開箱即用地持有 ERC721,即使沒有實施ERC721Receiver

EIP-721建議使用一個名為的可選介面ERC721TokenReceiver

/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface ERC721TokenReceiver {
/// @notice Handle the receipt of an NFT
/// @dev The ERC721 smart contract calls this function on the recipient
///  after a `transfer`. This function MAY throw to revert and reject the
///  transfer. Return of other than the magic value MUST result in the
///  transaction being reverted.
///  Note: the contract address is always the message sender.
/// @param _operator The address which called `safeTransferFrom` function
/// @param _from The address which previously owned the token
/// @param _tokenId The NFT identifier which is being transferred
/// @param _data Additional data with no specified format
/// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
///  unless throwing
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4);
}

這個介面只有一個名為的函式onERC721Received,它返回一個等於 的常量值bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))。您可以在此處找到實施範例:https ://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/utils/ERC721Holder.sol 。

這個界面的目的是什麼?

如果有人將代幣發送到不支持 ERC721 標準的智能合約,NFT 可能會永遠失去。

EIP-721 實施了一項safeTransferFrom功能來防止這種不良情況。這個方法做的事情基本上和 一樣,只是它在執行結束時transferFrom呼叫了一個私有函式。_checkOnERC721Received

如何_checkOnERC721Received工作?

_checkOnERC721Received具有以下行為:

  1. 如果接收地址to是 EOA,則返回 true
  2. 如果接收地址to是智能合約,它將呼叫合約onERC721Received上面看到的方法並檢查結果:
  • 如果合約返回魔法值,則_checkOnERC721Received返回 true
  • 否則它返回 false 並且_safeTransfer呼叫失敗(因為require不滿足條件)。

為什麼_checkOnERC721Received最後呼叫呢?

為了尊重 Checks-Effects-Interactions 模式並防止重入攻擊:_safeTransfer首先更新 ERC721 合約狀態,然後呼叫外部智能合約。

引用自:https://ethereum.stackexchange.com/questions/94344