草庐IT

这篇文章,让你了解ERC-1155 多代币标准协议

杰哥的技术杂货铺 2024-02-07 原文

文章目录

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-20
function transferFrom(address from, address to, uint256 value) external returns (bool);

// ERC-1155
function 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-20
function balanceOf(address owner) external view returns (uint256);

// ERC-1155
function 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-1155
function 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/

有关这篇文章,让你了解ERC-1155 多代币标准协议的更多相关文章

  1. ruby - 将 spawn() 的标准输出/标准错误重定向到 Ruby 中的字符串 - 2

    我想使用spawn(针对多个并发子进程)在Ruby中执行一个外部进程,并将标准输出或标准错误收集到一个字符串中,其方式类似于使用Python的子进程Popen.communicate()可以完成的操作。我尝试将:out/:err重定向到一个新的StringIO对象,但这会生成一个ArgumentError,并且临时重新定义$stdxxx会混淆子进程的输出。 最佳答案 如果你不喜欢popen,这是我的方法:r,w=IO.pipepid=Process.spawn(command,:out=>w,:err=>[:child,:out])

  2. ruby-on-rails - 标准化文件名的字符串,删除重音和特殊字符 - 2

    我正在尝试找到一种方法来规范化字符串以将其作为文件名传递。到目前为止我有这个:my_string.mb_chars.normalize(:kd).gsub(/[^\x00-\x7F]/n,'').downcase.gsub(/[^a-z]/,'_')但第一个问题:-字符。我猜这个方法还有更多问题。我不控制名称,名称字符串可以有重音符、空格和特殊字符。我想删除所有这些,用相应的字母('é'=>'e')替换重音符号,并将其余的替换为'_'字符。名字是这样的:“Prélèvements-常规”“健康证”...我希望它们像一个没有空格/特殊字符的文件名:“prelevements_routin

  3. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  4. ruby - 了解在 Ruby 中与 lambda 一起使用的 inject 行为 - 2

    我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject

  5. ruby-on-rails - 如何测试自己对 Ruby/ROR 的了解? - 2

    是否有self验证的问题列表。看着那个,我可以确定我知道。我应该复习一下。在学习的过程中,我列了一个这样的list,但它只包含我在某处听说过的项目。我需要一段时间才能找到新的东西。 最佳答案 以下是针对ruby​​和Rails的一些测试列表。证书名称:RubyonRails谁提供:oDeskIncorporation认证费用:免费网站:https://www.odesk.com/tests/985?pos=0证书名称:RubyonRails提供者:Techgig.com(TimesBusinessSolutionsLimited(T

  6. Ruby:标准递归模式 - 2

    我经常迷上ruby​​的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情

  7. ruby-on-rails - 使用 Ruby 标准 Logger 每天只创建一个日志 - 2

    我正在使用ruby​​标准记录器,我想要每天轮换一次,所以在我的代码中我有:Logger.new("#{$ROOT_PATH}/log/errors.log",'daily')它运行完美,但它创建了两个文件errors.log.20130217和errors.log.20130217.1。如何强制它每天只创建一个文件? 最佳答案 您的代码对于长时间运行的应用程序是正确的。发生的事情是您在给定的一天多次运行代码。第一次运行时,Ruby会创建一个日志文件“errors.log”。当日期改变时,Ruby将文件重命名为“errors.log

  8. ruby-on-rails - 了解 "attribute_will_change!"方法 - 2

    我想覆盖store_accessor的getter。可以查到here.代码在这里:#Fileactiverecord/lib/active_record/store.rb,line74defstore_accessor(store_attribute,*keys)keys=keys.flatten_store_accessors_module.module_evaldokeys.eachdo|key|define_method("#{key}=")do|value|write_store_attribute(store_attribute,key,value)enddefine_met

  9. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  10. 用于从 Open3.popen3 标准输出中提取值的正则表达式 - 2

    如何获取外部命令的输出并从中提取值?我有这样的东西:stdin,stdout,stderr,wait_thr=Open3.popen3("#{path}/foobar",configfile)if/exit0/=~wait_thr.value.to_srunlog.puts("Foobarexitednormally.\n")puts"Testcompleted."someoutputvalue=stdout.read("TX.*\s+(\d+)\s+")puts"Outputvalue:"+someoutputvalueend我没有在标准输出上使用正确的方法,因为Ruby告诉我它不能

随机推荐