Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约

上文 Web3代币基本token概念 我们简单讲述了代币的概念
也讲到了ERC-20这个协议的概念
ERC-20 官方文档地址如下 https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
说实话 给人的感觉不是很正规 连地址都是放在github上的 不过也没办法 官方都这么弄 我们也只能这么看了

先进入文档
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第1张图片
翻一翻文档 你会发现 其实也不是特别多

下面会告诉我们 需要一个name方法
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第2张图片
用view标注 表示他要读取状态变量 returns 返回的 是个字符串类型的值
这个name 就是我们自己代币的名字

好 那就别光说不练啦 先将ganache环境启起来
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第3张图片
然后打开一个 Truffle 项目环境
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第4张图片
在 contracts 目录下创建一个文件 叫 grToken.sol

参考代码如下

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;

contract grToken{
    //因为绑定了public  会自动生成get方法
    string public name = "gerToken";

}

这样 就生成了一个叫 gerToken 的代币
甚至 就这样 就已经可以测试了

我们 在 migrations 目录下创建一个文件
还记得吧 migrations 下的文件 必须用数字开头 才能读到这个脚本
我们创建一个文件 叫 2_contract.js
参考代码如下

const Contacts = artifacts.require("grToken.sol")
module.exports = function(deployer) {
    deployer.deploy(Contacts)
}

我们导入了contracts下的grToken
然后 我们终端运行 这个项目
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第5张图片
然后我们执行

truffle migrate

将合约部署上去
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第6张图片
这里有人会担心 truffle migrate之后 会不会将我们之前的文件都部署上去 其实是不用担心的
因为 truffle migrate 还是有点智能的 但不多
你已经部署上去的文件 他就不会再部署一次了
但是 如果你讲内容改了 再去truffle migrate 它一样不会重新部署
所以 如果你希望改的内容重新部署上去 你需要

truffle migrate --reser

这样 你改完的文件 才会重新部署到我们的区块链上

然后 我们终端运行

truffle console

运行到truffle控制台

然后 我们执行

const token = await grToken.deployed()

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第7张图片
这样 常量token就拿到了我们grToken合约对象
然后 我们尝试调用它的name

token.name

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第8张图片
输出之后 会发现 这是个函数

这就算我们实现的第一个这个文档的name功能了Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第9张图片
然后 文档中 name后面有个 symbol
这个你可以理解为 我们之前是 ETH 你也可以给自己的token起个标识
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第10张图片
我们直接加一行就好了
和name都是一样的

string public symbol = "GRY";

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第11张图片
我这里的就叫 GRY 代理符号

然后 下面还有一个 decimals
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第12张图片
之前我们讲过 这里 我们为了方便处理 有很多的单位 其中最基本的是 wei
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第13张图片
就是你代币的换算单位
我们这里 可以这样写

uint public decimals = 18;

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第14张图片
下面还有 totalSupply 啊 这完了哈
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第15张图片
共用的总量
我们可以这样写

uint public totalSupply;
constructor(){
   totalSupply = 1000000 *(19 * decimals);
}

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第16张图片

这里 反正我们有多少 自己说了算 直接一百万走起啊 总量 然后 的话 因为是 wei单位的 后面我们就处理一下计算 把他真的变成和 ETH一样的单位
总量 一百万 十乘以十的十八次方

然后 我们重新运行终端 输入

truffle migrate --reser

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第17张图片
因为之前部署过 grToken.sol 区块链上已经记录了 所以为了修改的内容能够上去 我们需要用–reser
然后 我们执行

truffle console

打开 truffle 控制台
然后 还是

const token = await grToken.deployed()

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第18张图片
再次创建一个 token对象 接这个 grToken对象

然后 我们可以 通过

token.name()

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第19张图片
就可以访问到这个代币名称了
然后

token.symbol()

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第20张图片
就可以看到我们定义的符号

然后

token.decimals()

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第21张图片
它给我们转换成 这个uint内容了

然后就是

token.totalSupply()

但是内容会发生一些变化
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第22张图片
但是不用担心 这是没问题的

这样 其实就差不多了 但是 其实后面还有一个 balanceOf
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第23张图片
这个东西搞起来就真比较麻烦了

就是 我们每个账户 下面对应的余额是多少
方法传入的是账号的地址
下面就是返回来的余额值

其实 我们可以模拟一种清空

Object public userList = {
    "admin": 5000,
    "gangdan": 1000,
    "zhanglei": 2000
}

我们这里设置一个对象 这样 当他 token.userList(“用户地址”)
就会返回余额
当然这种写法在solidity中是不能直接用的
但大体可以用这个思路

我们可以这样写 先声明一个mapping类型的变量

mapping(address => uint256) public balanceOf;

这个比较像 java的 哈希map集合
键值对应 这里 我们声明名称键 对应值 值是uint256类型
然后 名称叫 balanceOf

然后在constructor 对象初始化时 赋值

balanceOf[msg.sender] = totalSupply;

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第24张图片
这里 这个msg.sender
之前 我们web3操作智能合约也出现过 那时可以拿到用户列表第一个
这个也差不多 我们说过 部署智能合约 需要消耗燃料值 我们不设置 他就默认取扣第一个的
那么 这个 msg.sender 拿到的就也是这个用户
然后 我们之前讲过totalSupply是总量 直接这样写相当于 发布者拥有所有的代币

然后下面又来一个transfer 发送的方法
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第25张图片因为你不可能一直放在发布者这里啊 是不是?
我们这样写

function transfer(address _to, uint256 _value) public returns (bool success) {
    balanceOf[msg.sender] = balanceOf[msg.sender].sub(_value);
    balanceOf[_to] = balanceOf[_to].add(_value);
}

但其实刚写这个地方会报错
因为我们模块中暂时没有这些函数

我们需要引入一个库
输入

npm install @openzeppelin/contracts

这个库非常强大 大家可以自己了解一下
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第26张图片

然后 我们在文件最上面引入

import "@openzeppelin/contracts/utils/math/SafeMath.sol";

using SafeMath for uint256;

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第27张图片
这样 我们去使用那两个函数的地方就不报错了
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第28张图片
这里 transfer的业务并不复杂 balanceOf[msg.sender] 拿到当前正在操作的人
然后 将他减少_value数量的代币
然后 用balanceOf[_to] _to代币 我们需要操作的用户地址 给他加上 _value对应数量的代币

这里可能有个误解
我们constructor时 用msg.sender 拿到的是发布这个合约的用户
但 在transfer中拿到的msg.sender 是调用这个函数的用户
不过 我们这里肯定都是用的我们第一个用户 因为我们没有操作切换登录用户

但是这里需要注意的是 如果我们当前用户都没有等于_value的数值 哪那什么处理这个业务是吧?
所以 我们要在外面加个if
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第29张图片
就是简单在外层加个大于等于的判断
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第30张图片
但是 比起if solidity 中处理这种业务 有种更合适的语法 叫require

require的业务功能是 如果你给他的条件是 真(true) 则它继续往下走 如果不是 则直接抛出一个异常 而且这个异常会被我们区块链记录下来

然后 我们再严谨一点

require(_to != address(0));

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第31张图片
因为这个地址是前端传过来的 我们还是要简单判断一下 虽然 他是不是有效地址 这个并不能确定 但是总归有点用
你可以理解为 != null

然后 这里我们还会注意到 这个transfer是有returns的
bool success 要求返回一个布尔类型的值
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第32张图片
如果他能走完全部业务逻辑 我们返回一个 true 表示成功

但是文档这里 又说了 我们必须触发一个Transfer event.的事件
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第33张图片
我们下拉文档找到一个Events
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第34张图片
我们先将这个文档上的事件接口抄到自己的代码中来

event Transfer(address indexed _from, address indexed _to, uint256 _value)

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第35张图片
这个你可以理解为 就是调用一下日志记录我们发送的操作
到时 所有的操作记录 都会在区块链的日志中可以看到

我们之前中心化 或许 有些人可以将自己的操作记录给他干掉 甚至说 有些互联网公司平台操作内部有鬼
但是 我们区块链是真的记录上去就很难去掉了 这个记录也随时可以被调出来

然后 我们在 transfer 中调用它
或者可以说 只要区块链还在 这个记录就在

emit Transfer(msg.sender,_to,_value);

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第36张图片
这样 我们的业务就好了 这里 我们做个小小的测试
我们就不操作终端了 太麻烦了

我们找到根目录下的 scripts 没有就创建一个 下面来一个test.js
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第37张图片
我们终端先执行

truffle migrate --reser

重新部署一下智能合约
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第38张图片然后我们 test.js代表编写如下

const GrToken = artifacts.require("grToken.sol")

module.exports = async function(callback) {
    const grTokenDai = await GrToken.deployed();
    let res1 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(res1);
    callback()
}

这里 大家需要注意 0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974 是我ganache环境下的第一个账号的公钥地址
你们也要根据情况去填写 就是查看一下这个账号下的 getoken数
我们终端运行

truffle exec .\scripts\test.js  

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第39张图片
这里 我们前面输出的token.totalSupply() 共有量就到这来了

说明 我们constructor中的逻辑是完成了
Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第40张图片
但是这个单位 显然看着有点头疼

我们可以改成这样

const GrToken = artifacts.require("grToken.sol")

const towei = (bn)=> {
    return web3.utils.fromwei(bn,"ether");
}

module.exports = async function(callback) {
    const grTokenDai = await GrToken.deployed();
    let res1 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(towei(res1));
    callback()
}

很多人就会说 web3不是没引入吗?
这个大家可以放心 测试环境下 web3的方法是可以顺便用的

我们再次运行

truffle exec .\scripts\test.js  

这次 单位就没问题了
在这里插入图片描述
那么 现在能确定的是 balanceOf确实是好用

接下来 测试 transfer

但是这里有个点比较要命
我们没有登录授权 transfer它拿不到当前登录的用户
我们可以这样写

这里 我们将test.js代码更改如下

const GrToken = artifacts.require("grToken.sol")

const toWei = (bn) => {
  return web3.utils.fromWei(bn, "ether");
}
const inWei = (bn) => {
    return web3.utils.toWei(bn.toString(), "ether");
}

module.exports = async function(callback) {
    const grTokenDai = await GrToken.deployed();
    let res1 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(toWei(res1));

    await grTokenDai.transfer("0x096A90463E48723d3631b3291Dd76b6BA425eD4e",inWei(10000),{
        from: "0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974"
    });
    let res2 = await grTokenDai.balanceOf("0x096A90463E48723d3631b3291Dd76b6BA425eD4e");
    console.log(toWei(res2),"第二个用户");
    let res3 = await grTokenDai.balanceOf("0x323E82B10DCd0E5fB100BcC3F0ABAB561AA04974");
    console.log(toWei(res3),"第一个用户");
    callback()
}

inWei就是一个反向转换 transfer在测试环境 我们这就这样用 第一个参数 需要发送给谁 第二个发送多少 第三个是个对象
注意 0x096A90463E48723d3631b3291Dd76b6BA425eD4e 也是一个我ganache模拟出来的用户地址 毕竟这个肯定需要两个用户才能操作嘛
{
from: 当前登录用户地址
}
然后 我们再次终端运行

truffle exec .\scripts\test.js  

Web3带着大家根据ERC-20文档编写自己的第一个代表solidity智能合约_第41张图片
直接起飞啊 起飞

你可能感兴趣的:(区块链)