一 什么是Token? Token怎么分类?
1.1 什么是Token?
Token也叫做同质化代币(Fungible Token), 它可以表示区块链网络中任何虚拟的东西,比如虚拟货币、积分、金融资产、游戏技能、权益等等。在以太坊上,Token是通过智能合约创建和管理的。
1.2 Token怎么分类?
1.2.1 货币型代币
表示数字货币,比如BCH、DAI、USDT、LTC、TRX等
1.2.2 权益型代币
表示对某个项目或公司的股权或债权,比如:
BCAP: Blockchain Capital 是一家专注于区块链技术的风险投资公司。BCAP 代币代表对 Blockchain Capital 投资基金的部分所有权,持有者有权分享基金的收益。
SPICE:SpiceVC 是一个风险投资基金,专注于区块链和加密货币相关项目。SPICE 代币代表对基金资产和收益的部分所有权,持有者有权分享基金的利润。
SCI:Science Blockchain 是一个风险投资基金,投资于区块链技术和加密货币初创企业。SCI 代币持有者可以分享基金的收益,并对投资决策进行投票。
1.2.3 实用型代币
通常用于提供对某个特定服务或产品的访问权限,比如用于支付交易费用或访问一个平台。比如:
GNT (Obyte):Obyte是一个去中心化的支付网络,GNT代币用于支付网络中的交易费用。
BAT (Basic Attention Token):BAT是用于浏览器Brave的隐私保护广告平台的代币,用户可以通过观看广告获得BAT,然后使用它来支持他们喜欢的网站或内容创作者。
MATIC (Polygon):MATIC是Polygon网络的代币,用于支付交易费用和参与网络的治理,Polygon是一个以太坊的扩展解决方案。
1.2.4 治理型代币
允许持有者参与网络或平台的治理决策,比如投票权。比如:
LINK (Chainlink):Chainlink是一个去中心化的预言机网络,LINK代币持有者可以参与网络的治理,决定网络的发展方向。
AAVE (Aave):Aave是一个去中心化借贷平台,其治理代币AAVE允许持有者参与平台的治理决策。
UNI (Uniswap):Uniswap是一个流行的去中心化交易所(DEX),UNI代币持有者可以参与社区治理,对协议的更新和发展方向进行投票。
注意:
有些代币的分类可能同时属于几类,比如UNI属于治理型代币,代币持有者可以参与 Uniswap 协议的治理,投票决定协议的升级和调整。
但是他也可以作为实用型代币,比如流动性挖矿奖励,通过提供流动性,用户可以获得 UNI 代币作为奖励
同时UNI 代币可以在各种加密货币交易所进行交易,作为一种数字资产进行价值交换,因此也可以作为货币型货币
二 什么是ERC-20? 为什么需要ERC-20?
2.1 什么是ERC-20?
ERC-20是以太坊区块链上的一种同质化代币的标准或者协议,它定义了一组统一的接口和规则,使得代币在以太坊上可以互操作。ERC-20可以被用于创建和发行智能合约代币
2.2 为什么需要ERC-20?
2.2.1 互操作性问题
如果没有ERC-20标准,那么可能不同的代币需要使用不同的钱包,这样用户需要使用不同的代币下载和使用不同的钱包
另外,比如交易所,如果没有ERC-20标准,兼容比较差,可能需要为不同个的代币做不通的兼容逻辑
2.2.2 用户体验差
用户需要了解如何使用每个不同的代币和相关应用程序,因为每一个代币有不同的使用规则和接口,所以用户需要花费大量时间来学习如何使用这些代币。这会导致用户体验差,增加了使用的门槛。
2.2.3 缺乏标准
不同的代币可能在功能实现上有很大差异,导致代币在不同平台上的行为不一致。
应用程序和服务需要为每个代币实现不同的接口和交互方式,增加了开发和维护成本。
2.2.4 审计麻烦
每个代币的智能合约都需要单独审计,耗时耗力,还增加了安全风险。
2.2.5 提高安全性
由于ERC-20标准经过广泛的审查和测试,使用这一标准可以提高代币合约的安全性。开发者可以利用社区已经发现和修复的漏洞,从而减少智能合约中的潜在安全风险。
总结:
没有ERC-20标准会导致在以太坊上创建和使用代币变得复杂和不一致。标准化的重要性在于它简化了代币的开发、使用和集成,提高了安全性和互操作性,改善了用户体验,促进了生态系统的健康发展。
三 ERC-20规范
ERC-20标准定义了一组通用的规则,使不同的代币在以太坊网络上能够互操作,并且能够轻松地被各种应用(如钱包和交易所)集成和使用,这些规则包括必须实现的函数和事件。
3.1 函数
3.1.1 name
function name() external view returns (string memory);
返回代币的名字
3.1.2 symbol
function symbol() external view returns (string memory);
返回代币符号
3.1.3 decimals
function decimals() external view returns (uint8);
返回代币使用的小数位数或者说精度
3.1.4 balanceOf
function balanceOf(address _owner) external view returns (uint256 balance);
返回指定合约地址的代币余额
3.1.5 totalSupply
function totalSupply() external view returns (uint256);
返回已经供应的代币总量,mint的时候会增加totalSupply, burn的时候会减少totalSupply
3.1.6 transfer
function transfer(address _to, uint256 _value) external returns (bool success);
给指定的地址转指定数量的代币,可以是合约调用,也可以是外部调用,需要发送Transfer事件
3.1.7 transferFrom
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
将_from地址中代币转_value数量给_to地址,需要发送Transfer事件
3.1.8 approve
function approve(address _spender, uint256 _value) external returns (bool success);
给_spender授权_value额度或者数量,需要发送Approval事件
3.1.9 allowance
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
返回 _spender 仍被允许从 _owner 提取的代币数量。
3.2 事件
3.2.1 Transfer
event Transfer(address indexed _from, address indexed _to, uint256 _value);
当发生转账的时候,必须触发Transfer事件,哪怕转账的金额是0
3.2.2 Approval
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
当批准授权成功的时候,必须触发Approval事件
四 手动实现ERC-20
contract BaseERC20 {
// 代币名称
string public name;
// 代币符号
string public symbol;
// 返回token使用的小数点后几位
uint8 public decimals;
// 代币发行总量
uint256 public totalSupply;
// 保存着每个地址对应的余额
mapping(address => uint256) balances;
// 保存着某个地址A允许另一个地址B可操作的金额
mapping (address => mapping (address => uint256)) allowances;
// 定义Transfer转账事件
event Transfer(address indexed from, address indexed to, uint256 amount);
// 定义Approva批准事件
event Approval(address indexed owner, address indexed spender, uint256 amount);
error BaseERC20NotEnoughAllowance();
constructor() public {
name = "BaseERC20";
symbol = "BERC20";
// token小数位最多18位
decimals = 18;
// 供应总量 = 供应量 * 1 eth = 100000000 * 10^18
totalSupply = 100000000 * 10 ** uint256(decimals);
// 合约部署的时候,设置这个地址对应的代币供应量
balances[msg.sender] = totalSupply;
}
// 获取指定owner地址对应的代币余额
function balanceOf(address account) public view virtual returns (uint256) {
return balances[account];
}
// 查询某个owner授权委托人允许的转账数量
function allowance(address _owner, address _spender) public view returns (uint256){
return allowances[_owner][_spender];
}
// 向指定地址转账
function transfer(address _to, uint256 _value) public returns (bool success) {
// 校验地址是不是0, address如果没有传递地址就是默认就是0
require(_to != address(0), "BaseERC20: invalid sender");
// 检验发送者账户token数量是否足够
require(balances[msg.sender] > _value, "ERC20: transfer amount exceeds balance");
// 扣除发送者账户token余额
balances[msg.sender] -= _value;
// 增加接收者账户token余额
balances[_to] += _value;
// 向区块链发送一个转账事件
emit Transfer(msg.sender, _to, _value);
return true;
}
// 委托人将from用户转移一定数量token到to账户
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
// 校验地址是不是0, address如果没有传递地址就是默认就是0
require((_from != address(0) && _to != address(0)), "BaseERC20: invalid sender or recepient address");
// 检验发送者账户token数量是否足够
require(balances[_from] >= _value, "ERC20: transfer amount exceeds balance");
// 校验token委托方针对from用户剩余被批准的token数量
uint256 allowance = allowance(_from, msg.sender);
require(allowance >= _value, "ERC20: transfer amount exceeds allowance");
// 转移之后from的token数量扣减
balances[_from] -= _value;
// 扣减spender剩余的可转账token数量
allowances[_from][msg.sender] -= _value;
// 转移之后token数量的余额增加
balances[_to] += _value;
// 向区块链发送一个转账事件
emit Transfer(_from, _to, _value);
return true;
}
// 是授权的approve的调用方,即为批准方,也就是消息发送者,更新spender剩余可转账余额
function approve(address spender, uint256 value) public returns (bool success) {
allowances[msg.sender][spender] = value;
// 向区块链发送一个批准事件
emit Approval(msg.sender, spender, value);
return true;
}
}