当前位置:   article > 正文

Openzeppelin库详解-ERC20Wrapper_safeerc20

safeerc20

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

用法参考

可用方式如下:

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

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

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合约地址:

  1. IERC20 private immutable _underlying;
  2. /**
  3. * @dev The underlying token couldn't be wrapped.
  4. */
  5. error ERC20InvalidUnderlying(address token);
  6. constructor(IERC20 underlyingToken) {
  7. if (underlyingToken == this) {
  8. revert ERC20InvalidUnderlying(address(this));
  9. }
  10. _underlying = underlyingToken;
  11. }

函数

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

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

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

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/572489
推荐阅读
相关标签
  

闽ICP备14008679号