EIP-721 非同质化代币解析简单补充

SafeTransferFrom比transferFrom多一个校验步骤,校验目标地址是否是合约(dapp),如果是合约则调用目标合约的onERC721Received接口是否实现,并且检查返回值是否是 0x150b7a02 (即:bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))) 如果不是抛出异常。
(注:检查目标地址是否为合约的方法:检查目标地址code长度是否>0 本文文末有解释)

我们质疑onERC721Received的operator参数是否必要。在我们可以想象的所有情况下,如果操作员很重要,那么操作员可以将owner的token转移给自己然后使用它,然后他们就是地址from( @param _from :之前的NFT拥有者)。这似乎是人为的,因为我们认为操作员是令牌的临时所有者(并且转移给他们自己这一步操作是多余的),此时操作员发送token时,是操作员自愿发送,而不是操作员代表token持有者。这就是为什么操作员和之前的代币拥有者对代币接收者都具有重要意义的原因。(得看看实现部分)

interface ERC721Metadata // NFT数据标签name,symbol,tokenURI.URI 也许指向一个 符合 “ERC721 元数据 JSON Schema” 的 JSON 文件

interface ERC721Enumerable /* is ERC721 */ // NFT枚举拓展信息totalSupply,tokenByIndex枚举索引NFT,tokenOfOwnerByIndex枚举索引某个所有者的 NFTs
Example:

interface IERC165 {
    
    
  function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

contract ERC165 is IERC165 {
    
    
 function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
    
    
    return interfaceId == type(IERC165).interfaceId; // 此处IERC165应该是继承并已经实现了的接口,否则会出错
 }
}

function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
    
    
return
interfaceId == type(IERC721).interfaceId || // 本合约继承并实现了IERC721接口
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId); 
}

解析super:
子合约有两种方式调用父合约的函数:
①直接调用:子合约可以直接用 父合约名.函数名()
的方式来调用父合约函数。例如:ERC165.supportsInterface。
②super关键字:子合约可以利用super.函数名()来调用最近的父合约函数。它不会简单在其基类合约上调用该函数。相反,它在最终的继承关系图谱的下一个基类合约中调用这个函数。也就是说,不会调用最远的interface
IERC165中的function supportsInterface,而是调用最近的contract ERC165中的function
supportsInterface。

所有加了safe的都是检查目标地址是否为合约且是否实现了ERC721Receiver接口
检查目标是否为合约使用 :to.isContract()
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
// 检查目标地址的代码长度是否>0
// 因为代码只存储在构造函数执行的末尾。
}

unchek是为了节省gas,不用去检查上溢/下溢。
例如:每次i++调用时都会进行下/溢出检查。但是我们已经i通过length,进行了约束i < length,使得那些下溢/溢出检查变得不必要了。因此,我们可以像这样重写循环并可能节省大量gas:
uint256 length = array.length;for(uint256 i = 0; i < length;) {
doSomething(array[i]);
unchecked{ i++; }
}

资料来源:
eip-721接口标准
OpenZeppelin之ERC721实现

猜你喜欢

转载自blog.csdn.net/weixin_43380357/article/details/129697186