猛戳订阅学习专栏🍁🍁 👉 solidity系列合约源码+解析 👈 🍁🍁
1 介绍
ERC-1155是一种以太坊代币标准,由Enjin首席技术官Witek Radomski等人开发,并于2018年6月17日将该标准的第一个版本放置到Ethereum的github库中。其主要可用于游戏行业中道具的生成和处理。该标准的提出对nft在游戏行业的应用起到了极大的提升。在一定程度上融合了ERC-20和ERC-721的功能。
其主要用途包括了发行同质化代币和非同质化代币。同质化代币即能像ERC-20一样发布各样的代币类型,但目前为止各钱包和交易所暂未支持ERC-1155标准代币;与此同时,ERC-1155标准更是能够发行NFT,且能基于一个合约同时发行多个NFT。伴随现在区块链游戏的大火,ERC-1155标准能够给基于以太坊的上的游戏开发运行提供大大的帮助。尤其在同质化道具的生成和处理上,该标准能够极大降低成本,提高效率。
2 主要功能
该标准定义了开发者可以按照标准要求使用一些简单的功能如:
- 设定NFT名称
- 设定NFT总量
- 设定NFT元数据资源URI
- 查看地址中NFT余额
- 查看NFT的归属地址
- 规范如何批准NFT转移
- 一定条件下,允许第三方地址使用某账户中的NFT
- 允许NFT和兼容ETH的智能合约及钱包服务等第三方个体兼容
以及一些简单的函数功能等等。
我们先来看一下标准的 ERC1155 标准的接口:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC1155 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(address indexed operator,address indexed from,address indexed to,uint256[] ids,uint256[] values);
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(address from,address to,uint256 id,uint256 amount,bytes calldata data) external;
function safeBatchTransferFrom(address from,address to,uint256[] calldata ids,uint256[] calldata amounts,bytes calldata data) external;}
下面我们解释一下上述每个接口函数的作用:
-
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value)
当任何NFT的所有权更改时,会触发此事件。 -
event TransferBatch(address indexed operator,address indexed from,address indexed to,uint256[] ids,uint256[] values);
当NFT发生批量转移时会触发该事件 -
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
所有者启用或禁用操作员时触发。(操作员可管理所有者所持有的NFTs) -
event URI(string value, uint256 indexed id);;
当给某个NFT绑定或更新URI资源文件时触发 -
function balanceOf(address account, uint256 id) external view returns (uint256);
查询某地址中指定tokenId的NFT的数量 -
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
查询给定的地址数组中的地址对应的tokenId数组中tokenId的NFT的数量 -
function safeTransferFrom(address from,address to,uint256 tokenId,bytes calldata data) external;
将NFT的所有权从一个地址转移到另一个地址,data : 附加额外的参数(没有指定格式),传递给接收者。 -
function setApprovalForAll(address operator, bool _approved) external;
启用或禁用第三方(操作员)管理msg.sender
所有资产,触发 ApprovalForAll 事件。 -
function getApproved(uint256 tokenId) external view returns (address operator);
获取单个NFT的授权地址 -
function safeBatchTransferFrom(address from,address to,uint256[] calldata ids,uint256[] calldata amounts,bytes calldata data) external;}
给指定的地址转移指定tokenId数组所对应的数量数组中的数量的NFT
3 代码示例
下面我们借助openzeppelin智能合约库来写一个ERC1155合约,来实现NFT的铸造、批量铸造、单个NFT的URI信息获取和批量URI获取等功能。
代码:
// SPDX-License-Identifier: MIT;
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract Test1155 is ERC1155 {
using Counters for Counters.Counter;
Counters.Counter private _tokenId;
mapping(uint => string) private _tokenURIs;
constructor() ERC1155("https://baseUrl.com") {}
function mint(address _recipient,uint _amount, string memory _tokenUrl) public returns(uint _mintTokenId){
require(bytes(_tokenUrl).length > 0,"The _tokenUrl must be have");
require(_amount > 0,"The _amount must be have");
_tokenId.increment();
uint newTokenId = _tokenId.current();
_mint(_recipient, newTokenId,_amount,"");
_tokenURIs[newTokenId] = _tokenUrl;
return newTokenId;
}
function mintBatch(address _recipient,uint[] memory _amounts,string[] memory _tokenUrls) public returns(uint[] memory _mintTokenIds){
require(_amounts.length > 0,"The _amounts must be have");
require(_tokenUrls.length > 0,"The _tokenUrls must be have");
require(_amounts.length == _tokenUrls.length,"The _tokenUrl length must be Equal _amounts length");
uint newTokenId;
uint[] memory returnTokenUrls = new uint[](_amounts.length);
for(uint256 i = 0; i < _amounts.length; i++){
_tokenId.increment();
newTokenId = _tokenId.current();
_tokenURIs[newTokenId] = _tokenUrls[i];
returnTokenUrls[i] = newTokenId;
}
_mintBatch(_recipient, returnTokenUrls,_amounts,"");
return returnTokenUrls;
}
function uri(uint256 _id) public view override returns(string memory _tokenUrl){
return _tokenURIs[_id];
}
function uriBatch(uint[] memory _tokenIds) public view returns(string[] memory _tokenUrls){
require(_tokenIds.length > 0,"The _tokenId must be have");
string[] memory returnTokenUrl = new string[](_tokenIds.length);
for(uint256 i=0;i<_tokenIds.length;i++){
returnTokenUrl[i] = _tokenURIs[_tokenIds[i]];
}
return returnTokenUrl;
}
}
4 部署测试
我们先部署好该1155合约
我们给当前地址铸造了5个tokenId相同的NFT,并给该NFT的URI资源设定为www.test.img,从交易的output中可以看到该tokenId为1
接下来我们查询到了该地址中tokenId为1的NFT数量为5个,代表着铸造成功!
然后我们查询到tokenId为1的NFT的URI地址为www.test.img,OK,没问题
我们可以根据该流程测试批量的mint和转账方法,这里就不再一一列举。