solidity实现ERC1155多代币标准

2023-12-04 17:44

本文主要是介绍solidity实现ERC1155多代币标准,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 1、NFT - 维基百科
  • 2、IERC1155MetadataURI
  • 3、IERC1155Receiver
  • 4、IERC1155
  • 5、ERC1155
  • 6、NFT1155
  • 7、开源地址

1、NFT - 维基百科

ERC-1155 标准于2018年6月由Witek Radomski、Andrew Cooke、Philippe Castonguay、James Therien、Eric Binet及Ronan Sandford提出。此标准可针对单一应用合约,提供同质代币、非同质代币(用ERC-1155建构ERC-721资产)及其他结构类型(例如半同质代币,semi-fungible tokens)的多元组合。相较于ERC-721每创立一个代币ID就对应一个单独智能合约资产,在ERC-1155多元代币标准下,每个代币ID可以代表一系列不同类型的资产,并附加量化区块以标示钱包中各类型资产的数量;同类型资产可以互换,要转让多少数量也可以。
ERC-1155 标准下的NFT结构上更有弹性:拥有元数据、供应量与其他属性;新功能包括:可一次传输多种代币类型以节省交易成本、也可同时进行多个代币交易(托管/原子交换)而无需逐一批准每个合约、可在单一应用合约中注明并混搭多种FT、NFT及SFT。

2、IERC1155MetadataURI

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;// ERC1155的可选接口,加入了uri()函数查询元数据
interface IERC1155MetadataURI  {// 返回第`id`种类代币的URIfunction uri(uint256 id) external view returns (string memory);
}

3、IERC1155Receiver

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;import "./IERC165.sol";interface IERC1155Receiver is IERC165 {// 接受ERC1155安全转账`safeTransferFrom`     function onERC1155Received(address operator,address from,uint256 id,uint256 value,bytes calldata data) external returns (bytes4);// 接受ERC1155批量安全转账`safeBatchTransferFrom` function onERC1155BatchReceived(address operator,address from,uint256[] calldata ids,uint256[] calldata values,bytes calldata data) external returns (bytes4);
}

4、IERC1155

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;import "./IERC165.sol";// https://eips.ethereum.org/EIPS/eip-1155[EIP].
interface IERC1155 is IERC165 {// 单类代币转账事件event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);// 批量代币转账事件, ids和values为转账的代币种类和数量数组event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);// 批量授权事件, 当`account`将所有代币授权给`operator`时释放event ApprovalForAll(address indexed account, address indexed operator, bool approved);// 当`id`种类的代币的URI发生变化时释放,`value`为新的URIevent URI(string value, uint256 indexed id);// 持仓查询,返回`account`拥有的`id`种类的代币的持仓量function balanceOf(address account, uint256 id) external view returns (uint256);// 批量持仓查询,`accounts`和`ids`数组的长度要想等。function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);// 批量授权,将调用者的代币授权给`operator`地址。释放{ApprovalForAll}事件.function setApprovalForAll(address operator, bool approved) external;// 批量授权查询,如果授权地址`operator`被`account`授权,则返回`true`function isApprovedForAll(address account, address operator) external view returns (bool);// 安全转账,将`amount`单位`id`种类的代币从`from`转账给`to`.  释放{TransferSingle}事件.function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;// 批量安全转账, 释放{TransferBatch}事件function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
}

5、ERC1155

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;import "./IERC1155.sol";
import "./IERC1155Receiver.sol";
import "./IERC1155MetadataURI.sol";
import "./Address.sol";
import "./Strings.sol";
import "./IERC165.sol";// ERC1155多代币标准 https://eips.ethereum.org/EIPS/eip-1155
contract ERC1155 is IERC165, IERC1155, IERC1155MetadataURI {using Address for address; using Strings for uint256; // Token名称string public name;// Token代号string public symbol;// 代币种类id 到 账户account 到 余额balances 的映射mapping(uint256 => mapping(address => uint256)) private _balances;// address 到 授权地址 的批量授权映射mapping(address => mapping(address => bool)) private _operatorApprovals;// 构造函数,初始化`name` 和`symbol`, uri_constructor(string memory name_, string memory symbol_) {name = name_;symbol = symbol_;}function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {returninterfaceId == type(IERC1155).interfaceId ||interfaceId == type(IERC1155MetadataURI).interfaceId ||interfaceId == type(IERC165).interfaceId;}// 持仓查询 实现IERC1155的balanceOf,返回account地址的id种类代币持仓量。function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {require(account != address(0), "ERC1155: address zero is not a valid owner");return _balances[id][account];}// @dev 批量持仓查询   function balanceOfBatch(address[] memory accounts, uint256[] memory ids) public view virtual override returns (uint256[] memory) {require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");uint256[] memory batchBalances = new uint256[](accounts.length);for (uint256 i = 0; i < accounts.length; ++i) {batchBalances[i] = balanceOf(accounts[i], ids[i]);}return batchBalances;}//  批量授权,调用者授权operator使用其所有代币function setApprovalForAll(address operator, bool approved) public virtual override {require(msg.sender != operator, "ERC1155: setting approval status for self");_operatorApprovals[msg.sender][operator] = approved;emit ApprovalForAll(msg.sender, operator, approved);}// 查询批量授权.function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {return _operatorApprovals[account][operator];}// 安全转账,将`amount`单位的`id`种类代币从`from`转账到`to`function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) public virtual override {address operator = msg.sender;// 调用者是持有者或是被授权require(from == operator || isApprovedForAll(from, operator),"ERC1155: caller is not token owner nor approved");require(to != address(0), "ERC1155: transfer to the zero address");// from地址有足够持仓uint256 fromBalance = _balances[id][from];require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");// 更新持仓量unchecked {_balances[id][from] = fromBalance - amount;}_balances[id][to] += amount;// 释放事件emit TransferSingle(operator, from, to, id, amount);// 安全检查_doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);    }// 批量安全转账,将`amounts`数组单位的`ids`数组种类代币从`from`转账到`to`function safeBatchTransferFrom(address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public virtual override {address operator = msg.sender;// 调用者是持有者或是被授权require(from == operator || isApprovedForAll(from, operator),"ERC1155: caller is not token owner nor approved");require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");require(to != address(0), "ERC1155: transfer to the zero address");// 通过for循环更新持仓  for (uint256 i = 0; i < ids.length; ++i) {uint256 id = ids[i];uint256 amount = amounts[i];uint256 fromBalance = _balances[id][from];require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");unchecked {_balances[id][from] = fromBalance - amount;}_balances[id][to] += amount;}emit TransferBatch(operator, from, to, ids, amounts);// 安全检查_doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);    }// 锻造function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {require(to != address(0), "ERC1155: mint to the zero address");address operator = msg.sender;_balances[id][to] += amount;emit TransferSingle(operator, address(0), to, id, amount);_doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);}// 批量铸造function _mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) internal virtual {require(to != address(0), "ERC1155: mint to the zero address");require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");address operator = msg.sender;for (uint256 i = 0; i < ids.length; i++) {_balances[ids[i]][to] += amounts[i];}emit TransferBatch(operator, address(0), to, ids, amounts);_doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data);}// 销毁function _burn(address from, uint256 id, uint256 amount) internal virtual {require(from != address(0), "ERC1155: burn from the zero address");address operator = msg.sender;uint256 fromBalance = _balances[id][from];require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");unchecked {_balances[id][from] = fromBalance - amount;}emit TransferSingle(operator, from, address(0), id, amount);}// 批量销毁function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual {require(from != address(0), "ERC1155: burn from the zero address");require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");address operator = msg.sender;for (uint256 i = 0; i < ids.length; i++) {uint256 id = ids[i];uint256 amount = amounts[i];uint256 fromBalance = _balances[id][from];require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");unchecked {_balances[id][from] = fromBalance - amount;}}emit TransferBatch(operator, from, address(0), ids, amounts);}// 安全转账检查function _doSafeTransferAcceptanceCheck( address operator, address from, address to,uint256 id, uint256 amount, bytes memory data) private {if (to.isContract()) {try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {if (response != IERC1155Receiver.onERC1155Received.selector) {revert("ERC1155: ERC1155Receiver rejected tokens");}} catch Error(string memory reason) {revert(reason);} catch {revert("ERC1155: transfer to non-ERC1155Receiver implementer");}}}// ERC1155的批量安全转账检查function _doSafeBatchTransferAcceptanceCheck( address operator, address from, address to,uint256[] memory ids, uint256[] memory amounts, bytes memory data) private {if (to.isContract()) {try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (bytes4 response) {if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {revert("ERC1155: ERC1155Receiver rejected tokens");}} catch Error(string memory reason) {revert(reason);} catch {revert("ERC1155: transfer to non-ERC1155Receiver implementer");}}}// 返回id种类代币的uri,存储metadata,类似ERC721的tokenURI.function uri(uint256 id)  public view virtual override returns (string memory) {string memory baseURI = _baseURI();return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, id.toString())) : "";}// 计算{uri}的BaseURI,uri就是把baseURI和tokenId拼接在一起,需要开发重写.function _baseURI() internal view virtual returns (string memory) {return "";}
}

6、NFT1155

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;import "./ERC1155.sol"; contract NFT1155 is ERC1155 {uint256 constant MAX_ID = 10000;constructor() ERC1155("NFT1155", "NFT1155"){}function _baseURI() internal pure override returns (string memory) {return "ipfs://QmcPGA3kecSMfHcv8i6wpgB2RkPA1FSVqu6AZY3rKNmxuj/";}function mint(address to, uint256 id, uint256 amount) external {require(id < MAX_ID, "id overflow");_mint(to, id, amount, "");}function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts) external {for(uint256 i = 0; i < ids.length;i++){require(ids[i] < MAX_ID, "id overflow");}_mintBatch(to, ids, amounts, "");}
}

测试运行:
在这里插入图片描述

7、开源地址

gitee 开源地址。


这篇关于solidity实现ERC1155多代币标准的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/454345

相关文章

基于 HTML5 Canvas 实现图片旋转与下载功能(完整代码展示)

《基于HTML5Canvas实现图片旋转与下载功能(完整代码展示)》本文将深入剖析一段基于HTML5Canvas的代码,该代码实现了图片的旋转(90度和180度)以及旋转后图片的下载... 目录一、引言二、html 结构分析三、css 样式分析四、JavaScript 功能实现一、引言在 Web 开发中,

SpringBoot中使用Flux实现流式返回的方法小结

《SpringBoot中使用Flux实现流式返回的方法小结》文章介绍流式返回(StreamingResponse)在SpringBoot中通过Flux实现,优势包括提升用户体验、降低内存消耗、支持长连... 目录背景流式返回的核心概念与优势1. 提升用户体验2. 降低内存消耗3. 支持长连接与实时通信在Sp

Conda虚拟环境的复制和迁移的四种方法实现

《Conda虚拟环境的复制和迁移的四种方法实现》本文主要介绍了Conda虚拟环境的复制和迁移的四种方法实现,包括requirements.txt,environment.yml,conda-pack,... 目录在本机复制Conda虚拟环境相同操作系统之间复制环境方法一:requirements.txt方法

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

HTML5 getUserMedia API网页录音实现指南示例小结

《HTML5getUserMediaAPI网页录音实现指南示例小结》本教程将指导你如何利用这一API,结合WebAudioAPI,实现网页录音功能,从获取音频流到处理和保存录音,整个过程将逐步... 目录1. html5 getUserMedia API简介1.1 API概念与历史1.2 功能与优势1.3

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja