前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WETH10 - 更高效的 WETH

WETH10 - 更高效的 WETH

作者头像
Tiny熊
发布2020-11-03 14:40:50
1.5K0
发布2020-11-03 14:40:50
举报

玩过 DEFI 的应该都知道,很多项目是通过 WETH 把以太币代币化[1],再接入到 ERC20 为主的 DEFI 生态中。

当前使用最广泛的 WETH 实现是WETH9[2],有兴趣的可以点击链接查看实现。

WETH9 上线至今快有 3 年了,现在社区小伙伴实现了升级版本:WETH10[3],已经部署在 Kovan 测试网 [4]

WETH10 新特性

WETH10 和 WETH9 一样实现和以太币的包裹,实现 WETH 与以太币的 1:1 互换

存款:Ether -> WETH

具体是调用deposit存入以太币(或发送到合约),可接收到 WETH:

代码语言:javascript
复制
    receive() external payable {
        require(msg.sender != address(this));
        _balanceOf[msg.sender] += msg.value;
        emit Transfer(address(0), msg.sender, msg.value);
    }

    function deposit() external payable {
        _balanceOf[msg.sender] += msg.value;
        emit Transfer(address(0), msg.sender, msg.value);
    }

以上实现和 WETH9 基本一致,WETH10 还可以为指定的账号存款,调用 depositTo

代码语言:javascript
复制
    function depositTo(address to) external payable {
        require(to != address(this), "!recipient");
        _balanceOf[to] += msg.value;
        emit Transfer(address(0), to, msg.value);
    }

WETH10 还实现了存款加调用 depositToAndCall,通过depositToAndCall可以把资金存入合约,并立即调用合约自定义的实现onTokenTransfer,以往使用 WETH9 可能需要多笔交易才能完成的工作现在只需要一笔交易完成。

depositToAndCall 实现如下:

代码语言:javascript
复制
    function depositToAndCall(address to, bytes calldata data) external payable returns (bool success) {
        require(to != address(this), "!recipient");
        _balanceOf[to] += msg.value;
        emit Transfer(address(0), to, msg.value);

        ERC677Receiver(to).onTokenTransfer(msg.sender, msg.value, data);
        return true;
    }

depositToAndCall 的第 2 个参数 data 是传递给目标函数的参数。目标函数的调用使用 ERC677 标准[5]

取款 WETH -> Ether

取款通过调用 withdraw 来完成,withdraw 方法如下:

代码语言:javascript
复制
    function withdraw(uint256 value) external {
        require(_balanceOf[msg.sender] >= value, "!balance");

        _balanceOf[msg.sender] -= value;

        (bool success, ) = msg.sender.call{value: value}("");
        require(success, "!withdraw");

        emit Transfer(msg.sender, address(0), value);
    }

以上实现和 WETH9 基本一致,WETH10 还可以取款到指定的账号,调用withdrawTo

代码语言:javascript
复制
    function withdrawTo(address to, uint256 value) external {
        require(_balanceOf[msg.sender] >= value, "!balance");

        _balanceOf[msg.sender] -= value;

        (bool success, ) = to.call{value: value}("");
        require(success, "!withdraw");

        emit Transfer(msg.sender, address(0), value);
    }

另外还有withdrawFrom函数,用来从其他的账号以取款到指定的账号, 当然需要资金的所有者提前approve, withdrawFrom 实现如下:

代码语言:javascript
复制
    function withdrawFrom(address from, address to, uint256 value) external {
        require(_balanceOf[from] >= value, "!balance");

        if (from != msg.sender) {
            uint256 allow = allowance[from][msg.sender];
            if (allow != type(uint256).max) {
                require(allow >= value, "!allowance");
                allowance[from][msg.sender] -= value;
                emit Approval(from, msg.sender, allow - value);
            }
        }

        _balanceOf[from] -= value;
        (bool success, ) = to.call{value: value}("");
        require(success, "!withdraw");

        emit Transfer(from, address(0), value);
    }

仔细查看以上代码, 你还可以看到授权量的优化,如果授权量是最大值type(uint256).max 时,将不再减少授权量,从而降低 gas 成本。这个优化也同样应用到了 transferFrom 中。

离线授权

升级的 WETH10, 实现了离线授权功能(实现EIP2612[6]),可以参考文章:通过链下签名授权实现更少 Gas 的 ERC20 代币[7],方便合约合并授权与转账交易,减少 gas 消耗。

调用链

在前面 depositAndCall 函数已经提到过,在用户执行存款时,可以立即在用户定义的合约中执行一笔调用, 这样存款和合约调用发生在一次交易中。

升级的 WETH10 也支持在转账时(使用 transferAndCall 转账),同样支持在接收者地址上调用 onTokenTransfer,transferAndCall 实现如下:

代码语言:javascript
复制
    function transferAndCall(address to, uint value, bytes calldata data) external returns (bool success) {
        require(_balanceOf[msg.sender] >= value, "!balance");
        require(_balanceOf[to] + value >= value, "overflow");

        _balanceOf[msg.sender] -= value;
        _balanceOf[to] += value;

        emit Transfer(msg.sender, to, value);

        ERC677Receiver(to).onTokenTransfer(msg.sender, value, data);
        return true;
    }

闪电铸币

WETH10 合约允许通过flashMint 来增发任意数量的 WETH,而不用存入真实的以太币,只需要在交易结束前将其销毁掉。

flashMint函数会在调用者地址上调用executeOnFlashMintflashMint 还支持接收一个额外的bytes参数传递给executeOnFlashMintflashMint 的实现如下:

代码语言:javascript
复制
    function flashMint(uint256 value, bytes calldata data) external {
        _balanceOf[msg.sender] += value;
        require(_balanceOf[msg.sender] >= value, "overflow");

        emit Transfer(address(0), msg.sender, value);

        FlashMinterLike(msg.sender).executeOnFlashMint(value, data);

        require(_balanceOf[msg.sender] >= value, "!balance");
        _balanceOf[msg.sender] -= value;
        emit Transfer(msg.sender, address(0), value);
    }

预感 flashMint 会产生出很多闪电代新玩法。


本文作者:石头

作者主页:https://learnblockchain.cn/people/392


参考资料

[1]

通过WETH把以太币代币化: https://weth.io/

[2]

WETH9: https://etherscan.io/address/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code

[3]

WETH10: https://github.com/WETH10/WETH10

[4]

Kovan 测试网 : https://kovan.etherscan.io/address/0xD25f374A2d7d40566b006eC21D82b9655865F941

[5]

ERC677 标准: https://github.com/ethereum/EIPs/issues/677

[6]

EIP2612: https://eips.ethereum.org/EIPS/eip-2612

[7]

通过链下签名授权实现更少 Gas 的 ERC20代币: https://learnblockchain.cn/article/1496

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • WETH10 新特性
    • 存款:Ether -> WETH
      • 取款 WETH -> Ether
      • 离线授权
      • 调用链
      • 闪电铸币
        • 参考资料
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档