数字货币一日通——OpenZeppelin的ERC20

本文尝试发行一款基于以太坊区块链的数字货币,在此之前你需要先熟悉Solidity这门合约语言,并拥有Metamask钱包和账户。

「本文仅做技术探讨,如有上主网需求,请遵循当地国家的法律法规,后果自负」

数字货币基本认识

世界上第一个基于去中心区块链技术,点对点网络且有共识能力的开源数字货币应用就是大名鼎鼎的Bitcoin,我个人一直认为比特币是中本聪送给全世界的礼物,也是迄今为止唯一的真正去中心数字货币,其它的山寨币或多或少都有局部的中心化亦或根本就是财阀控制。比特币最早诞生于2008年,一篇论文详细描述了这款划时代的产品。尽管不是所有的国家承认这是一款货币替代品(实际上只有很少的国家承认),而只是将其认作一种虚拟资产,类似股票。仍然开创了一种新形态的经济模型和生态,随之而崛起的挖矿,数字货币交易所应运而生,同时它也启发了众多投身于去中心事业的科学家、工程师、用户,也在后续产生了以太坊等功能更加完善的区块链。

10多年来,比特币俨然构成了一种新的亚文化,影响着整个人类社会。有关于它的精彩故事太多太多,这里不再一一列举,欢迎大家投身于去中心事业,一同探索属于每一个人的新世界。

以太坊

发行数字货币有很多种方式,一种传统的方法是我们从零开始自己开发一款区块链,然后在上面部署数字货币;当然还可以基于现有的链发行代币,比如在以太坊生态上面。这里涉及到一个重要的合约:ERC20。其严格定义了代币的相关合约和接口,如果我们实现自己的ERC20,那么至少要知晓这个协议的全部细节,特别是接口IERC20实现细节:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 数字货币的名称,例:Bitcoin
function name() public view returns (string)
// 数字货币的符号,通常是缩写,例:BTC
function symbol() public view returns (string)
// 默认是18,num Token * (10 ** decimals)
function decimals() public view returns (uint8)
// 返回现存的代币数量
function totalSupply() public view returns (uint256)
// 获取账户_owner拥有的代币的数量
function balanceOf(address _owner) public view returns (uint256 balance)
// 从msg.sender账户转移_value数量的代币到_to账户
function transfer(address _to, uint256 _value) public returns (bool success)
// 从账户_from中往账户_to转数量为_value的代币,与approve方法配合使用,需要approve获取权限
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
// msg.sender设置账户_spender能从msg.sender中转出数量为_value的代币
function approve(address _spender, uint256 _value) public returns (bool success)
// 获取账户_spender可以从账户_owner中转出代币的数量
function allowance(address _owner, address _spender) public view returns (uint256 remaining)

// 发生转账时,必须要触发Transfer事件
event Transfer(address indexed _from, address indexed _to, uint256 _value)
// approve(address _spender, uint256 _value) 运行成功时必须要触发事件Approval
event Approval(address indexed _owner, address indexed _spender, uint256 _value)

OpenZeppelin的ERC20

我们不需要完全自己从头实现IERC20,基于OpenZeppelin的优秀实现是一个不错的选择,我们使用Hardhat工作流,有关于工作流的配置,可以参考这篇文章相关部分。合约代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
pragma solidity ^0.8.4;

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

contract ZY_Bitcoin is ERC20, Ownable {
constructor() ERC20("ZY Bitcoin", "ZBT") {
// 固定铸造10000个币
uint256 supply = 10 ** decimals();
_mint(msg.sender, 9000 * supply); // msg.sender持有 90%
_mint(block.coinbase, 1000 * supply ); // 奖励给miner 10%
}
}

编写部署脚本scripts/erc20.js如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const hre = require("hardhat");

async function main() {
const COIN = await hre.ethers.getContractFactory("ZY_Bitcoin");
const coin = await COIN.deploy();
await coin.deployed();
console.log("My Token deployed to:", coin.address);
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

部署到rinkeby测试网络中,在此之前你需要先设置好Relay测试网,可以使用Infura的服务,同时要配置好Metamask钱包的公钥和私钥到我们的Hardhat项目中。这个过程如果不熟悉,可以参考这篇文章当中的Infura测试部署的部分,终端命令行如下:

1
$ npx hardhat --network rinkeby run scripts/erc20.js

部署好后,我们在Etherscan上面查询我们的合约:

mint token

Metamask关联Token

因为我们是rinkeby测试网络,所以我们需要切换钱包网络,并且点击页面上的导入代币链接(在主页靠下的位置),点击后输入我们的合约地址:

import token

我们可以看到,有9000枚ZBT币铸造到账户当中了:

minted token

后记

任何人都可以基于ERC20发行自己的代币,同时伴随着Crypto圈子疯狂的炒币浪潮,其与法定货币锚定的价格令人心醉神迷。现如今大饼(比特币)已然可以看做大盘的指数,而各个项目方发行的代币本质就是上市,你所购买的山寨币可以视同购买股票。这里面当然伴随着监管和法律的问题,其背后的意义也值得深刻探讨。本文仅讨论技术实现,对于法律法规还请读者遵循本国的有关规定。祝福大家可以迎接美好的时代~