ERC720 开发实例

本教程是技术大牛 luofei614 的DApp开发学习笔记,编成教程分享给开发者。

ERC20代币

ERC20是以太坊流行的代币协议,ERC20名称的由来是:以太坊有个需求提案的地方叫ERC,GitHub自动分配20的编号,所以大家习惯叫ERC20

协议结构:

// ----------------------------------------------------------------------------

// ERC Token Standard #20 Interface

// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md

// ----------------------------------------------------------------------------

contract ERC20Interface {

//总发行量

function totalSupply() public constant returns (uint);

//账户余额

function balanceOf(address tokenOwner) public constant returns (uint balance);

//配额带支付, 一般是设置合约地址待支付的权限

function allowance(address tokenOwner, address spender) public constant returns (uint remaining);

//转账

function transfer(address to, uint tokens) public returns (bool success);

//审批, 设置合约地址的allowance配额数量

function approve(address spender, uint tokens) public returns (bool success);

//从其他账户转账,通常与approve一起用

function transferFrom(address from, address to, uint tokens) public returns (bool success);

//转账事件

event Transfer(address indexed from, address indexed to, uint tokens);

//审批事件

event Approval(address indexed tokenOwner, address indexed spender, uint tokens);

}

合约中实际是有两个mapping来记录余额和配合的

mapping(adress => uint256) balances; //记录地址有多少代币余额

mapping(address => mapping(address => unit256)) public allowed;//记录配额

转账有两个方法

  • transfer, 是当前用户(msg.sender) 转账给指定地址, 改变的是balances的状态结构。

  • transferFrom,是from参数地址向to参数地址转账, from不一定是msg.sender ,所以需要from地址向授权给合约地址配额, 合约地址才能实现转账。 设置配额改变的是allowed状态,这个是个二级结构,第一级的address是对应了转出账号地址(from) , 第二级的address对应的是智能合约地址,被授权的智能合约才能转账,等会儿会做个水龙头的合约作为演示。

实现合约可以借助 openzeppelin , 它已经封装好了父类, 子类继承它即可

新建一个项目:

truffle init

安装依赖:

yarn add @openzeppelin/contracts

创建合约: contracts/MTK.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MTK is ERC20 {

//发行一个币的名称叫MyToken, 简称MTK

constructor() ERC20("MyToken", "MTK") {

_mint(msg.sender, 1000);//发现总量,TODO还没有找到怎么设置小数位数

}

}

先用remix调试, 这时候因为import导入多文件, 不方便把代码复制到remix上调试。 所以要建立remix的本地服务,让remix调试本地文件

安装remixd

npm install -g @remix-project/remixd

在项目根目录下启动服务:

sudo remixd -s `pwd` --remix-ide https://remix.ethereum.org

此时在remix文件的wordspaces选择为localhost即可。

编译和部署好合约后,可以用remix界面调试合约函数:

下面重点说一下用truflle console 命令行调试合约。

在migrate文件夹下建立2_MTK.js文件:

const MTK = artifacts.require("MTK");

module.exports = function (deployer) {

deployer.deploy(MTK);

};

编辑truffle-config.js 修改编译器版本为 0.8.4

编译:truffle compile , 并部署合约 truffle migrate

进入命令行:

truflle console

>MTK.address //获得部署合约地址

>let instance=await MTK.deployed() //获得合约实例

>let accounts = await web3.eth.getAccounts() //获得账户

>instance.totalSupply() //获得总发行量

>instance.balanceOf(accounts[0]) //获得账户余额

>instance.transfer(accounts[1],web3.utils.toBN(100)) //向第二个账户打100MTK

>instance.balanceOf(accounts[0]) //获得第二个账户余额

下面在说下建立MTK的水龙头合约,演示approve和transferFrom的使用。

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "./MTK.sol";

contract MTKFaucet {

MTK public MTKInstance;

address public MTKOwner;

constructor(MTK _MTKInstance, address _MTKOwner) {

MTKInstance=_MTKInstance;

MTKOwner=_MTKOwner;

}

function (uint withdraw_amount) public{

require(withdraw_amount<=1000);

MTKInstance.transferFrom(MTKOwner,msg.sender,withdraw_amount);

}

}

创建上面合约时需要传递已经部署好的MTK合约地址和部署账户的地址。

建立migrate/3_MTKFaucet.js文件

const MTKFaucet = artifacts.require("MTKFaucet");

const MTK = artifacts.require("MTK");//前一步MTK已经部署好,这里可以用MTK.address获得部署地址

module.exports = function (deployer,network,accounts) {

deployer.deploy(MTKFaucet,MTK.address,accounts[0]);

};

调试MTKFaucet合约:

truffle console

>let instance=await MTKFaucet.deployed()

>let accounts=await web3.eth.getAccounts();

>instance.withdraw(1,{from:accounts[1]}) //这会报错 revert ERC20: transfer amount exceeds allowance , 是因为没有分配限额

>let MTKInstance=await MTK.deployed()

>MTKInstance.approve(MTKFaucet.address,10) //对合约分配限额为10

>instance.withdraw(1,{from:accounts[1]}) //这时候管用了

>MTKFaucetInstances.withdraw(11,{from:accounts[1]}) //超过限额还会报错

代币的转账和以太坊的转账是有区别的, 太坊的转账是改变的目标地址的状态。 而代币的转账是改变的合约的状态。

大多数交易所的账号地址是合约地址, 要判断交易所合约是否支持代币,如果向不支持代币的合约转账代币, 这个代币将永远卡住取不出来。

PS: ERC721就是NFT的协议。https://docs.openzeppelin.com/contracts/4.x/erc721

Last updated