ERC-20 Wrapper

Extension of the ERC-20 token contract to support token wrapping.

Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful in conjunction with other modules.

Usage

In order to make ERC20Wrapper methods “external” so that other contracts can call them, you need to implement them by yourself for your final contract as follows:

use alloc::{vec, vec::Vec};

use alloy_primitives::{Address, U256, U8};
use openzeppelin_stylus::token::erc20::{
    extensions::{wrapper, Erc20Wrapper, IErc20Wrapper},
    Erc20,
};
use stylus_sdk::prelude::*;

#[entrypoint]
#[storage]
struct Erc20WrapperExample {
    #[borrow]
    erc20: Erc20,
    #[borrow]
    erc20_wrapper: Erc20Wrapper,
}

#[public]
#[inherit(Erc20)]
impl Erc20WrapperExample {
    fn underlying(&self) -> Address {
        self.erc20_wrapper.underlying()
    }

    fn decimals(&self) -> U8 {
        self.erc20_wrapper.decimals()
    }

    fn deposit_for(
        &mut self,
        account: Address,
        value: U256,
    ) -> Result<bool, wrapper::Error> {
        self.erc20_wrapper.deposit_for(account, value, &mut self.erc20)
    }

    fn withdraw_to(
        &mut self,
        account: Address,
        value: U256,
    ) -> Result<bool, wrapper::Error> {
        self.erc20_wrapper.withdraw_to(account, value, &mut self.erc20)
    }
}

Additionally, you need to ensure proper initialization during contract deployment. Make sure to include the following code in your Solidity Constructor:

contract Erc20WrapperExample {
    // Erc20 Token Storage
    mapping(address account => uint256) private _balances;
    mapping(address account => mapping(address spender => uint256))
        private _allowances;
    uint256 private _totalSupply;

    // Erc20 Wrapper Storage
    address private _underlying;
    uint8 private _decimals;

    error ERC20InvalidUnderlying(address token);

    constructor(address underlyingToken_, uint8 decimals_) {
        if (underlyingToken_ == address(this)) {
            revert ERC20InvalidUnderlying(address(this));
        }
        _underlying = underlyingToken_;
        _decimals = decimals_;
    }
}