TRC-721

TRC-721 是 TRON 上的非同质化 Token(NFT)标准,在接口层与 ERC-721 兼容。

📘

前置阅读

TRC-721 是 TRON 上的非同质化 Token(NFT)标准,规定 NFT 合约必须实现统一接口,包括余额查询、所有权确认、Token 转移与权限管理。钱包、交易市场和区块浏览器只要适配标准接口,就能与任意符合 TRC-721 的合约交互。

在接口定义上,TRC-721 与 ERC-721 兼容。主要差异有两处:第一,接收方回调函数的返回值要求不同(见下文);第二,合约运行在 TVM 上。已有 ERC-721 Token 合约通常只需通过 TRON 开发工具链重新编译并验证,即可迁移到 TRON。

必须实现的接口

符合 TRC-721 的合约必须同时实现 TRC-721TRC-165 两个接口。

pragma solidity 0.5.10;

interface TRC721 {
    // 返回指定账户持有的 NFT 数量
    function balanceOf(address _owner) external view returns (uint256);

    // 返回给定 NFT 的所有者
    function ownerOf(uint256 _tokenId) external view returns (address);

    // 转移 NFT 所有权(带数据的安全变体)
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;

    // 转移 NFT 所有权(安全变体)
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;

    // 转移 NFT 所有权(非安全变体——调用方负责验证目标地址)
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;

    // 授予 `_approved` 地址对 NFT `_tokenId` 的控制权
    function approve(address _approved, uint256 _tokenId) external payable;

    // 授予或撤销 `_operator` 对调用方所有 NFT 的控制权
    function setApprovalForAll(address _operator, bool _approved) external;

    // 返回当前被授权控制 `_tokenId` 的地址
    function getApproved(uint256 _tokenId) external view returns (address);

    // 如果 `_operator` 被授权控制 `_owner` 的所有 NFT,则返回 true
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);

    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
    event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
    event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
}

interface TRC165 {
    // 如果合约实现了 `interfaceID` 定义的接口,则返回 true
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

接收方的 TRC721TokenReceiver

如果接收方需要安全转账(即通过 safeTransferFrom 接收 NFT)必须实现接收者接口:

interface TRC721TokenReceiver {
    // 每当 safeTransferFrom 向本合约发送 NFT 时调用。
    // 返回值必须匹配 keccak256("onTRC721Received(address,address,uint256,bytes)"),
    // 否则转账将 revert。
    function onTRC721Received(
        address _operator,
        address _from,
        uint256 _tokenId,
        bytes _data
    ) external returns (bytes4);
}
🚧

注意:哈希值的不同

bytes4(keccak256("onTRC721Received(address,address,uint256,bytes)")) 的哈希值与以太坊版本 bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")) 不同。对于函数 onTRC721Received 的返回值,请使用 0x5175f878(TRON)而非 0x150b7a02(以太坊);返回以太坊的值会导致转账 revert。

可选:元数据扩展

元数据扩展(Metadata Extension)为每个 Token 提供可读的名称、符号,以及指向链下元数据的 URI。钱包和交易市场通常依赖该接口解析并展示 NFT 内容,因此多数 NFT 合约都会实现此扩展。

interface TRC721Metadata {
    // 返回该 NFT 系列的名称
    function name() external view returns (string _name);

    // 返回该系列的简称
    function symbol() external view returns (string _symbol);

    // 返回 `_tokenId` 的链下元数据文件 URI
    function tokenURI(uint256 _tokenId) external view returns (string);
}

tokenURI 指向描述该 Token 的 JSON 文件。JSON 结构如下:

{
  "title": "Asset Metadata",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "Identifies the asset this NFT represents"
    },
    "description": {
      "type": "string",
      "description": "Describes the asset this NFT represents"
    },
    "image": {
      "type": "string",
      "description": "A URI pointing to an image representing the asset"
    }
  }
}

可以将元数据 JSON 与图片托管在 IPFS、BTFS 或自建 CDN 上。NFT 铸造后绑定的 URI,后续只能通过合约提供的更新函数修改。

可选:枚举扩展

枚举扩展允许调用方列出当前集合中的全部 Token,并遍历特定地址持有的所有 Token。它能提升合约的可检索性:区块浏览器和链上分析工具不必扫描完整历史事件日志,也能直接在链上枚举持仓分布。

interface TRC721Enumerable {
    // 返回系列中 NFT 的总数量
    function totalSupply() external view returns (uint256);

    // 返回全局索引处的 tokenId
    function tokenByIndex(uint256 _index) external view returns (uint256);

    // 返回 `_owner` 的按所有者索引处的 tokenId
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

实现该扩展会增加每次铸造和转账的能量消耗,因为合约必须实时维护多组索引数组。如果 Token 项目不需要链上枚举,可以跳过该扩展;外部调用方和索引器仍可通过订阅并解析 Transfer 事件日志,在链下重建所有权关系。


相关资源