Openzeppelin库详解-ERC20Wrapper

ERC20Wrapper能够实现对指定ERC20的锚定,通过调用ERC20Wrapper的存入、取出方法,在实现锚定ERC20转移的同时,实现等值ERC20Wrapper的mint、burn。

用法参考

可用方式如下:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20,ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {ERC20Wrapper} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol";
contract MyERC20Wrapper is ERC20, ERC20Wrapper{
    constructor(IERC20 _underlying) ERC20("MyWrapper","MW") ERC20Wrapper(_underlying){
       
    }
     function decimals() public view virtual override(ERC20, ERC20Wrapper) returns (uint8) {
        return super.decimals();
     }
}

部署后对外暴露的方法如下所示:

ERC20相关方法不做过多介绍,主要说明下ERC20Wrapper相关个性化方法:

1、depositFor:该方法能够首先从指定地址向当前ERC20Wrapper合约地址转移指定数量锚定ERC20 TOKEN,然后向该地址铸造等量的ERC20Wrapper TOKEN。这里要注意的是这个ERC20转移底层实现ERC20的转移方式为transferFrom,所以会消耗授权额度,具体消耗的是指定地址对当前ERC20Wrapper合约地址的授权额度,因此在调用该方法前,要先在指定账户上进行approve(ERC20Wrapper,value)。

2、withdrawTo:该方法首先进行ERC20Wrapper TOKEN的销毁,然后从当前ERC20Wrapper合约向指定账户转账等量锚定ERC20,这里的ERC20转移调用的是transfer方法,因此不消耗授权额度,因而不需要approve。

代码详解

代码地址:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.0.1/contracts/token/ERC20/extensions/ERC20Wrapper.sol

状态变量与构造函数

首先看下状态变量与构造函数,状态变量为immutabe的锚定ERC20合约地址,在经过构造函数赋值后不能再修改,赋值要求锚定ERC20不能是当前ERC20Wrapper合约地址:

    

    IERC20 private immutable _underlying;

    /**
     * @dev The underlying token couldn't be wrapped.
     */
    error ERC20InvalidUnderlying(address token);

    constructor(IERC20 underlyingToken) {
        if (underlyingToken == this) {
            revert ERC20InvalidUnderlying(address(this));
        }
        _underlying = underlyingToken;
    }

函数

depositFor函数功能如前所述,实现细节如下:

    //从指定地址account存入到当前合约value数量的ERC20,然后向该地址account铸造同等数量的ERC20Wrapper
    function depositFor(address account, uint256 value) public virtual returns (bool) {
        address sender = _msgSender();
        if (sender == address(this)) {
            revert ERC20InvalidSender(address(this));
        }
        if (account == address(this)) {
            revert ERC20InvalidReceiver(account);
        }
        //SafeERC20为Library,因此在SafeERC20的safeTransferFrom方法中,msg.sender仍然为当前ERC20Wrapper合约地址,然后SafeERC20中调用的是锚定ERC20的transferFrom,所以在ERC20的transferFrom中的msg.sender就是当前ERC20Wrapper合约地址,因此要先进行account对ERC20Wrapper合约的可转移ERC20授权(approve)
        SafeERC20.safeTransferFrom(_underlying, sender, address(this), value);
        //向account铸造value数量的ERC20Wrapper
        _mint(account, value);
        return true;
    }

withdrawTo函数功能如前所述,实现细节如下:

    //从指定地址account销毁指定数量value的ERC20Wrapper,然后从ERC20Wrapper合约地址向account转移value数量的锚定ERC20
    function withdrawTo(address account, uint256 value) public virtual returns (bool) {
        if (account == address(this)) {
            revert ERC20InvalidReceiver(account);
        }
        _burn(_msgSender(), value);
        //safeTransfer底层调用的是transfer,因此不需要进行授权
        SafeERC20.safeTransfer(_underlying, account, value);
        return true;
    }

_recover函数用于恢复错误转入该地址锚定ERC20的情况,实现细节如下:

    //针对没有通过depositFor方法转入锚定ERC20,而是直接transfer,会出现锚定ERC20数量大于ERC20Wrapper数量的情况,可以同步铸造差值数量的ERC20Wrapper来找补错误转入的ERC20
    function _recover(address account) internal virtual returns (uint256) {
        uint256 value = _underlying.balanceOf(address(this)) - totalSupply();
        _mint(account, value);
        return value;
    }

  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值