赞
踩
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。
状态变量与构造函数
首先看下状态变量与构造函数,状态变量为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;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。