TRC-721
TRC-721 is the TRON standard for non-fungible tokens (NFTs), fully compatible with ERC-721.
Prerequisites
TRC-721 is the TRON standard for non-fungible tokens (NFTs). It defines a common interface every NFT contract must expose — balance queries, ownership lookups, transfers, and approval management — so that wallets, marketplaces, and explorers can interact with any TRC-721 contract without custom integration work.
TRC-721 is fully compatible with the Ethereum ERC-721 standard at the interface level. The only practical differences are the receiver-hook return value (see below) and the compiler and runtime environment (TVM instead of EVM). If you have an ERC-721 contract, porting it to TRON is mostly a matter of recompiling with the TRON toolchain.
Required interfaces
Every TRC-721 compliant contract must implement both the TRC-721 and TRC-165 interfaces. TRC-165 is the introspection interface — it lets a caller ask the contract "do you support this other interface?" without having to make a call that might revert.
pragma solidity 0.5.10;
interface TRC721 {
// Returns the number of NFTs owned by the given account
function balanceOf(address _owner) external view returns (uint256);
// Returns the owner of the given NFT
function ownerOf(uint256 _tokenId) external view returns (address);
// Transfer ownership of NFT (safe variant with data)
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable;
// Transfer ownership of NFT (safe variant)
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
// Transfer ownership of NFT (unsafe variant — caller is responsible for the destination)
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
// Grants the `_approved` address control of the NFT `_tokenId`
function approve(address _approved, uint256 _tokenId) external payable;
// Grants or revokes control of every NFT owned by the caller to `_operator`
function setApprovalForAll(address _operator, bool _approved) external;
// Returns the address currently approved for `_tokenId`
function getApproved(uint256 _tokenId) external view returns (address);
// Returns true if `_operator` is approved for all NFTs owned by `_owner`
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 {
// Returns true if the contract implements the interface defined by `interfaceID`
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}Receiving contracts must implement TRC721TokenReceiver
TRC721TokenReceiverA wallet, broker, or auction contract that wants to accept safe transfers (that is, receive NFTs via safeTransferFrom) must implement the receiver interface:
interface TRC721TokenReceiver {
// Called whenever a safeTransferFrom sends an NFT to this contract.
// The return value must match keccak256("onTRC721Received(address,address,uint256,bytes)")
// or the transfer reverts.
function onTRC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes calldata _data
) external returns (bytes4);
}
TRON-specific return valueThe TRC-721 hash differs from the Ethereum ERC-721 version. Use
0x5175f878(the TRON hash), not0x150b7a02(the Ethereum hash). Returning the Ethereum value causes the transfer to revert.
Optional: metadata extension
The metadata extension exposes a human-readable name, a symbol, and a URI pointer to off-chain metadata for each token. Most NFT contracts implement this — wallets and marketplaces use it to render the token.
interface TRC721Metadata {
// Returns the name of this NFT collection
function name() external view returns (string memory _name);
// Returns a short symbol for the collection
function symbol() external view returns (string memory _symbol);
// Returns the URI of an external metadata file for `_tokenId`
function tokenURI(uint256 _tokenId) external view returns (string memory);
}The tokenURI points to a JSON file describing the individual token. The expected JSON schema is:
{
"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"
}
}
}Host the metadata JSON and image on IPFS, BTFS, or a CDN you control. Once an NFT is minted with a URI, changing that URI is only possible if the contract exposes an update function.
Optional: enumeration extension
The enumeration extension lets callers list every token in the collection and walk the tokens owned by an address. This makes your contract discoverable — explorers and analytics tools can enumerate holdings without scanning logs.
interface TRC721Enumerable {
// Returns the total number of NFTs in the collection
function totalSupply() external view returns (uint256);
// Returns the tokenId at a global index
function tokenByIndex(uint256 _index) external view returns (uint256);
// Returns the tokenId at the per-owner index for `_owner`
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}Implementing this extension costs extra Energy on mints and transfers because the contract must maintain index arrays. Skip it if your collection never needs enumeration — callers can always reconstruct ownership from Transfer events.
Related resources
- TRC-721 protocol interfaces — full interface reference
- TRC-721 contract example — full OpenZeppelin-style implementation
- Issuing a TRC-721 token — end-to-end deployment walkthrough
- TRC-721 contract interaction — read and write from a deployed TRC-721
- TRC-1155 — multi-token standard
Updated 11 days ago