什么是ERC¶
ERC全称是“Ethereum Request for Comment”,表示以太坊的意见征求稿,ERC 中包含技术和组织等注意事项及标准。这套标准其实不光由以太坊官方提出,还由一些以太坊爱好者提出。是以太坊生态系统中被广泛使用的关键标
代币(token)标准¶
https://ethereum.org/zh/developers/docs/standards/tokens/
- ERC-20 - 同质化(可互换)代币的标准接口,比如投票代币、质押代币或虚拟货币。
- ERC-721 - 非同质化代币的标准接口,比如艺术作品或歌曲的契约。
- ERC-777 - ERC-777 使人们能够通过代币上创建额外的功能,例如用于改善交易私密性的混合合约,或是在您不慎丢失私钥时的紧急恢复功能。
- ERC-1155 - ERC-1155 允许更有效的交易和打包交易,从而节省燃料成本。 此代币标准允许创建实用代币(例如 $BNB 或 $BAT)和加密朋克之类的非同质化代币。
- ERC-4626 - 一个代币化的资金库标准,旨在优化和统一收益资金库的技术参数。
ERC-20代币¶
千言万语汇成一句话: 造钱
什么叫做代币 代替货币
- 代币可以在以太坊中表示任何东西
- 在线平台中的信誉积分
- 游戏中一个角色的技能
- 彩票
- 金融资产类似于公司股份的资产
- 像美元一样的法定货币
- 一克黄金
- 以及更多
ERC-20以太坊代币标准是创建与更广泛的以太坊网络兼容的可替换代币的蓝图。以太坊,或称Ethereum,是一种加密货币,允许创建各种应用,包括代币,与大多数传统应用不同,它不需要中心化服务机构就可以运作
简单来说,ERC-20就是一套基于以太坊网络的标准代币发行协议。有了ERC-20,开发者们得以高效、可靠.低成本地创造专属自己项目的代币,我们甚至可以将ERC-20视为以大坊网络为早期区块链世界做出的最重要贡献,也是以太坊网络第一个真正意义上的杀手级应用。
如果我们把众多区块链项目的开发者,看作是在一个小区门口商铺里,经营不同业态的众多商户。这些商户根据自己的专长提供各自不同的商品和服务,也都希望发行自己店铺专属的消费储值卡。方便消费者光顾的同时,也能提升用户的体验和粘性
以太坊就像是运营这个小区底商的物业公司,它提供一整套标准化的储值卡发放协议和配套服务。借助这套叫做ERC-20的整体解决方案,每个商户(开发者)都可以像瓜式地发行专属于自己店铺的消费储值卡,同时由于这种储值卡采用了统一的协议,可以非常方便地和其他商户的储值卡做无缝兑换。
于是借助ERC-20,用户可以通过持有其中一种储值卡 token)很方便地享受整个生态的各种服务,商户(开发者)则节约了开发运营成本、同时提升了获取用户的效率;而物业公司(以太坊基金会和矿工)则可以通过做大生态体量实现更多的租金(ETH增值)和储值卡结算手续费 (Gas费用)收入。
ERC-20就是用这种做大生态价值的方式,实现了用户、开发者和以太坊网络三方面的共赢。
ERC-20的应用案例
- Tether (USDT)
- Chainlink (LINK)
- Binance coin (BNB)
- UsD coin (USDC)
- Wrapped bitcoin(WBTC)
- Dai(DAI)
需要特别指出的是,这上面提到的Tether发行的稳定币USDT除了基于ERC-20协议的版本之外,其实还有基于其他公链发行的多个版本,只不过ERC-20版的发行量最大,知名度也最高
openzeppelin智能合约库¶
官网: https://www.openzeppelin.com/ GitHub: https://github.com/OpenZeppelin/openzeppelin-contracts
OpenZeppelin 是一个使用以太坊智能合约语言 Solidity 进行构建的开发框架,可以简化智能合约和 Dapp 的开发。
OpenZeppelin合约和库已成为行业标准,其开源代码模板经历了以太坊及其他区块链的实战考验,帮助开发者最大限度降低风险。OpenZeppelin代码包括使用度最高的ERC标准及拓展部署,已被社区在各类指南以及操作教程中大量使用。
contract wizard¶
OpenZeppelin开发了一种基于网络的线上智能合约交互式工具,它可能是使用openZeppelin代码编写智能合约最简单快捷的方式。这一工具称为Contracts Wizard。
案例,自己构建¶
https://docs.openzeppelin.com/contracts/5.x/wizard
傻瓜式生成
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
contract MyToken is ERC20, ERC20Permit {
constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {
_mint(msg.sender, 100000000 * 10 ** decimals());
}
}
用小狐狸部署
怎么把创建的代币添加进来?
导入成功
xxxxxxxxxx 地址: 0xA55b1C8De4d960D909457F4420bB69fEf1349187 私钥: 0x1918fd2a7e94ef4ec4280562de49f4aa54b72afa6e80d6ecb100d5e03d492e37账户信息:
转账
ERC-20实现¶
笔者实现代码:
https://github.com/sonichen/Web3.0_Project_Demo/tree/main/%E4%BB%A3%E5%B8%81%E7%BC%96%E5%86%99_ERC20
reference:
https://ethereum.org/zh/developers/docs/standards/tokens/erc-20/#top https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md https://docs.openzeppelin.com/contracts/4.x/api/token/erc20#ERC20 https://github.com/0penZeppelin/openzeppelin-contracts/blob/v4.8.0/contracts/token/ERC20/ERC20.sol https://www.openzeppelin.com/contracts https://ethereum.org/zh/ https://www.osgeo.cn/solidity/units-and-global-variables.html#special-variables-and-functions
优秀案例:
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/9b3710465583284b8c4c5d2245749246bb2e0094/contracts/token/ERC20/ERC20.sol
https://ethereum.org/zh/developers/docs/standards/tokens/erc-20/
ERC-20(以太坊意见征求 20)由 Fabian Vogelsteller 提出于 2015 年 11 月。这是一个能实现智能合约中代币的应用程序接口标准。
ERC-20 的功能示例包括:
- 将代币从一个帐户转到另一个帐户
- 获取帐户的当前代币余额
- 获取网络上可用代币的总供应量
- 批准一个帐户中一定的代币金额由第三方帐户使用
如果智能合约实施了下列方法和事件,它可以被称为 ERC-20 代币合约,一旦部署,将负责跟踪以太坊上创建的代币。
方法
function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
事件
event Transfer(address indexed _from, address indexed _to, uint256 _value)
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
代币信息和代币取值器¶
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import './Context.sol' ;
contract MyToken is Context{
/**
- 规范 -
function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
event Transfer(address indexed _from, address indexed _to, uint256 _value)
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
**/
// - 1. 代币信息 -
// 代币名称 name
string private _name;
// 代币标识 symbol
string private _symbol;
// 代币小数数位 decimals
uint8 private _decimals;
// 代币的总发行量 totalSupply
uint256 private _totalSupply;
// 代数量 balance
mapping (address=>uint256) private _balances;
// 授权代币数量 allowance
mapping (address=>mapping (address=>uint256)) private _allowance;
// - 2.初始化 -
constructor(){
_name="sonichen";
_symbol="sc";
_decimals=18;
// 初始化货币值
_mint(_msgSender(), 100 *10000*10**_decimals);
}
// 合约内部函数
function _mint(address account,uint256 amount) internal {
require(account!=address(0),"ERC20: mint to thge zero address");
// 初始化货币数量
_totalSupply+=amount;
//给某个账号注入起始资金
unchecked{
_balances[account]+=amount;
}
}
// - 3.取值器 -
// 返回代币的名字 name()
function name() public view returns (string memory){
return _name;
}
// 返回代币标识
function symbol() public view returns (string memory){
return _symbol;
}
//返回代币小数位数
function decimals() public view returns (uint8){
return _decimals;
}
//返回代币总发行量
function totalSupply() public view returns (uint256){
return _totalSupply;
}
//返回某个账户拥有的代币数量
function balanceOf(address _owner) public view returns (uint256 balance){
return _balances[_owner];
}
}
代币转账¶
// 代币转发
function transfer(address to, uint256 amount) public returns (bool success){
address owner=_msgSender();
// 实现转账
_transfer(owner,to,amount);
return true;
}
// 转账操作
function _transfer(address from, address to, uint256 amount) internal {
// 检查地址
require(from !=address(0),"ERC20: transfer from the zero address");
require(to!=address(0),"ERO20: transfer to the zero address");
// 检查余额是否足够
uint256 fromBalance=_balances[from];
require(fromBalance>=amount,unicode"ERC20: 余额不足.");
// 转账
unchecked{
_balances[from]=fromBalance-amount;
_balances[to]+=amount;
}
}
代币授权¶
借贷
主体:借款人,贷款人,中介公司 account
授权:贷款人(银行)借钱给我 approve 100w
提款:从银行贷款账户提钱给自己 transferFrom 1w
支付房款:借款人转账给房屋出售者 transferFrom 90w
支付佣金:借款人转账中介公司 transferFrom 9w
// 授权代币
function approve(address spender, uint256 amount) public returns (bool) {
// 银行授权给我(用户贷款给我)
address owner = _msgSender();
// owner是授权人
// spender 被授权人
_approve(owner, spender, amount);
return true;
}
// 授权代币转发
function transferFrom(
address from,
address to,
uint256 amount
) public returns (bool) {
// approve授权,现在要提款,要有一个转账操作
address owner = _msgSender();
// 更新授权账户信息
_spendAllowance(from, owner, amount);
// 执行转账
// from: 银行
// to: 自己/中介公司/买房人
_transfer(from, to, amount);
return true;
}
//授权代币的转发
function _approve(
address owner,
address spender,
uint256 amount
) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve from the zero address");
// 执行授权
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
// 执行授权代币转发
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal {
uint256 currentAllowance = allowanceOf(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, unicode"ERC20: 余额不足");
// 修改余额
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
销毁代币¶
见官网
总结¶
// MyToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
import "./Context.sol";
contract MyToken is Context {
/**
- 规范 -
function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
event Transfer(address indexed _from, address indexed _to, uint256 _value)
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
**/
// - 1. 代币信息 -
// 代币名称 name
string private _name;
// 代币标识 symbol
string private _symbol;
// 代币小数数位 decimals
uint8 private _decimals;
// 代币的总发行量 totalSupply
uint256 private _totalSupply;
// 代数量 balance
mapping(address => uint256) private _balances;
// 授权代币数量 allowance
mapping(address => mapping(address => uint256)) private _allowances;
// - 2.初始化 -
constructor() {
_name = "sonichen";
_symbol = "sc";
_decimals = 18;
// 初始化货币值
_mint(_msgSender(), 100 * 10000 * 10**_decimals);
}
// - 3.取值器 -
// 返回代币的名字 name()
function name() public view returns (string memory) {
return _name;
}
// 返回代币标识
function symbol() public view returns (string memory) {
return _symbol;
}
//返回代币小数位数
function decimals() public view returns (uint8) {
return _decimals;
}
//返回代币总发行量
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
//返回某个账户拥有的代币数量
function balanceOf(address account) public view returns (uint256 balance) {
return _balances[account];
}
//返回授权代币数量
function allowanceOf(address owner, address spender)
public
view
returns (uint256 balance)
{
return _allowances[owner][spender];
}
// - 4. 函数 -
// 代币转发
function transfer(address to, uint256 amount) public returns (bool) {
address owner = _msgSender();
// 实现转账
_transfer(owner, to, amount);
return true;
}
// 授权代币
function approve(address spender, uint256 amount) public returns (bool) {
// 银行授权给我(用户贷款给我)
address owner = _msgSender();
// owner是授权人
// spender 被授权人
_approve(owner, spender, amount);
return true;
}
// 授权代币转发
function transferFrom(
address from,
address to,
uint256 amount
) public returns (bool) {
// approve授权,现在要提款,要有一个转账操作
address owner = _msgSender();
// 更新授权账户信息
_spendAllowance(from, owner, amount);
// 执行转账
// from: 银行
// to: 自己/中介公司/买房人
_transfer(from, to, amount);
return true;
}
// - 5.事件-
event Transfer(address _from, address _to, uint256 amount);
event Approval(address _owner, address _spender, uint256 amount);
// - 6. 合约内部函数 -
function _mint(address account, uint256 amount) internal {
require(account != address(0), "ERC20: mint to thge zero address");
// 初始化货币数量
_totalSupply += amount;
//给某个账号注入起始资金
unchecked {
_balances[account] += amount;
}
}
// 转账操作
function _transfer(
address from,
address to,
uint256 amount
) internal {
// 检查地址
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERO20: transfer to the zero address");
// 检查余额是否足够
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, unicode"ERC20: 余额不足.");
// 转账
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
}
//授权代币的转发
function _approve(
address owner,
address spender,
uint256 amount
) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve from the zero address");
// 执行授权
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
// 执行授权代币转发
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal {
uint256 currentAllowance = allowanceOf(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, unicode"ERC20: 余额不足");
// 修改余额
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
}
// Context.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
contract Context{
function _msgSender() internal view returns (address){
return msg.sender;
}
}
ERC-20代币部署¶
小狐狸部署¶
准备部署到线上
部署到小狐狸
连接小狐狸
连接到Goerli测试网络
点击deploy部署
部署成功
到写小狐狸添加资产
这样合约部署者(account1)
给account2转账测试