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的依赖。