文章目录

  • ERC1155 介绍
    • 多代币标准
  • 前提条件
    • 代币标准:
    • ERC-20
    • ERC-721
  • 构建 ERC1155 代币合约
  • ERC-1155 的功能和特点:
    • 批量传输
    • 批量余额
    • 批量审批
    • 接收钩子
    • 支持非同质化代币
    • 安全转账规则

ERC1155 介绍

用于多种代币管理的合约标准接口。 单个部署的合约可以包括同质化代币、非同质化代币或其他配置(如半同质化代币)的任何组合。

多代币标准

ERC1155 的显着特点是它使用单个智能合约一次代表多个代币。这就是为什么它的balanceOf功能不同于 ERC20 和 ERC777 的原因:它有一个额外的id参数,用于您要查询余额的代币的标识符。

这类似于 ERC721 做事的方式,但在该标准中,代币id没有平衡的概念:每个代币都是不可替代的,存在或不存在。ERC721balanceOf函数是指一个账户有多少不同的代币,而不是每个有多少。另一方面,在 ERC1155 账户中,每个代币都有不同的余额id,不可替代的代币是通过简单地铸造其中一个来实现的。

这种方法可以为需要多个代币的项目节省大量气体。无需为每种代币类型部署新合约,单个 ERC1155 代币合约可以保存整个系统状态,从而降低部署成本和复杂性。

前提条件

为了更好地理解后面的内容,需要首先了解以下三方面知识:

代币标准:

以下是以太坊上最受欢迎的一些代币标准:

  • ERC20:可替代资产最广泛使用的代币标准,尽管受到其简单性的限制。

  • ERC721:不可替代代币的实际解决方案,通常用于收藏品和游戏。

  • ERC777:更丰富的可替代代币标准,支持新的用例并建立在过去的学习基础上。向后兼容 ERC20。

  • ERC1155:一种新的多代币标准,允许单个合约代表多个可替代和不可替代的代币,以及批量操作以提高气体效率。

ERC-20

ERC-20 提供了一个同质化代币的标准,换句话说,每个代币与另一个代币(在类型和价值上)完全相同。 例如,一个 ERC-20 代币就像以太币一样,意味着一个代币会并永远会与其他代币一样。

详情可了解:https://eips.ethereum.org/EIPS/eip-20

ERC-721

ERC-721 为 NFT 引入了一个标准,换言之, 这种类型的代币是独一无二的,并且可能与来自同一智能合约的另一代币有不同的价值,也许是因为它的年份、稀有性、甚至是它的观感。 稍等,看起来怎么样呢?

是的。 所有 NFTs 都有一个 uint256 变量,名为 tokenId,所以对于任何 ERC-721 合约,这对值contract address, tokenId 必须是全局唯一的。 也就是说,dApp 可以有一个“转换器”,该转换器使用 tokenId 输入和输出一些非常有趣的事物的图像, 例如僵尸、武器、技能或非常可爱的猫咪!

详情可了解:https://eips.ethereum.org/EIPS/eip-721

构建 ERC1155 代币合约

我们将使用 ERC1155 来跟踪我们游戏中的多个项目,每个项目都有自己独特的属性。我们将所有项目铸造给合约的部署者,然后我们可以将其转移给玩家。玩家可以自由地保留他们的代币或在他们认为合适的时候与其他人交易,就像他们对区块链上的任何其他资产一样!

为简单起见,我们将在构造函数中铸造所有项目,但您可以在合约中添加铸造功能,以便按需铸造给玩家。

请注意,对于我们的游戏物品,黄金是可替代的代币,而雷神之锤是不可替代的代币,因为我们只铸造了一个。

ERC1155合同包括可选的扩展IERC1155MetadataURI。这就是uri函数的来源:我们使用它来检索元数据 uri。

另请注意,与 ERC20 不同,ERC1155 缺少decimals字段,因为每个令牌都是不同的并且无法分区。

ERC-1155 的功能和特点:

  • 批量传输:通过一次合约调用传输多种资产。
  • 批量余额:在一次调用中获取多个资产的余额。
  • 批量审批:审批同一地址的所有代币。
  • Hook:接收代币的钩子函数。
  • 支持非同质化代币:如果供应量仅为 1,将其作为非同质化代币处理。
  • 安全转账规则:安全转账规则集。

批量传输

批量传输与常规 ERC-20 传输非常相似。 让我们看看常规的 ERC-20 与ERC-1155有什么区别:

// ERC-20function transferFrom(address from, address to, uint256 value) external returns (bool);// ERC-1155function safeBatchTransferFrom(address _from,address _to,uint256[] calldata _ids,uint256[] calldata _values,bytes calldata _data) external;

ERC-1155 中唯一的区别是我们将数值作为数组传递,我们也传递了数组 id。 例如,给出 ids=[3, 6, 13] 和 values=[100, 200, 5],传输结果将是

  1. 将 id 3 的 100 个代币从 _from 传输到 _to。
  2. 将 id 6 的 200 个代币从 _from 传输到 _to。
  3. 将 id 13 的 5 个代币从 _from 转移到 _to。

在 ERC-1155 中,我们只有 transferFrom,没有 transfer。 要像常规的 transfer一样使用它,只需将 “from” 地址设为调用该函数的地址。

例如以下操作:

我们可以将物品转移到玩家账户:

> NFTV2.safeTransferFrom(deployerAddress, playerAddress, 2, 1, "0x0")> NFTV2.balanceOf(playerAddress, 2)1> NFTV2.balanceOf(deployerAddress, 2)0

我们也可以批量转账到玩家账户,获取批量余额:

> NFTV2.safeBatchTransferFrom(deployerAddress, playerAddress, [0,1,3,4], [50,100,1,1], "0x0")> NFTV2.balanceOfBatch([playerAddress,playerAddress,playerAddress,playerAddress,playerAddress], [0,1,2,3,4])[50,100,1,1,1]

批量余额

相应的 ERC-20 balanceOf 调用同样具有支持批处理的相应函数。 同样,使用ERC-20 与 ERC-1155 做一个对比:

// ERC-20function balanceOf(address owner) external view returns (uint256);// ERC-1155function balanceOfBatch(address[] calldata _owners,uint256[] calldata _ids) external view returns (uint256[] memory);

调用余额查询更简单的是,我们可以在单次调用中获取多个余额。 参数中传递所有者账户数组和代币的 id 数组。

例如,对于给出的 _ids=[3, 6, 13] 和 _owners=[0xbeef…, 0x1337…, 0x1111…],返回值将为:

[balanceOf(0xbeef...),balanceOf(0x1337...),balanceOf(0x1111...)]

当然,我们也可以查询单个地址及token的余额

> NFTV2.balanceOf(deployerAddress,3)1000000000

批量审批

// ERC-1155function setApprovalForAll(address _operator,bool _approved) external;function isApprovedForAll(address _owner,address _operator) external view returns (bool);

审批过程与 ERC-20 略有不同。 这里不是批准特定金额,而是通过 setApprovalForall 函数设置操作帐户为已批准或未批准。

查看当前的审批状态可以通过 isApprovedForall 完成。 如你所见,要么全部批准,要么不批准。 不能定义要批准代币的数量,甚至代币类型。

这是考虑到简洁性而故意设计的。 你只能批准一个地址的所有代币。

接收钩子

function onERC1155BatchReceived(address _operator,address _from,uint256[] calldata _ids,uint256[] calldata _values,bytes calldata _data) external returns(bytes4);

基于 EIP-165 的协议支持,ERC-1155 只支持智能合约的接收钩子函数。 钩子函数必须返回一个事先预定义的 4 字节值,这个值被指定为:

bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))

当接收合约返回这一值时,意味着合约知道如何处理 ERC-1155 代币并接受转账。 太好了,代币不会再卡在合约中了!

使用时的一个关键区别safeTransferFrom是令牌转移到其他合约可能会恢复并显示以下消息:

ERC1155: transfer to non ERC1155Receiver implementer

这是一件好事!这意味着接收合约尚未将自己注册为了解 ERC1155 协议,因此禁用向其传输以防止代币被永久锁定。例如,Golem 合约目前持有超过 35万个GNT代币,价值数万美元,并且缺乏将它们从那里取出的方法。几乎每个 ERC20 支持的项目都会发生这种情况,通常是由于用户错误。

为了让我们的合约接收 ERC1155 代币,我们可以继承ERC1155Holder为我们处理注册的便利合约。尽管我们需要记住实现功能以允许将代币从我们的合约中转移出来:

支持非同质化代币

当供应量仅为 1 时,代币本质上就是一个非同质化的代币 (NFT)。 按照 ERC-721 的标准,您可以定义一个元数据网址。 客户端可以读取并修改网址,请参阅这里。

安全转账规则

在前面的解释中,我们已经提到过一些安全转账规则。 现在我们来看一下最重要的规则:

  1. 调用者必须获得批准才能从 _from 的账户地址消费代币,或者调用者账户地址必须与 _from 的账户地址相同。
  2. 在以下情况下,转账调用将回退
  • _to 地址为 0;
  • _ids 的长度与 _values 的长度不同;
  • _ids 中代币持有者的任何余额低于发送给接收者的相应 _value 金额。
  • 出现任何其他错误。

注意:包括钩子在内的所有批处理函数也均作为非批处理的版本存在。 这样做是为了提高燃料效率,考虑到只转移一种资产可能仍然是最常用的方式。 简洁起见,我们没有在这里介绍这些非批处理的版本,包括安全转账规则。 名称是相同的,只需移除 ‘Batch’。

参考文档:
ERC-1155 Github 代码库:https://github.com/enjin/erc-1155
ERC-1155 Openzepelin 文档:https://docs.openzeppelin.com/contracts/3.x/erc1155
EIP-1155 多代币标准:https://eips.ethereum.org/EIPS/eip-1155
EIP-1155 以太坊官网文档:https://ethereum.org/zh/developers/docs/standards/tokens/erc-1155/