使用Remix,15 分钟部署使用ERC 1155 智能合约

一、ERC1155 和ERC721 有什么区别

开始介绍ERC1155 智能合约的写法之前,我觉得先要说说ERC1155 和ERC721 到底有什么区别。简单来说,ERC1155 是ERC721 的升级版,ERC1155 在ERC721 的基础上,主要增加或改善了如下功能:

  • 同时支持可替换代币(同质化代币)和不可替换代币(非同质化代币);
  • 批量转账: 仅需要一次智能合约调用,就可以转账多种代币资产;
  • 批量查询余额:一次智能合约调用可以查询多种代币余额资料;
  • 批量授权:一次智能合约调用可以向指定地址授权多种代币的使用权;

用再简单一些的人话来讲,就是一张ERC1155 智能合约,里面可以同时包含类似USDT 这种代币,和类似MekaVerse无聊猿等这种独一无二的NFT 代币。

另外,传统的ERC721 合约,如果要转移NFT,必须一个一个操作,没有办法做到批量转账。

而ERC1155,则宛如加入了类似「购物车」的概念,可以一堆代币一次过转移。

不要小看这个「批量」功能,要知道每次和区块链交互,都要消耗gas,如果有某些应用场景需要大量,频繁转移资产,那ERC1155 相比ERC721 则能节约大量的gas 成本。

我们可以试想一下,假如现在想要创作一款区块链游戏,里面有类似USDT 的可替换同质化代币以进行金融操作,也需要有各种游戏装备,英雄角色等独一无二不可替换代币来进行游戏,这两种代币也需要透过一定的机制进行交易互换,这个场景,使用ERC1155 则可以完美实现。

我们不妨对比一下ERC721 和ERC1155 合约的规范接口:

ERC721

function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool)

ERC1155

function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external;
function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
function balanceOf(address _owner, uint256 _id) external view returns (uint256);
function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) external view returns (uint256[] memory);
function setApprovalForAll(address _operator, bool _approved) external;
function isApprovedForAll(address _owner, address _operator) external view returns (bool);

可以明显看到,ERC1155 在原有ERC721 基础上增加了很多batch 的接口。

再看看OpenZeppelin 中的ERC1155 实现,其中的mint function 增加了amount参数, 不难想象,如果amount = 1, 则代表这个代币总共只发行一个,那这个代币就是类似ERC721 的NFT 了。

function _mint(
    address account,
    uint256 id,
    uint256 amount,
    bytes memory data
) internal virtual {
    require(account != address(0), "ERC1155: mint to the zero address");
    address operator = _msgSender();
    _beforeTokenTransfer(operator, address(0), account, _asSingletonArray(id), _asSingletonArray(amount), data);
    _balances[id][account] += amount;
    emit TransferSingle(operator, address(0), account, id, amount);
    _doSafeTransferAcceptanceCheck(operator, address(0), account, id, amount, data);
}

说完了基本概念,下面我们就来get your hands dirty,亲手尝试一下写一个ERC1155 智能合约,你会发现,其实远比你想象的简单。

二、代码示例

下面我们借助openzeppelin智能合约库来写一个ERC1155合约,来实现NFT的铸造、批量铸造、单个NFT的URI信息获取和批量URI获取等功能。

代码:

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract rockPaperScissors is ERC1155 {
    uint256 public constant Rock = 1;
    uint256 public constant Paper = 2;
    uint256 public constant Scissors = 3;

    constructor() ERC1155("https://ipfs.io/ipfs/bafybeihjjkwdrxxjnuwevlqtqmh3iegcadc32sio4wmo7bv2gbf34qs34a/{id}.json") {
        _mint(msg.sender, Rock, 1, "");
        _mint(msg.sender, Paper, 1, "");
        _mint(msg.sender, Scissors, 1, "");
    }

    function uri(uint256 _tokenid) override public pure returns (string memory) {
        return string(
            abi.encodePacked(
                "https://ipfs.io/ipfs/bafybeihjjkwdrxxjnuwevlqtqmh3iegcadc32sio4wmo7bv2gbf34qs34a/",
                Strings.toString(_tokenid),".json"
            )
        );
    }
}

三、使用Remix IDE

Remix是Ethereum 官方提供的IDE 。包含完整的编译器、执行合约、发布合约等等的功能。无须安装,只要用浏览器开启Remix - Ethereum IDE即可。

Remix 默认情况下会将所有资料存储在浏览器的Local Storage 中,所以当你清除浏览器缓存快取,或者在另外一台电脑打开Remix,你的资料便会丢失。Remix 也提供了使用本地文件系统来进行存储的功能,但需要安装一个remixd 本地程式,具体方法可以参考这里

当你安装好remixd 后,便可以透过运行下面的指令来建立Remix 和本地档案的连结:

remixd -s <absolute-path-to-the-shared-folder> --remix-ide <your-remix-ide-URL-instance>

四、编译,发布智能合约

编辑完成后, 就可以切换到Compile 面板进行编译。留意要选择正确的编译器版本,编译器版本要和你合约中声明的版本相符合,否则无法编译。

编译完成后,便可以准备发布(deploy)了。切换到Deploy 面板。此时我们要在左上角的Environment 中选择【Injected Web 3】,此时便会弹出MetaMask 进行连结。如果还没有安装MetaMask,可以先在Chrome Web Store中安装。

我们开始尝试时一般都会选择在测试网路(testnet)中进行,测试网络和Ethereum 主网在技术上没有区别,但在测试网路中不需要花费真实的ETH ,而是使用测试网路中的ETH。一般我们开发的Blockchain 程式,都要先在测试网路上做全面测试,之后才在主网中上线。要知道Ethereum 主网的Gas Fee 可高的惊人。

在Ethereum 网路上任何导致更改数据的动作都需要花费ETH,因此发布智能合约自然需要ETH。如果没有testnet 的ETH 可以在网上找到很多testnet faucet 可以免费获得testnet 的ETH 。一切就绪后,就可以按下【Deploy】,开始发布你的智能合约,中间会弹出MetaMask 进行付款确认。

发布完成后,Remix 会显示对应的Transaction Hash,例如我自己上面的例子,对应的Transaction 可以在区块链浏览器上看到,里面亦可以看到我们建立的ERC1155 智能合约地址。

五、验证合约

验证合约

选择合约类型

上传合约代码

合约验证成功

六、测试合约

Mint NFT

回到Remix或者浏览器合约页面,可以看到Deployed Contracts 中已经有我们刚才发布的智能合约,点开他之后可以看到里面有一个mint 的Function,现在我们就可以调用这个Function 来Mint NFT 了。

这个mint function 需要传入四个参数,分别是 拥有者地址,token id,发行数量,附加数据

附加数据在ERC1155 规范中并没有指定用途,因此这个参数可以根据自己的需要来传递任何数据,如果没有的话传递空值即可。

可以查看一下这笔交易的详情

query balance

然后我们可以查看一下刚刚创建的NFT余额,点开他之后可以看到里面有一个balanceOf 的Function,现在我们就可以调用这个Function 来query balance 了。

这个balanceOf function 需要传入四个参数,分别是 拥有者地址,token id

查询token ID的附加数据

转移NFT

然后我们可以再对刚刚mint的NFT进行转移,点开他之后可以看到里面有一个safeTransferFrom 的Function,现在我们就可以调用这个Function 来转移了。

这个safeTransferFrom function 需要传入四个参数,分别是 from,to,token id,amount,data。

我们经常在solidity合约方法的参数里看到的“bytes _data”,那么他究竟是做什么用的?

可以把 bytes 理解为一个泛型参数。因为bytes 可以转化为各种不同的基本类型。

例如,在 safeTransferFrom 中,你可以在转账的时候把一个附加的信息给目标方,这个附加的信息可以一个单品 ID(uint), 或者是一个推荐人地址。

一个高级的用法时:bytes 包含了一个函数选择器编码及参数, 这样可以通过这个参数去实现动态调用其他的方法。

可以查看一下这笔交易的详情

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个简单的ERC20智能合约示例: ```solidity pragma solidity ^0.8.0; contract ERC20Token { string public name; string public symbol; uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; constructor(string memory _name, string memory _symbol, uint256 _totalSupply) { name = _name; symbol = _symbol; totalSupply = _totalSupply; balanceOf[msg.sender] = _totalSupply; } function transfer(address _to, uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value, "Insufficient balance"); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; emit Transfer(msg.sender, _to, _value); return true; } function approve(address _spender, uint256 _value) public returns (bool success) { allowance[msg.sender][_spender] = _value; emit Approval(msg.sender, _spender, _value); return true; } function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { require(balanceOf[_from] >= _value, "Insufficient balance"); require(allowance[_from][msg.sender] >= _value, "Insufficient allowance"); balanceOf[_from] -= _value; balanceOf[_to] += _value; allowance[_from][msg.sender] -= _value; emit Transfer(_from, _to, _value); return true; } event Transfer(address indexed _from, address indexed _to, uint256 _value); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } ``` 该合约包括以下功能: - `name`:代币名称 - `symbol`:代币符号 - `totalSupply`:代币总量 - `balanceOf`:每个地址的代币余额 - `allowance`:允许其他地址花费的代币数量 该合约实现了ERC20标准中的以下函数: - `transfer`:从调用者的地址向另一个地址发送代币 - `approve`:允许另一个地址花费指定数量的代币 - `transferFrom`:从一个地址向另一个地址发送代币,前提是已经获得了允许 该合约还定义了两个事件: - `Transfer`:代币发送时触发 - `Approval`:允许花费代币时触发 要部署这个合约,你需要使用Solidity编译器将其编译为字节码,然后将字节码发送到以太坊网络上。你可以使用Remix或Truffle等工具来编译和部署智能合约

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰哥的技术杂货铺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值