基于ERC1155标准实现一个代币合约

255 阅读4分钟

前言

本文主要依托于openzeppelin库实现一个ERC1155标准的代币,包含了合约的开发,测试,部署以及和ERC20标准,ERC721标准的区别和使用场景分析。

ERC20、ERC721、ERC1155标准

特点
  • ERC20标准:同质化、可分割性、标准化、兼容性、流通性;
  • ERC721标准:非同质化、不可分割性、所有权验证、元数据、稀缺性;
  • ERC1155标准:多功能性、效率、灵活性、批量操作、兼容性、安全性;
使用场景
  • ERC20标准:ERC-20代币广泛应用于ICO、代币化资产、DApp的实用代币、去中心化自治组织(DAO)的治理代币,以及作为在以太坊生态系统内转移价值的手段

  • ERC721标准:ERC-721代币被广泛应用于各类NFT项目中,包括数字艺术、游戏内资产、数字收藏品、虚拟地产等

  • ERC1155标准:ERC-1155代币标准提供了更为高效的代币管理方式,适用于需要在同一合约中管理多种资产的场景;

标准区别
  • ERC20标准:同质化代币,具有可分割性以及可替代性,类似于货币;
  • ERC721标准:非同质化代币,具有不可分割性以及不可替代性,类似于艺术品;
  • ERC1155标准:在一个合约中包装多个同质化与非同质化代币,提供了更灵活高效的搭配;
ERC1155合约

合约功能:铸造,销毁,批量销毁和铸造,转账、查看、验证等相关的功能;

// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.22;

import {ERC1155} from "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import {ERC1155Burnable} from "@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract GameToken is ERC1155, Ownable, ERC1155Burnable {
    constructor(address initialOwner)
        ERC1155("ipfs://QmcN49MKt4MbSXSGckAcpvFqtea43uuPD2tvmuER1mG67s")
        Ownable(initialOwner)
    {}

    function setURI(string memory newuri) public onlyOwner {
        _setURI(newuri);
    }

    function mint(address account, uint256 id, uint256 amount, bytes memory data)
        public
        onlyOwner
    {
        _mint(account, id, amount, data);
    }

    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        public
        onlyOwner
    {
        _mintBatch(to, ids, amounts, data);
    }
}

ERC1155合约测试
const {ethers,getNamedAccounts,deployments} = require("hardhat");
const { assert,expect } = require("chai");
describe("GameToken",async()=>{
    let GameToken;//合约
    let addr1;//第一个账户
    let addr2;//第二个账户
    let firstAccount//第一个账户
    let secondAccount//第二个账户;
    let mekadata="ipfs://QmcN49MKt4MbSXSGckAcpvFqtea43uuPD2tvmuER1mG67s"
    let mekadata1="ipfs://QmTL5CJsEUGGPxBi3VNYnFebGScrs8ANa5aeK98QGb5Prn"
    let tokenId=0;
    beforeEach(async()=>{
        await deployments.fixture(["gametoken"]);
        [addr1,addr2]=await ethers.getSigners();
        firstAccount=(await getNamedAccounts()).firstAccount;
        secondAccount=(await getNamedAccounts()).secondAccount;
        const GameTokenDeployment = await deployments.get("GameToken");
        GameToken = await ethers.getContractAt("GameToken",GameTokenDeployment.address);//已经部署的合约交互
    })
    describe("GameToken测试用例",async()=>{
        it("测试用例",async()=>{
            const owner = await GameToken.owner();
            console.log("owner",owner)
            //修改URI
            await GameToken.setURI(mekadata1);
            console.log(await GameToken.uri(0))
            //铸造说明如果数量是1是非同质化代币,数量大于1是同质化代币
            //铸造单个 参数说明:地址,tokenid,数量,唯一标识或其他参说
            await GameToken.mint(firstAccount,0,100,'0x11');
            console.log("tokenid 为0",await GameToken.balanceOf(firstAccount,0))
            //销毁单个 销毁tokenid为0的10个
            await GameToken.burn(firstAccount,0,10);
            //查看余额为90
            console.log('销毁后firstAccount查看余额',await GameToken.balanceOf(firstAccount,0))
            await GameToken.mint(firstAccount,1,1,'0x11');
            console.log("tokenid 为1",await GameToken.balanceOf(firstAccount,1))
            //返回的value为0说明不存在
            console.log("tokenid 为3不存在",await GameToken.balanceOf(firstAccount,3))
            //批量铸造
            await GameToken.mintBatch(firstAccount,[2,3,4],[200,300,400],'0x22');
            console.log(firstAccount)
            //addr数字和id的数组长度必须一致 返回余额的数组
            console.log("tokenid 为数组",await GameToken.balanceOfBatch([firstAccount,firstAccount,firstAccount],[2,3,4]))
            //批量销毁 tokenid为2,3,4的100个
            await GameToken.burnBatch(firstAccount,[2,3,4],[100,100,100]);
            //查看firstAccount余额为 100,200,300
            console.log('销毁后firstAccount查看余额',await GameToken.balanceOfBatch([firstAccount,firstAccount,firstAccount],[2,3,4]))
            //单个转账 
            //把tokenid为1的转给secondAccount
            await GameToken.safeTransferFrom(firstAccount,secondAccount,1,1,'0x');
            console.log("firstAccount的余额",await GameToken.balanceOf(firstAccount,1))
            console.log("secondAccount的余额",await GameToken.balanceOf(secondAccount,1))
            //批量转账
            //把tokenid为2,3的转给secondAccount
            await GameToken.safeBatchTransferFrom(firstAccount,secondAccount,[2,3],[100,200],'0x');
            console.log("firstAccount的余额",await GameToken.balanceOfBatch([firstAccount],[4]))
            console.log("secondAccount的余额",await GameToken.balanceOfBatch([secondAccount,secondAccount,secondAccount],[1,2,3]))
            console.log(await GameToken.uri(4))
        })
    })
})
ERC1155合约部署
module.exports = async function ({getNamedAccounts,deployments}) {
    const  firstAccount= (await getNamedAccounts()).firstAccount;
    const {deploy,log} = deployments;
    const GameToken=await deploy("GameToken",{
        from:firstAccount,
        args: [firstAccount],//参数
        log: true,
    })
    console.log("gametoken合约",GameToken.address)

}
module.exports.tags = ["all","gametoken"];
# 部署指令
# npx hardhat deploy
总结

以上就是基于ERC1155标准实现的综合代币合约,包含了开发、测试、部署流程,在测试文件中对合约单个或批量铸造、销毁、转移代币等相关功能进行相关测试。简单一句话:ERC1155代币就是ERC20和ERC721标准的综合使用。