TRC-1155 protocol interfaces
Full reference for every function and event in the TRC-1155 standard, plus the receiver and metadata extensions.
Prerequisites
This page is the function-and-event reference for TRC-1155. TRC-1155 lets a single contract represent and manage many fungible, non-fungible, and semi-fungible tokens, with batch operations for transfers and approvals.
ERC-1155 compatibilityTRC-1155 uses the same selectors as Ethereum's ERC-1155:
0xf23a6e61foronERC1155Receivedand0xbc197c81foronERC1155BatchReceived. ERC-1155 contracts can be ported to TRON without changing the receiver hook return values. (This is different from TRC-721, which uses TRON-specific hash0x5175f878.)
Required interfaces
A TRC-1155 contract must implement the TRC-1155 and TRC-165 interfaces:
interface ITRC1155 {
// Events
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
event TransferSingle(address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value);
event TransferBatch(address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values);
event URI(string _value, uint256 indexed _id);
// Required functions
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
function balanceOf(address _owner, uint256 _id) external view returns (uint256);
function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
}
interface ITRC165 {
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}Function reference
| Function | Purpose |
|---|---|
setApprovalForAll(address _operator, bool _approved) | Authorize or revoke _operator to transfer every token under this contract on behalf of the caller. Emits ApprovalForAll. |
isApprovedForAll(address _owner, address _operator) | Returns true if _operator is currently approved to manage every token of _owner. |
balanceOf(address _owner, uint256 _id) | Returns the balance of token _id held by _owner. |
balanceOfBatch(address[] _owners, uint256[] _ids) | Returns balances for many (owner, id) pairs in one call. The two arrays must be the same length, or the call reverts. |
safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes _data) | Transfer _value of token _id from _from to _to. If _to is a contract, calls onERC1155Received and checks the return value. |
safeBatchTransferFrom(address _from, address _to, uint256[] _ids, uint256[] _values, bytes _data) | Batch version of safeTransferFrom. Calls onERC1155BatchReceived if _to is a contract. |
Event reference
| Event | Fires when |
|---|---|
TransferSingle(_operator, _from, _to, _id, _value) | A single-token transfer succeeds. Also fires on mint (_from = 0x0) and burn (_to = 0x0). |
TransferBatch(_operator, _from, _to, _ids, _values) | A batch transfer succeeds. |
ApprovalForAll(_owner, _operator, _approved) | setApprovalForAll toggles the operator. |
URI(_value, _id) | The metadata URI for token _id is updated to _value. |
Receive hooks
A contract receiving TRC-1155 tokens via safeTransferFrom or safeBatchTransferFrom must implement TRC1155TokenReceiver:
interface TRC1155TokenReceiver {
function onERC1155Received(
address _operator,
address _from,
uint256 _id,
uint256 _value,
bytes calldata _data
) external returns (bytes4);
function onERC1155BatchReceived(
address _operator,
address _from,
uint256[] calldata _ids,
uint256[] calldata _values,
bytes calldata _data
) external returns (bytes4);
}onERC1155Received(...)
onERC1155Received(...)Called when safeTransferFrom sends tokens to a contract. The contract must return:
0xf23a6e61 // = bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))Returning any other value causes the transfer to revert.
onERC1155BatchReceived(...)
onERC1155BatchReceived(...)Called when safeBatchTransferFrom sends tokens to a contract. The contract must return:
0xbc197c81 // = bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))TRC-165 supportsInterface
supportsInterfaceA contract implementing TRC1155TokenReceiver should also implement TRC-165 introspection:
function supportsInterface(bytes4 interfaceID) external view returns (bool) {
return interfaceID == 0x01ffc9a7 // TRC-165 itself
|| interfaceID == 0x4e2312e0; // TRC1155TokenReceiver
}interfaceID | What it identifies |
|---|---|
0x01ffc9a7 | TRC-165 — bytes4(keccak256("supportsInterface(bytes4)")) |
0xd9b67a26 | TRC-1155 core interface |
0x0e89341c | TRC-1155 metadata URI extension |
0x4e2312e0 | TRC1155TokenReceiver — XOR of the two hook selectors |
A TRC-1155 token contract should return true for 0xd9b67a26 and, when it implements the metadata URI extension, for 0x0e89341c. A receiving contract should return true for 0x4e2312e0.
Metadata extension (optional)
TRC-1155 contracts may expose a per-token metadata URI through the URI event and an optional uri(uint256) function. The URI string can include the token id substitution pattern {id}, which clients replace with the lowercase hex representation of the token id (zero-padded to 64 characters).
interface ITRC1155Metadata_URI {
function uri(uint256 _id) external view returns (string memory);
}The metadata JSON pointed to by the URI follows a schema similar to TRC-721 metadata — name, description, image, and any custom attributes.
Reference implementation snippets (non-standard, OpenZeppelin-derived)
The standard above only specifies the protocol interface. The contract logic that backs these interfaces — including mint helpers, internal balance accounting, and the safe-transfer acceptance checks — is implementation-defined. The snippets below are common patterns drawn from OpenZeppelin's reference TRC-1155 implementation. They use Solidity 0.8.6, where the compiler checks integer overflow and underflow. When using Solidity 0.7.x or earlier, protect every integer operation with SafeMath or an equivalent mechanism.
Internal storage layout
pragma solidity 0.8.6;
contract TRC1155 is ITRC1155, ITRC165 {
// id => (owner => balance)
mapping (uint256 => mapping(address => uint256)) internal balances;
// owner => (operator => approved)
mapping (address => mapping(address => bool)) internal operatorApproval;
}setApprovalForAll implementation
setApprovalForAll implementationfunction setApprovalForAll(address _operator, bool _approved) external {
operatorApproval[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}safeTransferFrom with receiver-hook check
safeTransferFrom with receiver-hook check
NoteThe following code demonstrates the core transfer and minting flows; it is not a complete, independently compilable contract. It depends on storage mappings, access modifiers, and helper functions from the full implementation, including
isContract,isFungible,isNonFungible, and_doSafeTransferAcceptanceCheck.
bytes4 constant public TRC1155_ACCEPTED = 0xf23a6e61;
bytes4 constant internal TRC1155_BATCH_ACCEPTED = 0xbc197c81;
function safeTransferFrom(
address _from,
address _to,
uint256 _id,
uint256 _value,
bytes calldata _data
) external {
require(_to != address(0x0), "_to cannot be the zero address");
require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval");
require(balances[_id][_from] >= _value, "insufficient balance");
balances[_id][_from] = balances[_id][_from] - _value;
balances[_id][_to] = balances[_id][_to] + _value;
emit TransferSingle(msg.sender, _from, _to, _id, _value);
// Call onERC1155Received if the destination is a contract.
if (isContract(_to)) {
require(
TRC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data) == TRC1155_ACCEPTED,
"contract returned an unknown value from onERC1155Received"
);
}
}mintFungible helper (non-standard extension)
mintFungible helper (non-standard extension)mintFungible is not part of the TRC-1155 standard — minting is up to the implementer. The pattern below is a common one for fungible-token mints under TRC-1155:
function mintFungible(uint256 _id, address[] calldata _to, uint256[] calldata _quantities) external creatorOnly(_id) {
require(isFungible(_id));
require(_to.length == _quantities.length, "length mismatch");
for (uint256 i = 0; i < _to.length; ++i) {
address to = _to[i];
uint256 quantity = _quantities[i];
balances[_id][to] = quantity + balances[_id][to];
// 0x0 source address indicates a mint.
emit TransferSingle(msg.sender, address(0x0), to, _id, quantity);
if (isContract(to)) {
_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, to, _id, quantity, '');
}
}
}mintNonFungible helper (non-standard extension)
mintNonFungible helper (non-standard extension)mintNonFungible is similarly an implementer's pattern — it mints one NFT for each address in the list:
function mintNonFungible(uint256 _type, address[] calldata _to) external creatorOnly(_type) {
require(isNonFungible(_type));
uint256 index = maxIndex[_type] + 1;
maxIndex[_type] = _to.length + maxIndex[_type];
for (uint256 i = 0; i < _to.length; ++i) {
address dst = _to[i];
uint256 id = _type | index + i;
nfOwners[id] = dst;
emit TransferSingle(msg.sender, address(0x0), dst, id, 1);
if (isContract(dst)) {
_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, dst, id, 1, '');
}
}
}Related resources
- TRC-1155 — standard overview
- Token standards overview
- TRC-721 — for NFT-only contracts
- TRC-20 — for fungible-only contracts
- TIP-1155 specification — full protocol specification
Updated 10 days ago