本文介绍了ERC-1155代币标准,它是一种新型代币标准,旨在从以前的标准中吸取精华,以创建与同质化无关且具有gas效率的代币合约。ERC-1155使用单个智能合约来同时表示多个代币,从而节省了gas,并简化了多代币项目的部署和操作。文章还提供了构造ERC-1155代币合约的示例,并讨论了如何向合约发送代币。
ERC-1155 是一种新颖的 token 标准,旨在从以前的标准中吸取精华,创建一个 fungibility-agnostic 和 gas-efficient 的 token 合约。
ERC-1155 从 ERC-20, ERC-721, 和 ERC-777 中借鉴了想法。如果你不熟悉这些标准,请在继续之前查阅它们的指南。 |
ERC-1155 的显著特点是它使用单个智能合约来同时表示多个 token。这就是为什么它的 balanceOf
函数与 ERC-20 和 ERC-777 的不同:它有一个额外的 id
参数,用于标识你想查询余额的 token。
这与 ERC-721 的做法类似,但在该标准中,token id
没有余额的概念:每个 token 都是非同质化的,要么存在,要么不存在。ERC-721 的 balanceOf
函数指的是一个账户拥有多少个不同的 token,而不是每种 token 有多少个。另一方面,在 ERC-1155 中,账户对每个 token id
都有不同的余额,而非同质化 token 的实现方式仅仅是铸造一个。
这种方法为需要多种 token 的项目节省了大量的 gas。无需为每种 token 类型部署新的合约,单个 ERC-1155 token 合约就可以保存整个系统状态,从而降低部署成本和复杂性。
由于所有状态都保存在单个合约中,因此可以在单个交易中非常高效地操作多个 token。该标准提供了两个函数,balanceOfBatch
和 safeBatchTransferFrom
,它们使查询多个余额和转移多个 token 更简单,gas 消耗更少。
本着该标准的精神,我们还在非标准函数中包含了批量操作,例如 _mintBatch
。
我们将使用 ERC-1155 来跟踪我们游戏中的多个物品,每个物品都有自己独特的属性。我们将所有物品铸造给合约的部署者,我们稍后可以将这些物品转移给玩家。玩家可以自由地保留他们的 token,或者与其他玩家进行交易,就像他们在区块链上交易任何其他资产一样!
为简单起见,我们将在构造函数中铸造所有物品,但你可以向合约添加铸造功能,以便按需铸造给玩家。
有关铸造机制的概述,请查看创建 ERC-20 供应。 |
这是一个 token 化物品的合约示例:
// contracts/GameItems.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
contract GameItems is ERC1155 {
uint256 public constant GOLD = 0;
uint256 public constant SILVER = 1;
uint256 public constant THORS_HAMMER = 2;
uint256 public constant SWORD = 3;
uint256 public constant SHIELD = 4;
constructor() ERC1155("https://game.example/api/item/{id}.json") {
_mint(msg.sender, GOLD, 10 ** 18, "");
_mint(msg.sender, SILVER, 10 ** 27, "");
_mint(msg.sender, THORS_HAMMER, 1, "");
_mint(msg.sender, SWORD, 10 ** 9, "");
_mint(msg.sender, SHIELD, 10 ** 9, "");
}
}
请注意,对于我们的游戏物品,黄金是一种同质化 token,而雷神之锤是一种非同质化 token,因为我们只铸造了一个。
ERC1155
合约包括可选的扩展 IERC1155MetadataURI
。这就是 uri
函数的来源:我们使用它来检索元数据 URI。
另请注意,与 ERC-20 不同,ERC-1155 缺少 decimals
字段,因为每个 token 都是不同的,不能被分割。
部署后,我们将能够查询部署者的余额:
> gameItems.balanceOf(deployerAddress,3)
1000000000
我们可以将物品转移给玩家账户:
> gameItems.safeTransferFrom(deployerAddress, playerAddress, 2, 1, "0x0")
> gameItems.balanceOf(playerAddress, 2)
1
> gameItems.balanceOf(deployerAddress, 2)
0
我们还可以批量将物品转移给玩家账户,并获取批量的余额:
> gameItems.safeBatchTransferFrom(deployerAddress, playerAddress, [0,1,3,4], [50,100,1,1], "0x0")
> gameItems.balanceOfBatch([playerAddress,playerAddress,playerAddress,playerAddress,playerAddress], [0,1,2,3,4])
[50,100,1,1,1]
可以获得元数据 URI:
> gameItems.uri(2)
"https://game.example/api/item/{id}.json"
uri
可以包含字符串 {id}
,客户端必须将其替换为实际的 token ID,以小写十六进制形式(不带 0x 前缀),并以零填充到 64 个十六进制字符。
对于 token ID 2
和 URI https://game.example/api/item/{id}.json
,客户端会将 {id}
替换为 0000000000000000000000000000000000000000000000000000000000000002
,以检索 https://game.example/api/item/0000000000000000000000000000000000000000000000000000000000000002.json
处的 JSON。
token ID 2 的 JSON 文档可能如下所示:
{
"name": "Thor's hammer",
"description": "Mjölnir, the legendary hammer of the Norse god of thunder.",
"image": "https://game.example/item-id-8u5h2m.png",
"strength": 20
}
有关元数据 JSON 架构的更多信息,请查看 ERC-1155 元数据 URI JSON 架构。
你会注意到该物品的信息包含在元数据中,但该信息不在链上!因此,游戏开发者可以更改底层元数据,从而更改游戏规则! |
如果你想将所有物品信息放在链上,你可以扩展 ERC-721 来做到这一点(尽管这将非常昂贵),方法是提供一个带有编码的 JSON 模式的 Base64 数据 URI。你还可以利用 IPFS 来存储 URI 信息,但这些技术超出了本概述指南的范围 |
使用 safeTransferFrom
时的一个主要区别是,向其他合约转移 token 可能会因以下自定义错误而恢复:
ERC1155InvalidReceiver("<ADDRESS>")
这是一件好事!这意味着接收合约尚未将自己注册为知道 ERC-1155 协议,因此禁用了向其的转移,以防止 token 永远被锁定。例如,Golem 合约目前持有超过 35 万个 GNT
token,并且缺乏将它们从那里取出的方法。这种情况几乎发生在每个 ERC20 支持的项目中,通常是由于用户错误造成的。
为了让我们的合约接收 ERC-1155 token,我们可以继承便捷合约 ERC1155Holder
,它会为我们处理注册。但是,我们需要记住实现允许 token 从我们的合约转移出去的功能:
// contracts/MyERC115HolderContract.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
contract MyERC115HolderContract is ERC1155Holder {}
我们还可以使用 onERC1155Received
和 onERC1155BatchReceived
函数来实现更复杂的场景。
- 原文链接: docs.openzeppelin.com/co...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!