ERC 20 优缺点,以及 eth 3 种转账方式
ERC 20 协议的产生(优点):
- 定义统一的函数名:名称、发行量、转账函数、转账事件等
- 以便交易所、钱包进行集成
- 所有实现了这些函数的合约都是 ERC20Token
- ERC20 可以表示任何同质的可以交易的内容: 货币、股票、积分、债券、利息...
- 可以用数量来表示的内容 基本上可以ERC20 表示
ERC 20 的缺点
以下是一个遇到很多次的场景:有一天老板过来找你(开发者),最近存币生息很火,我们也做一个合约吧, 用户打币过来给他计算利息, 看起来是一个很简单的需求,你满口答应说好,结果自己一研究发现,使用 ERC20 标准没办法在合约里记录是谁发过来多少币,从而没法计算利息(因为接收者合约并不知道自己接收到ERC20代币)。
ERC20 标准下,可以通过一个变通的办法,采用两个交易组合完成,方法是:第1步:先让用户把要转移的金额用 ERC20 的approve 授权的存币生息合约(这步通常称为解锁),第2步:再次让用户调用存币生息合约的计息函数,计息函数中通过 transferFrom 把代币从用户手里转移的合约内,并开始计息。
同样由于ERC20 标准没有一个转账通知机制,很多ERC20代币误转到合约之后,再也没有办法把币转移出来,已经有大量的ERC20 因为这个原因被锁死。
另外一个问题是ERC20 转账时,无法携带额外的信息,例如:我们有一些客户希望让用户使用 ERC20 代币购买商品,因为转账没法携带额外的信息, 用户的代币转移过来,不知道用户具体要购买哪件商品,从而展加了线下额外的沟通成本。
如何解决 ERC 20 中存在的问题
使用这个ERC777:send(dest, value, data) 解决。
ERC777 使用 send转账时会分别在持有者和接收者地址上使用ERC1820 的getInterfaceImplementer函数进行查询,查看是否有对应的实现合约,ERC777 标准规范里预定了接口及函数名称,如果有实现则进行相应的调用。
即便是一个普通用户地址,同样可以实现对 ERC777 转账的监听, 听起来有点神奇,其实这是通过 ERC1820 接口注册表合约来是实现的。
ERC1820 如此的重要,以至于ERC777单独把它拆出来作为一个EIP。
ERC1820合约提过了两个主要接口:
- setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer)
用来设置地址(_addr)的接口(_interfaceHash 接口名称的 keccak256 )由哪个合约实现(_implementer)。 - getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address)
这个函数用来查询地址(_addr)的接口由哪个合约实现。
ERC1820 是一个全局的合约,有一个唯一在以太坊链上都相同的合约地址,它总是 0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24
,这个合约是通过非常巧妙的方式进行部署的。
如果面试官问 :有没有办法不使用 erc 777 来解决误转入合约锁死?
可以查看 erc 20 的源码 发现 transfer 方法如下 :
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
我们在实现自己的erc 20 合约的时候重载 _afterTokenTransfer 这个方法 。
并且判断 我们这个代币 如果转入的是合约,就要就他实现一个接受代币的方法 。
这种处理方式是有 副作用的 ,比如你转到 uniswap ,等 ,他应该是没有实现你指定的方法 。
我思考 可以参考 erc 721 的做法增加一个新的函数 ,叫safexxx 来执行转账的逻辑。
eth 3 种转账方式的区别 :
erc 20:
如果要给合约转账,则需先授权给合约:合约能使用多少个币,然后才能进行转账
举例说明,如果账户A有1000个ETH,想允许B账户随意调用他的100个ETH,过程如下:
A账户按照以下形式调用approve函数approve(B,100)
B账户想用这100个ETH中的10个ETH给C账户,调用transferFrom(A, C, 10)
调用allowance(A, B)可以查看B账户还能够调用A账户多少个token
此处的token 需要是只要符合erc20 标准的token
ERC 777
参考上面提到的 :
ERC777 使用 send转账时会分别在持有者和接收者地址上使用ERC1820 的getInterfaceImplementer函数进行查询,查看是否有对应的实现合约,ERC777 标准规范里预定了接口及函数名称,如果有实现则进行相应的调用。
ERC 2612 (ERC20 permit)
线下签名授权
(授权)可以在线下签名进行,签名信息可以在执行接收转账交易时提交到链上,让授权和转账在一笔交易里完成。 同时转账交易也可以由接收方(或其他第三方)来提交,也避免了用户(ERC20的拥有者)需要有 ETH的依赖。