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)")) |
0x4e2312e0 | TRC1155TokenReceiver — XOR of the two hook selectors |
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.
Internal storage layout
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");
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));
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 4 days ago