实现 ERC721 持有 token 标准的智能合约还必须实现 ERC165,并在传递接口 ID 0x16b900ff 时返回 true。
/**
* @notice the ERC721 holder standard provides a common interface to query
* token ownership and balance information
* @notice ERC721 持有者标准提供了一个通用的接口来查询 token 所有权和余额信息
*/interfaceIERC721HolderisIERC165{/**
* @notice emitted when the token is transferred to the contract
* @param owner functional token owner
* @param tokenAddress held token address
* @param tokenId held token ID
* @notice 当 token 转移到合约时发出
* @param owner 功能性 token 所有者
* @param tokenAddress 持有 token 地址
* @param tokenId 持有 token ID
*/eventHold(addressindexedowner,addressindexedtokenAddress,uint256indexedtokenId);/**
* @notice emitted when the token is released back to the user
* @param owner functional token owner
* @param tokenAddress held token address
* @param tokenId held token ID
* @notice 当 token 释放回用户时发出
* @param owner 功能性 token 所有者
* @param tokenAddress 持有 token 地址
* @param tokenId 持有 token ID
*/eventRelease(addressindexedowner,addressindexedtokenAddress,uint256indexedtokenId);/**
* @notice get the functional owner of a held token
* @dev should throw for invalid queries and return zero for a token ID that is not held
* @param tokenAddress held token address
* @param tokenId held token ID
* @return functional token owner
* @notice 获取持有 token 的功能性所有者
* @dev 对于无效查询应抛出异常,对于未持有的 token ID 应返回零
* @param tokenAddress 持有 token 地址
* @param tokenId 持有 token ID
* @return 功能性 token 所有者
*/functionheldOwnerOf(addresstokenAddress,uint256tokenId)externalviewreturns(address);/**
* @notice get the held balance of the token owner
* @dev should throw for invalid queries and return zero for no balance
* @param tokenAddress held token address
* @param owner functional token owner
* @return held token balance
* @notice 获取 token 所有者的持有余额
* @dev 对于无效查询应抛出异常,对于没有余额的情况应返回零
* @param tokenAddress 持有 token 地址
* @param owner 功能性 token 所有者
* @return 持有 token 余额
*/functionheldBalanceOf(addresstokenAddress,addressowner)externalviewreturns(uint256);}
值得注意的是,IERC721Holder 接口的消费者可以使用以下逻辑对任何特定 token ID 的所有者进行链式查找。
/**
* @notice get the functional owner of a token
* @param tokenId token id of interest
* @notice 获取 token 的功能性所有者
* @param tokenId 感兴趣的 token id
*/functiongetOwner(uint256tokenId)externalviewreturns(address){// get raw owner
// 获取原始所有者
addressowner=token.ownerOf(tokenId);// if owner is not contract, return
// 如果所有者不是合约,则返回
if(!owner.isContract()){returnowner;}// check for token holder interface support
// 检查 token 持有者接口支持
tryIERC165(owner).supportsInterface(0x16b900ff)returns(boolret){if(!ret)returnowner;}catch{returnowner;}// check for held owner
// 检查持有所有者
tryIERC721Holder(owner).heldOwnerOf(address(token),tokenId)returns(addressuser){if(user!=address(0))returnuser;}catch{}returnowner;}