TRC-1155 协议接口
TRC-1155 标准中每个函数和事件的完整参考,以及接收者和元数据扩展。
前置阅读
本文是 TRC-1155 的函数与事件参考。TRC-1155 允许单个合约同时管理同质化、非同质化、半同质化 Token,并支持批量转账与授权。
ERC-1155 兼容性TRC-1155 使用与 ERC-1155 完全一致的选择器:
onERC1155Received对应0xf23a6e61,onERC1155BatchReceived对应0xbc197c81。ERC-1155 合约可直接移植到 TRON,无需修改接收者钩子返回值——与 TRC-721 不同,后者使用 TRON 特有的哈希0x5175f878。
必须实现的接口
TRC-1155 合约必须实现 TRC-1155 和 TRC-165 接口:
interface ITRC1155 {
// 事件
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);
// 必须实现的函数
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);
}函数参考
| 函数 | 用途 |
|---|---|
setApprovalForAll(address _operator, bool _approved) | 授权或撤销 _operator 代表调用方转账该合约下所有 Token 的权限。触发 ApprovalForAll 事件。 |
isApprovedForAll(address _owner, address _operator) | 若 _operator 当前被授权管理 _owner 的所有 Token,则返回 true。 |
balanceOf(address _owner, uint256 _id) | 返回 _owner 持有的 _id Token 余额。 |
balanceOfBatch(address[] _owners, uint256[] _ids) | 在一次调用中返回多个 (owner, id) 对的余额。两个数组长度必须相同,否则调用 revert。 |
safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes _data) | 将 _value 个 _id Token 从 _from 转账到 _to。若 _to 是合约,则调用 onERC1155Received 并检查返回值。 |
safeBatchTransferFrom(address _from, address _to, uint256[] _ids, uint256[] _values, bytes _data) | safeTransferFrom 的批量版本。若 _to 是合约则调用 onERC1155BatchReceived。 |
事件参考
| 事件 | 触发时机 |
|---|---|
TransferSingle(_operator, _from, _to, _id, _value) | 单 Token 转账成功时触发。铸造(_from = 0x0)和燃烧(_to = 0x0)时也会触发。 |
TransferBatch(_operator, _from, _to, _ids, _values) | 批量转账成功时触发。 |
ApprovalForAll(_owner, _operator, _approved) | setApprovalForAll 切换操作员授权状态时触发。 |
URI(_value, _id) | _id Token 的元数据 URI 更新为 _value 时触发。 |
接收钩子
通过 safeTransferFrom 或 safeBatchTransferFrom 接收 TRC-1155 Token 的合约必须实现 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(...)当 safeTransferFrom 向本合约发送 Token 时触发。合约须返回:
0xf23a6e61 // = bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))
返回任何其他值都会导致转账 revert。
onERC1155BatchReceived(...)
onERC1155BatchReceived(...)当 safeBatchTransferFrom 向合约发送 Token 时调用。合约必须返回:
0xbc197c81 // = bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))
TRC-165 supportsInterface
supportsInterface实现 TRC1155TokenReceiver 的合约还应实现 TRC-165 内省:
function supportsInterface(bytes4 interfaceID) external view returns (bool) {
return interfaceID == 0x01ffc9a7 // TRC-165 本身
|| interfaceID == 0x4e2312e0; // TRC1155TokenReceiver
}interfaceID | 标识的接口 |
|---|---|
0x01ffc9a7 | TRC-165——bytes4(keccak256("supportsInterface(bytes4)")) |
0x4e2312e0 | TRC1155TokenReceiver——两个钩子选择器的异或值 |
元数据扩展(可选)
TRC-1155 合约可通过 URI 事件和可选的 uri(uint256) 函数暴露每个 Token 的元数据 URI。URI 字符串可包含 Token ID 替换模式 {id},客户端将其替换为 Token ID 的小写十六进制表示(零填充至 64 个字符)。
interface ITRC1155Metadata_URI {
function uri(uint256 _id) external view returns (string memory);
}URI 指向的元数据 JSON 遵循与 TRC-721 元数据类似的结构——name、description、image 以及任何自定义 attributes。
参考实现片段(非标准,源自 OpenZeppelin)
以上标准仅规定了协议接口。支持这些接口的合约逻辑——包括铸造辅助函数、内部余额记账以及安全转账接受检查——由实现方定义。以下代码片段是从 OpenZeppelin 的 TRC-1155 参考实现中提取的常见模式。
内部存储结构
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 实现
setApprovalForAll 实现function setApprovalForAll(address _operator, bool _approved) external {
operatorApproval[msg.sender][_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}带接收者钩子检查的 safeTransferFrom
safeTransferFrombytes4 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);
// 若目标地址是合约,则调用 onERC1155Received。
if (isContract(_to)) {
require(
TRC1155TokenReceiver(_to).onERC1155Received(msg.sender, _from, _id, _value, _data) == TRC1155_ACCEPTED,
"contract returned an unknown value from onERC1155Received"
);
}
}mintFungible 辅助函数(非标准扩展)
mintFungible 辅助函数(非标准扩展)mintFungible 不是 TRC-1155 标准的一部分——铸造由实现方决定。以下模式是 TRC-1155 下同质化 Token 铸造的常见做法:
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 源地址表示铸造。
emit TransferSingle(msg.sender, address(0x0), to, _id, quantity);
if (isContract(to)) {
_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, to, _id, quantity, '');
}
}
}mintNonFungible 辅助函数(非标准扩展)
mintNonFungible 辅助函数(非标准扩展)mintNonFungible 同样是实现方的模式——它为列表中每个地址铸造一个 NFT:
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, '');
}
}
}相关资源
- TRC-1155 —— 标准概览
- Token 标准概览
- TRC-721 —— 仅 NFT 合约
- TRC-20 —— 仅同质化 Token 合约
- TIP-1155 规范 —— 完整协议规范
Updated 26 days ago