ERC20标准接口
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
可以看到ERC20由5个function函数和2个event构成;
构成解析:
- totalSupply(): token的总量,总发行量
- balanceOf() :某个账户地址上的余额
- transfer() : 发送token,转账
- allowance() :额度、配额、津贴,owner授权给spender余额
- approve() : 批准给某个地址一定数量的token(授予额度、授予津贴)
- transferFrom(): 提取approve授予的token(提取额度、提取津贴),针对授权进行转账
- Transfer() : token转移事件,转账
- Approval() :额度批准事件,授权
下面我们来举个例子,首先是接口代码:
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.7;
interface IERC20 {
function name() external view returns (string memory);
function symbol() external view returns(string memory);
function decimals() external view returns(uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256 remaining);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
这里的name(),symbol(),decimals()(精度)都是可选项而不是必选项;
我们需要将这些函数正之后的继承中全部实现;
合约示例代码:
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.7;
import "./IERC20.sol";
contract ERC20 is IERC20{
string ercName;
string ercSymbol;
uint8 ercDecimal;
uint256 ercTotalSupply;
mapping(address=>uint256) ercBalances; //自定义账本;
mapping(address=>mapping(address=>uint256))ercAllowance; //授权转账额度;
address public owner;
constructor(string memory _name,string memory _sym,uint8 _decimals){
ercName = _name;
ercSymbol = _sym;
ercDecimal = _decimals;
owner = msg.sender;
// ercTotalSupply=21000000;
// ercBalances[owner]=ercTotalSupply;
}
function mint(address _to,uint256 _value)public{ //挖矿或者空投;
require(msg.sender==owner);
require(address(0)!=_to);
require(_value>0);
ercBalances[_to]+=_value;
ercTotalSupply += _value;
emit Transfer(address(0), _to, _value);
}
function name() override external view returns (string memory){
return ercName;
}
function symbol() override external view returns(string memory){
return ercSymbol;
}
function decimals() override external view returns(uint8){ //精度
return ercDecimal;
}
function totalSupply() override external view returns (uint256){
return ercTotalSupply;
}
function balanceOf(address account) override external view returns (uint256){
return ercBalances[account];
}
function transfer(address recipient, uint256 amount) override external returns (bool){
require(amount>0,"amount must >0");
require(address(0)!=recipient,"recipient address is zero");
require(ercBalances[msg.sender]>=amount,"user' balance not enough");
ercBalances[msg.sender]-=amount;
ercBalances[recipient]+=amount;
emit Transfer(msg.sender, recipient, amount);
return true;
}
function allowance(address owner, address spender)override external view returns (uint256 remaining){
remaining = ercAllowance[owner][spender];
}
function approve(address spender, uint256 amount) external returns (bool){
//委托人->被委托人->value
require(amount>0,"amount must >0");
require(spender!=address(0),"spender is a zero address");
require(ercBalances[msg.sender]>=amount,"user's balance not enough");
ercAllowance[msg.sender][spender]=amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transferFrom(address sender, address recipient, uint256 amount)override external returns (bool){
require(ercBalances[sender]>=amount);
require(ercAllowance[sender][msg.sender]>=amount);
require(amount>0);
require(address(0)!=recipient);
ercBalances[sender]-=amount;
ercBalances[recipient]+=amount;
ercAllowance[sender][msg.sender]-=amount;
emit Transfer(msg.sender, recipient, amount);
return true;
}
}
注意事项:
- 只要是涉及到token的转移,都需要使用emit激活事件;
- approve函数涉及到mapping的二次映射需要注意;
- allowance()主要是查看owner授权给spender的额度;
- 如果没有经过owner的授权,spender无法进行transferFrom()转账;
- 该例子还涉及到了空投(挖矿)函数,由该函数来决定token的发行量,token最初的地址来源于黑洞地址;