跳转到内容

ERC-1155 多代币标准

ERC-1155 多代币标准

本页内容正在整理中,欢迎贡献

概述

ERC-1155 是一种多代币标准,单个合约可以管理无限种类型的代币——既可以是同质化的(如游戏货币),也可以是非同质化的(如独特道具)。批量操作使 Gas 消耗大幅降低,特别适合区块链游戏和多资产项目。

主要内容

ERC-1155 vs ERC-721 vs ERC-20

特性ERC-20ERC-721ERC-1155
代币类型数1 种1 种无限种
同质化✅(部分 ID)
非同质化✅(供应量=1)
批量转移
部署成本低(多资产共用)
单次转账 Gas低(批量时)

基础实现

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol";
contract GameItems is ERC1155, ERC1155Supply, Ownable {
// Token ID 常量定义
uint256 public constant GOLD = 0; // 同质化:游戏金币
uint256 public constant SILVER = 1; // 同质化:银币
uint256 public constant SWORD = 2; // 半同质化:剑(可多把)
uint256 public constant RARE_SWORD = 3; // NFT:稀有剑(只有1把)
uint256 public constant SHIELD = 4;
// 每种 Token 的最大供应量(0 = 无限)
mapping(uint256 => uint256) public maxSupply;
constructor() ERC1155("https://api.mygame.xyz/items/{id}.json") Ownable(msg.sender) {
maxSupply[RARE_SWORD] = 1; // 稀有剑只有 1 把
}
// 铸造
function mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) external onlyOwner {
if (maxSupply[id] > 0) {
require(totalSupply(id) + amount <= maxSupply[id], "Exceeds max supply");
}
_mint(to, id, amount, data);
}
// 批量铸造
function mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) external onlyOwner {
_mintBatch(to, ids, amounts, data);
}
// 设置元数据 URI
function setURI(string memory newuri) external onlyOwner {
_setURI(newuri);
}
// 覆盖 supportsInterface
function supportsInterface(bytes4 interfaceId)
public view override(ERC1155, ERC1155Supply) returns (bool) {
return super.supportsInterface(interfaceId);
}
function _update(address from, address to, uint256[] memory ids, uint256[] memory values)
internal override(ERC1155, ERC1155Supply) {
super._update(from, to, ids, values);
}
}

批量转移

// 批量转移多种代币(一笔交易)
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public override {
super.safeBatchTransferFrom(from, to, ids, amounts, data);
}
// 前端批量转移
await writeContract({
address: GAME_ITEMS_ADDRESS,
abi: ERC1155_ABI,
functionName: "safeBatchTransferFrom",
args: [
fromAddress,
toAddress,
[0n, 1n, 2n], // Gold, Silver, Sword
[100n, 50n, 1n], // 数量
"0x",
],
});

元数据格式

ERC-1155 元数据 URI 中的 {id} 会被替换为十六进制 token ID(64 位,零填充):

URI 模板: "https://api.example.com/tokens/{id}.json"
tokenId 0: "https://api.example.com/tokens/0000000000000000000000000000000000000000000000000000000000000000.json"

元数据 JSON:

{
"name": "Gold Coin",
"description": "游戏中的黄金货币",
"image": "https://api.example.com/images/gold.png",
"decimals": 0,
"properties": {
"type": "currency",
"rarity": "common"
}
}

接收回调

接收 ERC-1155 的合约需实现:

import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
contract ItemVault is IERC1155Receiver {
// 接收单个 Token
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external override returns (bytes4) {
return this.onERC1155Received.selector;
}
// 接收批量 Token
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
function supportsInterface(bytes4 interfaceId) external view override returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId;
}
}

典型使用场景

场景Token ID 设计
区块链游戏0=金币(FT),1-999=武器(SFT),1000+=独特道具(NFT)
数字藏品每个系列一个 ID,supply=版次数量
活动票务每场活动一个 ID,supply=座位数
多合约替代将原来需要多个 ERC-20/721 的项目合并

深入阅读