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-721 与 TRC-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
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 事件日志,在链下重建所有权关系。
相关资源
- TRC-721 协议接口 —— 完整接口参考
- TRC-721 合约示例 —— 完整的 OpenZeppelin 风格实现
- 发行 TRC-721 Token —— 端到端部署演练
- TRC-721 合约交互 —— 读取和写入已部署的 TRC-721 合约
- TRC-1155 —— 多 Token 标准
Updated 26 days ago