TRC-721 protocol interfaces

Full reference for every function and event in the TRC-721 standard and its optional extensions.

📘

Prerequisites

This page is the reference for every function and event defined by TRC-721. TRC-721 is the TRON standard for non-fungible tokens (NFTs). The TRC-20 fungible-token standard is not sufficient for NFTs because each TRC-721 token is unique and needs its own tokenId, owner, and optional metadata.

TRC-721 is the TRON counterpart to Ethereum's ERC-721, and the two are interface-compatible.

Required interfaces

Every TRC-721 contract must implement the TRC-721 and TRC-165 interfaces.

pragma solidity 0.5.10;

interface TRC721 {
    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);

    function balanceOf(address _owner) external view returns (uint256);
    function ownerOf(uint256 _tokenId) external view returns (address);
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable;
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
    function approve(address _approved, uint256 _tokenId) external payable;
    function setApprovalForAll(address _operator, bool _approved) external;
    function getApproved(uint256 _tokenId) external view returns (address);
    function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

interface TRC165 {
    function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

Function reference

FunctionPurpose
balanceOf(address _owner)Returns the number of NFTs owned by _owner.
ownerOf(uint256 _tokenId)Returns the current owner of _tokenId.
safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data)Transfers _tokenId from _from to _to, invoking onTRC721Received on _to if it is a contract.
safeTransferFrom(address _from, address _to, uint256 _tokenId)Same as above with empty data.
transferFrom(address _from, address _to, uint256 _tokenId)Transfers _tokenId without the receiver-hook check. The caller is responsible for verifying that _to can handle the NFT; otherwise the token may be permanently lost.
approve(address _approved, uint256 _tokenId)Grants _approved the authority to transfer _tokenId.
setApprovalForAll(address _operator, bool _approved)Grants or revokes _operator the authority to transfer every NFT the caller currently owns and will ever own.
getApproved(uint256 _tokenId)Returns the address currently approved for _tokenId, or the zero address if none.
isApprovedForAll(address _owner, address _operator)Returns true if _operator has been approved to manage every NFT owned by _owner.
supportsInterface(bytes4 interfaceID)From TRC-165. Returns true if the contract implements the interface identified by interfaceID.

Event reference

EventFires when
Transfer(_from, _to, _tokenId)A successful transferFrom or safeTransferFrom moves a token. Also fires on mint (_from = 0x0) and burn (_to = 0x0).
Approval(_owner, _approved, _tokenId)approve succeeds, setting a new approved address for one token.
ApprovalForAll(_owner, _operator, _approved)setApprovalForAll succeeds, toggling an operator.

TRC721TokenReceiver — required for contracts that accept safe transfers

A wallet, broker, or auction contract that accepts NFTs via safeTransferFrom must implement the receiver hook:

interface TRC721TokenReceiver {
    function onTRC721Received(
        address _operator,
        address _from,
        uint256 _tokenId,
        bytes calldata _data
    ) external returns (bytes4);
}

onTRC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data)

Works in tandem with safeTransferFrom. When _to is a contract, safeTransferFrom calls onTRC721Received on that contract and checks the return value. The contract must return the hash bytes4(keccak256("onTRC721Received(address,address,uint256,bytes)")). Any other return value causes the transfer to revert.

📘

Note

The TRC-721 hash is different from the Ethereum ERC-721 hash. Return 0x5175f878 (TRON), not 0x150b7a02 (Ethereum). This is the most common porting bug when moving contracts from Ethereum.

Metadata extension (optional)

The metadata extension lets your contract expose human-readable names, symbols, and per-token URIs. Wallets and marketplaces rely on this extension to render tokens.

interface TRC721Metadata {
    function name() external view returns (string memory _name);
    function symbol() external view returns (string memory _symbol);
    function tokenURI(uint256 _tokenId) external view returns (string memory);
}
FunctionPurpose
name()Returns the human-readable collection name.
symbol()Returns a short symbol for the collection.
tokenURI(uint256 _tokenId)Returns a URI pointing to a JSON metadata file describing the individual token.

The metadata JSON file should include a name, description, and image field. Host it on IPFS, BTFS, or your own CDN — if the URI eventually goes offline, the NFT's metadata becomes inaccessible.

Enumeration extension (optional)

The enumeration extension lets callers list every NFT in the collection and every NFT owned by a specific address.

interface TRC721Enumerable {
    function totalSupply() external view returns (uint256);
    function tokenByIndex(uint256 _index) external view returns (uint256);
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
FunctionPurpose
totalSupply()Returns the total number of NFTs currently tracked by the contract.
tokenByIndex(uint256 _index)Returns the tokenId at a global index.
tokenOfOwnerByIndex(address _owner, uint256 _index)Returns the tokenId at the per-owner index for _owner.

Implementing enumeration costs extra storage and Energy on every mint, transfer, and burn because the contract must maintain two index arrays. Skip it unless you know you need on-chain enumeration — most applications can reconstruct ownership from Transfer events off-chain.


Related resources