id:BSN_2021

公众号:BSN研习社

目标:跟大家一块去研究下1155标准中提供的案例
章节流程:

1.核心文件

2.核心方法

3.汇总

在eip-1155中看到如下图所示一段内容,并提供了一个案例,因此今天跟大家去研究一下内部的实现细节。

一、核心文件

其主要涉及两个文件ERC1155MixedFungibleMintable.solERC1155MixedFungible .sol,如下:

1.文件ERC1155MixedFungible .sol内容如下:

pragma solidity ^0.5.0;import "./ERC1155.sol";/**@dev Extension to ERC1155 for Mixed Fungible and Non-Fungible Items supportThe main benefit is sharing of common type information, just like you do whencreating a fungible id.
*/
contract ERC1155MixedFungible is ERC1155 {// Use a split bit implementation. Store the type in the upper 128 bits..// 十进制:115792089237316195423570985008687907852929702298719625575994209400481361428480// 十六进制:ffffffffffffffffffffffffffffffff00000000000000000000000000000000// 二进制:// 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111// 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000uint256 public constant TYPE_MASK = uint256(uint128(~0)) << 128;// ..and the non-fungible index in the lower 128// 十进制:340282366920938463463374607431768211455// 十六进制:ffffffffffffffffffffffffffffffff// 二进制: // 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000// 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111uint256 public constant NF_INDEX_MASK = uint128(~0);// The top bit is a flag to tell if this is a NFI.// 十进制: 57896044618658097711785492504343953926634992332820282019728792003956564819968// 十六进制: 8000000000000000000000000000000000000000000000000000000000000000// 二进制:// 10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000// 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000uint256 public constant TYPE_NF_BIT = 1 << 255;mapping (uint256 => address) nfOwners;// Only to make code clearer. Should not be functionsfunction isNonFungible(uint256 _id) public pure returns(bool) {return _id & TYPE_NF_BIT == TYPE_NF_BIT;}function isFungible(uint256 _id) public pure returns(bool) {return _id & TYPE_NF_BIT == 0;}function getNonFungibleIndex(uint256 _id) public pure returns(uint256) {return _id & NF_INDEX_MASK;}function getNonFungibleBaseType(uint256 _id) public pure returns(uint256) {return _id & TYPE_MASK;}function isNonFungibleBaseType(uint256 _id) public pure returns(bool) {// A base type has the NF bit but does not have an index.return (_id & TYPE_NF_BIT == TYPE_NF_BIT) && (_id & NF_INDEX_MASK == 0);}function isNonFungibleItem(uint256 _id) public pure returns(bool) {// A base type has the NF bit but does has an index.return (_id & TYPE_NF_BIT == TYPE_NF_BIT) && (_id & NF_INDEX_MASK != 0);}function ownerOf(uint256 _id) public view returns (address) {return nfOwners[_id];}// overridefunction safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external {require(_to != address(0x0), "cannot send to zero address");require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers.");if (isNonFungible(_id)) {require(nfOwners[_id] == _from);nfOwners[_id] = _to;// You could keep balance of NF type in base type id like so:// uint256 baseType = getNonFungibleBaseType(_id);// balances[baseType][_from] = balances[baseType][_from].sub(_value);// balances[baseType][_to]   = balances[baseType][_to].add(_value);} else {balances[_id][_from] = balances[_id][_from].sub(_value);balances[_id][_to]   = balances[_id][_to].add(_value);}emit TransferSingle(msg.sender, _from, _to, _id, _value);if (_to.isContract()) {_doSafeTransferAcceptanceCheck(msg.sender, _from, _to, _id, _value, _data);}}// overridefunction safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external {require(_to != address(0x0), "cannot send to zero address");require(_ids.length == _values.length, "Array length must match");// Only supporting a global operator approval allows us to do only 1 check and not to touch storage to handle allowances.require(_from == msg.sender || operatorApproval[_from][msg.sender] == true, "Need operator approval for 3rd party transfers.");for (uint256 i = 0; i < _ids.length; ++i) {// Cache value to local variable to reduce read costs.uint256 id = _ids[i];uint256 value = _values[i];if (isNonFungible(id)) {require(nfOwners[id] == _from);nfOwners[id] = _to;} else {balances[id][_from] = balances[id][_from].sub(value);balances[id][_to]   = value.add(balances[id][_to]);}}emit TransferBatch(msg.sender, _from, _to, _ids, _values);if (_to.isContract()) {_doSafeBatchTransferAcceptanceCheck(msg.sender, _from, _to, _ids, _values, _data);}}function balanceOf(address _owner, uint256 _id) external view returns (uint256) {if (isNonFungibleItem(_id))return nfOwners[_id] == _owner ? 1 : 0;return balances[_id][_owner];}function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory) {require(_owners.length == _ids.length);uint256[] memory balances_ = new uint256[](_owners.length);for (uint256 i = 0; i < _owners.length; ++i) {uint256 id = _ids[i];if (isNonFungibleItem(id)) {balances_[i] = nfOwners[id] == _owners[i] ? 1 : 0;} else {balances_[i] = balances[id][_owners[i]];}}return balances_;}
}

2.文件ERC1155MixedFungibleMintable.sol内容如下:


pragma solidity ^0.5.0;import "./ERC1155MixedFungible.sol";/**@dev Mintable form of ERC1155Shows how easy it is to mint new items
*/
contract ERC1155MixedFungibleMintable is ERC1155MixedFungible {uint256 nonce;mapping (uint256 => address) public creators;mapping (uint256 => uint256) public maxIndex;modifier creatorOnly(uint256 _id) {require(creators[_id] == msg.sender);_;}// This function only creates the type.function create(string calldata _uri,bool   _isNF)external returns(uint256 _type) {// Store the type in the upper 128 bits_type = (++nonce << 128);// Set a flag if this is an NFI.if (_isNF)_type = _type | TYPE_NF_BIT;// This will allow restricted access to creators.creators[_type] = msg.sender;// emit a Transfer event with Create semantic to help with discovery.emit TransferSingle(msg.sender, address(0x0), address(0x0), _type, 0);if (bytes(_uri).length > 0)emit URI(_uri, _type);}function mintNonFungible(uint256 _type, address[] calldata _to) external creatorOnly(_type) {// No need to check this is a nf type rather than an id since// creatorOnly() will only let a type pass through.require(isNonFungible(_type));// Index are 1-based.uint256 index = maxIndex[_type] + 1;maxIndex[_type] = _to.length.add(maxIndex[_type]);for (uint256 i = 0; i < _to.length; ++i) {address dst = _to[i];uint256 id  = _type | index + i;nfOwners[id] = dst;// You could use base-type id to store NF type balances if you wish.// balances[_type][dst] = quantity.add(balances[_type][dst]);emit TransferSingle(msg.sender, address(0x0), dst, id, 1);if (dst.isContract()) {_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, dst, id, 1, '');}}}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];// Grant the items to the callerbalances[_id][to] = quantity.add(balances[_id][to]);// Emit the Transfer/Mint event.// the 0x0 source address implies a mint// It will also provide the circulating supply info.emit TransferSingle(msg.sender, address(0x0), to, _id, quantity);if (to.isContract()) {_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, to, _id, quantity, '');}}}
}

二、核心方法

先看一下几个内置的状态变量,如下:
TYPE_NF_BIT= 100xxx000 000xxx000
TYPE_MASK= 111xxx111 000xxx000
NF_INDEX_MASK=000xxx000 111xxx111

主要的几个方法,详解如下:

  1. 创建类型 create(string calldata _uri,bool _isNF):

    • 关键逻辑:首先,通过nonce自增然后左移128位生成_type 类别唯一标识(tokenid)。接下来,判断是否是非同质化,是则与TYPE_NF_BIT按位或(注:其结果最高位标识为1开头),否则直接返回_type。

    • 示例:前128位,后128位。
      nft_type:100xxx001 000xxx000;
      ft_type: 000xxx001 000xxx000;

  2. 铸造非同质化 mintNonFungible(uint256 _type, address[] calldata _to)

    • 关键逻辑:首先,要求_type符合非同质化条件,即判断_type按位与TYPE_NF_BIT是否等于TYPE_NF_BIT。接下来,获取最新的索引值index,然后根据规则(将_type与index+i按位或)生成唯一标识,并与对应的address进行映射。

    • 示例:
      非同质化条件:100xxx001 000xxx000 & TYPE_NF_BIT == TYPE_NF_BIT ;
      生成tokenId的规则:id = _type | index +i。即 100xxx001 000xxx000 | 001 => 100xxx001 000xxx001 ;

  1. 铸造同质化mintFungible(uint256 _id, address[] calldata _to, uint256[] calldata _quantities)

    • 关键逻辑:首先,要求符合同质化条件,即判断_type按位与TYPE_NF_BIT是否等于0;接下来,计算最新的数量,并与对应的address进行映射。

    • 示例:
      同质化条件:000xxx001 000xxx000 & TYPE_NF_BIT == 0;

  2. 转移 safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data)

    • 关键逻辑:根据_id判断是否是非同质化标识,即判断_type按位与TYPE_NF_BIT是否等于TYPE_NF_BIT,然后返回对应的结果。

  3. 获取余额balanceOf(address _owner, uint256 _id) external view returns (uint256)

    • 关键逻辑:根据_id判断是否是非同质化标识,即判断_id按位与TYPE_NF_BIT是否等于TYPE_NF_BIT,并且_id按位与NF_INDEX_MASK 等于零。然后返回对应的结果。注:非同质化的数量为0或1;

三、汇总

关键的几个方法看完后,可以发现技术上没有太大的难度,主要是运用了标识位拆分(Split ID bits)以及位运算进行巧妙的设计。即将tokenid uint256分为两部分(前128位和后128位)。当非同质化时前128位标识类型,后面128为代表索引或id,即<uint128: base token id><uint128: index of non-fungible>。当同质化时前128位标识id,后128位为零,即<uint128: base token id><uint128: zero>

通俗点的来说,当调用create方法时,非同质化生成的为类别(或系列)标识,然后再生成该类别下的唯一标识,即nf-tokenID。同质化生成的即为唯一标识,即f-tokenID。


引用资源地址:
https://eips.ethereum.org/EIPS/eip-1155
https://github.com/enjin/erc-1155

探索如何在武汉链(基于ETH)的一个合约中实现同质化与非同质化功能相关推荐

  1. 链游知识01:同质化和非同质化资产标准是什么?

    前言:链游知识是链游玩家专门推出的针对入门玩家的游戏知识科普,从小白到高玩,看链游玩家就够了. 区块链游戏诞生于17年末18年初,至今也不到2年的时间,虽然目前已经有很多团队和项目方在做区块链游戏了, ...

  2. 基于SpringBoot开发一个Restful服务,实现增删改查功能

    点击上方"方志朋",选择"置顶公众号" 技术文章第一时间送达! 作者:虚无境 cnblogs.com/xuwujing/p/8260935.html 前言 在去 ...

  3. springboot增删改查案例_大神基于SpringBoot开发一个Restful服务,实现增删改查功能...

    前言 在去年的时候,在各种渠道中略微的了解了SpringBoot,在开发web项目的时候是如何的方便.快捷.但是当时并没有认真的去学习下,毕竟感觉自己在Struts和SpringMVC都用得不太熟练. ...

  4. 基于java设计一个可视化中智数计算器

    Smarandache在1995年首次描述了中智学,并提出了一种重要的数学机制,称为中智集理论,用以处理模糊及其各种类型无法处理的不精确.不确定和不确定问题.NS是由真实程度(t).不确定程度(i)和 ...

  5. HashSpace:探索无国界社交生态链的价值潜力

    HashSpace是由HashSpace.N.V库拉索基金会发起.William Hill等数家国际上市公司领投.多家全球数字经济行业协会共同参与的无国界社交应用生态链,致力于为全球用户建设一个开放. ...

  6. 区块链学习笔记21——智能合约

    二十一.智能合约 智能合约是以太坊的精髓,也是以太坊和比特币一个最大的区别. 什么是智能合约? 智能合约的本质是运行在区块链上的一段代码,代码的逻辑定义了智能合约的内容 智能合约的账户保存了合约当前的 ...

  7. 区块链(七)智能合约(Smart Contract)

    1. 智能合约(Smart Contract) 智能合约(Smart Contract),是一种旨在以信息化方式传播.验证或执行合同的计算机协议.智能合约允许在没有第三方的情况下进行可信交易,这些交易 ...

  8. BSN武汉链对接说明

    项目说明 我们项目需要把ETH合约功能迁移到国内链上来, 然后基于开发成本等多方面考虑, 最终选择了BSN-武汉链接入, 相关的BSN文档: BSN-文档地址 对接说明 1. 创建BSN帐号 注册并登 ...

  9. BSN开放联盟链“武汉链”新版浏览器wuscan.io正式上线发布

    11月21日,武汉链新版区块浏览器正式上线.同时,旧版武汉链浏览器将继续保持运行. 新版武汉链区块浏览器地址: https://wuscan.io 旧版武汉链区块浏览器地址: http://explo ...

最新文章

  1. 南昌大学计算机控制,南昌大学计算机控制实验报告数/模转换实验..doc
  2. 数据结构:栈--计算表达式
  3. Qt Creator与调试器进行交互
  4. TCP传输-出现差错的解决办法
  5. ws5102怎么设置虚拟服务器,【华为路由器WS5102怎么设置开双频】规格参数|限速|APP|配置|功耗_摘要频道_什么值得买...
  6. 收集sqlite常见问题
  7. 手机上python编程工具3和3h有区别吗_Python 高级 3
  8. linq to js使用汇总
  9. javascript乘法和加法_前端基础:JavaScript
  10. 设计模式1-简单工厂模式
  11. 刚接触Cisco认证:CCNA学习经验
  12. storyboard用代码跳转
  13. 利用user-agent取得浏览器版本号
  14. Vue3+elementplus搭建通用管理系统实例五:后台主页搭建上
  15. Matlab中的Smith 预估器
  16. 静态函数和非静态函数的区别(静态方法和非静态方法)
  17. Ae 内置效果控件(合集)
  18. BGP路由器协议排错教程:BGP 对等体翻动问题
  19. 程序员,这12个问题让经理比你痛苦多了
  20. python找出3或者5的倍数_python – 3和5的倍数之和

热门文章

  1. 关于SQL模糊查询日期时间的方法
  2. 均值场博弈_平均场博弈论数值算法之系数法
  3. 企业绩效考核的有效性研究
  4. 劳动工资电子台账操作流程
  5. 浏览器尺寸判断(兼容标准及低版本ie浏览器)
  6. 经销商网上下单系统|移讯云企业订货管理软件解决
  7. 工银e生活开发脱坑日志(2)AES解码后乱码
  8. 解决java.sql.SQLException: Field ‘id‘ doesn‘t have a default value问题
  9. 方阵的转置二次方三次方
  10. selenium最大化窗口,刷新网页,及退出