Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Erc20Wrapper extension #498

Draft
wants to merge 30 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1944622
chore: wrapper approch
Ifechukwudaniel Jan 16, 2025
0cca59f
chore: code fmt
Ifechukwudaniel Jan 16, 2025
3bab6ac
chore: comments
Ifechukwudaniel Jan 16, 2025
038020b
chore: erc20 wrapper token
Ifechukwudaniel Jan 16, 2025
7587d34
chore: code fmt
Ifechukwudaniel Jan 16, 2025
961353e
chore: wrapper example
Ifechukwudaniel Jan 16, 2025
a347f69
chore: erc20 wrapper
Ifechukwudaniel Jan 25, 2025
9c66630
chore: removed variable
Ifechukwudaniel Jan 25, 2025
bd69a58
chore: wrapper and example
Ifechukwudaniel Jan 26, 2025
1bedc16
chore: erc20 wrapper example
Ifechukwudaniel Jan 26, 2025
9d5419c
cargo fmt
Ifechukwudaniel Jan 26, 2025
2d6a02f
chore: fixed constructor test
Ifechukwudaniel Jan 27, 2025
398da73
chore: wrapper
Ifechukwudaniel Jan 27, 2025
3405bf2
chore: fomrmat
Ifechukwudaniel Jan 27, 2025
dfc1e00
chore: CHANGELOG
Ifechukwudaniel Jan 27, 2025
4274d2b
chore:docs
Ifechukwudaniel Jan 27, 2025
fd1de52
chore: removed docs
Ifechukwudaniel Jan 27, 2025
fb6a894
chore: erc20 wrappers docs
Ifechukwudaniel Jan 27, 2025
102611b
chore: fix underlying state
Ifechukwudaniel Jan 27, 2025
1f450b2
chore: fixed clippy error
Ifechukwudaniel Jan 27, 2025
fae5882
chore: fixed clippy warnings
Ifechukwudaniel Jan 27, 2025
f8d684a
docs
Ifechukwudaniel Jan 28, 2025
d13ad47
docs: added missing docs
Ifechukwudaniel Jan 28, 2025
ab401e2
chore: format
Ifechukwudaniel Jan 28, 2025
4070411
docs: ivalid to invalid
Ifechukwudaniel Jan 28, 2025
4ac2b5c
test: underlying test works
Ifechukwudaniel Jan 28, 2025
104c45a
test: test fixes
Ifechukwudaniel Jan 28, 2025
b6e1d6e
Merge branch 'main' into ERC20Wrapper
Ifechukwudaniel Jan 30, 2025
1b15a10
Merge branch 'main' into ERC20Wrapper
Ifechukwudaniel Jan 31, 2025
1114ccf
Merge branch 'main' into ERC20Wrapper
Ifechukwudaniel Feb 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [Unreleased]

### Added

- Implement `AddAssignChecked` for `StorageUint`. #474
- `Erc20FlashMint` extension. #407
- `Erc20Wrapper` "Token Wrapping contract". #498

### Changed

Expand Down
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ members = [
"examples/erc20",
"examples/erc20-permit",
"examples/erc20-flash-mint",
"examples/erc20-wrapper",
"examples/erc721",
"examples/erc721-consecutive",
"examples/erc721-metadata",
Expand All @@ -34,6 +35,7 @@ default-members = [
"examples/erc20",
"examples/erc20-permit",
"examples/erc20-flash-mint",
"examples/erc20-wrapper",
"examples/erc721",
"examples/erc721-consecutive",
"examples/erc721-metadata",
Expand Down
2 changes: 2 additions & 0 deletions contracts/src/token/erc20/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ pub mod capped;
pub mod flash_mint;
pub mod metadata;
pub mod permit;
pub mod wrapper;

pub use burnable::IErc20Burnable;
pub use capped::Capped;
pub use flash_mint::{Erc20FlashMint, IErc3156FlashLender};
pub use metadata::{Erc20Metadata, IErc20Metadata};
pub use permit::Erc20Permit;
pub use wrapper::{Erc20Wrapper, IERC20Wrapper};
232 changes: 232 additions & 0 deletions contracts/src/token/erc20/extensions/wrapper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
//! 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. For example, combining this wrapping mechanism with {ERC20Votes}

Check warning on line 5 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:5:67 | 5 | //! modules. For example, combining this wrapping mechanism with {ERC20Votes} | ^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown = note: `-W clippy::doc-markdown` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::doc_markdown)]` help: try | 5 | //! modules. For example, combining this wrapping mechanism with {`ERC20Votes`} | ~~~~~~~~~~~~ Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:5:67:w:warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:5:67 | 5 | //! modules. For example, combining this wrapping mechanism with {ERC20Votes} | ^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown = note: `-W clippy::doc-markdown` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::doc_markdown)]` help: try | 5 | //! modules. For example, combining this wrapping mechanism with {`ERC20Votes`} | ~~~~~~~~~~~~ __END__

Check warning on line 5 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:5:67 | 5 | //! modules. For example, combining this wrapping mechanism with {ERC20Votes} | ^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown = note: `-W clippy::doc-markdown` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::doc_markdown)]` help: try | 5 | //! modules. For example, combining this wrapping mechanism with {`ERC20Votes`} | ~~~~~~~~~~~~ Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:5:67:w:warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:5:67 | 5 | //! modules. For example, combining this wrapping mechanism with {ERC20Votes} | ^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown = note: `-W clippy::doc-markdown` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::doc_markdown)]` help: try | 5 | //! modules. For example, combining this wrapping mechanism with {`ERC20Votes`} | ~~~~~~~~~~~~ __END__
//! will allow the wrapping of an existing "basic" ERC-20 into a governance
//! token.
//!
//! WARNING: Any mechanism in which the underlying token changes the {balanceOf}
//! of an account without an explicit transfer may desynchronize this contract's
//! supply and its underlying balance. Please exercise caution when wrapping
//! tokens that may undercollateralize the wrapper (i.e. wrapper's total supply
//! is higher than its underlying balance). See {_recover} for recovering value
//! accrued to the wrapper.
use alloy_primitives::{Address, U256};
use alloy_sol_macro::sol;
use stylus_sdk::{
call::Call,
contract, msg,
prelude::storage,
storage::{StorageAddress, TopLevelStorage},
stylus_proc::SolidityError,
};

use crate::token::erc20::{
self,
utils::{
safe_erc20::{self, ISafeErc20},
SafeErc20,
},
Erc20,
};

mod token {

#![allow(missing_docs)]
#![cfg_attr(coverage_nightly, coverage(off))]

use alloc::vec;

use stylus_sdk::stylus_proc::sol_interface;

sol_interface! {
/// Solidity Interface of the ERC-20 token.
interface IErc20 {
function balanceOf(address account) external view returns (uint256);
function totalSupply() external view returns (uint256);
}
}
}

use token::IErc20 as IErc20Solidity;

sol! {
Ifechukwudaniel marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Debug)]
#[allow(missing_docs)]
error ERC20InvalidUnderlying(address token);

#[derive(Debug)]
#[allow(missing_docs)]
error ERC20InvalidSender(address sender);

/// The address is not a valid ERC-20 token.
///
/// * `asset` - Address of the invalid ERC-20 token.
#[derive(Debug)]
#[allow(missing_docs)]
error InvalidAsset(address asset);

#[derive(Debug)]
#[allow(missing_docs)]
error ERC20InvalidReceiver(address receiver);

}

/// An [`Erc20Wrapper`] error.
#[derive(SolidityError, Debug)]
pub enum Error {
/// Error type from [`SafeErc20`] contract [`safe_erc20::Error`].
SafeErc20(safe_erc20::Error),

/// The Sender Address is not valid.
InvalidSender(ERC20InvalidSender),

/// The Reciver Address is not valid.
InvalidReceiver(ERC20InvalidReceiver),

/// The underlying token couldn't be wrapped.
InvalidUnderlying(ERC20InvalidUnderlying),

/// The address is not a valid ERC-20 token.
InvalidAsset(InvalidAsset),

/// Error type from [`Erc20`] contract [`erc20::Error`].
Erc20(erc20::Error),
}
/// State of an [`Erc20Wrapper`] token.
#[storage]
pub struct Erc20Wrapper {
/// Token Address of the underline token
#[allow(clippy::used_underscore_binding)]
pub(crate) _underlying: StorageAddress,
Ifechukwudaniel marked this conversation as resolved.
Show resolved Hide resolved

/// [`SafeErc20`] contract
safe_erc20: SafeErc20,
}

/// ERC-4626 Tokenized Vault Standard Interface
pub trait IERC20Wrapper {
/// The error type associated to this ERC20Wrapper trait implementation.

Check warning on line 111 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:111:43 | 111 | /// The error type associated to this ERC20Wrapper trait implementation. | ^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown help: try | 111 | /// The error type associated to this `ERC20Wrapper` trait implementation. | ~~~~~~~~~~~~~~ Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:111:43:w:warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:111:43 | 111 | /// The error type associated to this ERC20Wrapper trait implementation. | ^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown help: try | 111 | /// The error type associated to this `ERC20Wrapper` trait implementation. | ~~~~~~~~~~~~~~ __END__

Check warning on line 111 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:111:43 | 111 | /// The error type associated to this ERC20Wrapper trait implementation. | ^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown help: try | 111 | /// The error type associated to this `ERC20Wrapper` trait implementation. | ~~~~~~~~~~~~~~ Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:111:43:w:warning: item in documentation is missing backticks --> contracts/src/token/erc20/extensions/wrapper.rs:111:43 | 111 | /// The error type associated to this ERC20Wrapper trait implementation. | ^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown help: try | 111 | /// The error type associated to this `ERC20Wrapper` trait implementation. | ~~~~~~~~~~~~~~ __END__
Ifechukwudaniel marked this conversation as resolved.
Show resolved Hide resolved
type Error: Into<alloc::vec::Vec<u8>>;

/// Returns the address of the underlying token that is been wrapped.
fn underlying(&self) -> Address;

/// Allow a user to deposit underlying tokens and mint the corresponding
/// number of wrapped token
///
/// Arguments:
///
/// * `&mut self` - Write access to the contract's state.
/// * `account` - The account to deposit tokens to.
/// * `value` - The amount of tokens to deposit.
fn deposit_to(

Check warning on line 125 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:125:5 | 125 | / fn deposit_to( 126 | | &mut self, 127 | | account: Address, 128 | | value: U256, 129 | | erc20: &mut Erc20, 130 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc = note: `-W clippy::missing-errors-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_errors_doc)]` Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:125:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:125:5 | 125 | / fn deposit_to( 126 | | &mut self, 127 | | account: Address, 128 | | value: U256, 129 | | erc20: &mut Erc20, 130 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc = note: `-W clippy::missing-errors-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_errors_doc)]` __END__

Check warning on line 125 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:125:5 | 125 | / fn deposit_to( 126 | | &mut self, 127 | | account: Address, 128 | | value: U256, 129 | | erc20: &mut Erc20, 130 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc = note: `-W clippy::missing-errors-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_errors_doc)]` Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:125:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:125:5 | 125 | / fn deposit_to( 126 | | &mut self, 127 | | account: Address, 128 | | value: U256, 129 | | erc20: &mut Erc20, 130 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc = note: `-W clippy::missing-errors-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_errors_doc)]` __END__
Ifechukwudaniel marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
account: Address,
value: U256,
erc20: &mut Erc20,
) -> Result<bool, Self::Error>;

/// Allow a user to burn a number of wrapped tokens and withdraw the
/// corresponding number of underlying tokens.
///
/// Arguments:
///
/// * `&mut self` - Write access to the contract's state.
/// * `account` - The account to withdraw tokens to.
/// * `value` - The amount of tokens to withdraw.
/// * `erc20` - A mutable reference to the Erc20 contract.
fn withdraw_to(

Check warning on line 141 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:141:5 | 141 | / fn withdraw_to( 142 | | &mut self, 143 | | account: Address, 144 | | value: U256, 145 | | erc20: &mut Erc20, 146 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:141:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:141:5 | 141 | / fn withdraw_to( 142 | | &mut self, 143 | | account: Address, 144 | | value: U256, 145 | | erc20: &mut Erc20, 146 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc __END__

Check warning on line 141 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:141:5 | 141 | / fn withdraw_to( 142 | | &mut self, 143 | | account: Address, 144 | | value: U256, 145 | | erc20: &mut Erc20, 146 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:141:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:141:5 | 141 | / fn withdraw_to( 142 | | &mut self, 143 | | account: Address, 144 | | value: U256, 145 | | erc20: &mut Erc20, 146 | | ) -> Result<bool, Self::Error>; | |___________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc __END__
Ifechukwudaniel marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
account: Address,
value: U256,
erc20: &mut Erc20,
) -> Result<bool, Self::Error>;
}

/// NOTE: Implementation of [`TopLevelStorage`] to be able use `&mut self` when
/// calling other contracts and not `&mut (impl TopLevelStorage +
/// BorrowMut<Self>)`. Should be fixed in the future by the Stylus team.
unsafe impl TopLevelStorage for Erc20Wrapper {}

impl IERC20Wrapper for Erc20Wrapper {
type Error = Error;

fn underlying(&self) -> Address {
self._underlying.get()
}

fn deposit_to(
&mut self,
account: Address,
value: U256,
erc20: &mut Erc20,
) -> Result<bool, Error> {
let underlined_token = self._underlying.get();
let sender = msg::sender();
if account == contract::address() {
return Err(Error::InvalidUnderlying(ERC20InvalidUnderlying {
token: contract::address(),
}));
}

if sender == contract::address() {
return Err(Error::InvalidUnderlying(ERC20InvalidUnderlying {
token: account,
}));
}
self.safe_erc20.safe_transfer_from(
underlined_token,
sender,
contract::address(),
value,
)?;
erc20._mint(account, value)?;
Ok(true)
}

fn withdraw_to(
&mut self,
account: Address,
value: U256,
erc20: &mut Erc20,
) -> Result<bool, Error> {
let underlined_token = self._underlying.get();
if account == contract::address() {
return Err(Error::InvalidUnderlying(ERC20InvalidUnderlying {
token: contract::address(),
}));
}
erc20._burn(account, value)?;
self.safe_erc20.safe_transfer(underlined_token, account, value)?;
Ok(true)
}
}

impl Erc20Wrapper {
/// Mints wrapped tokens to cover any underlying tokens that might have been
/// mistakenly transferred or acquired through rebasing mechanisms.
///
/// This is an internal function that can be exposed with access control if
/// required.
///
/// Arguments:
///
/// * `&mut self` - Write access to the contract's state.
/// * `account` - The account to mint tokens to.
/// * `erc20` - A mutable reference to the Erc20 contract.
pub fn _recover(

Check warning on line 220 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:220:5 | 220 | / pub fn _recover( 221 | | &mut self, 222 | | account: Address, 223 | | erc20: &mut Erc20, 224 | | ) -> Result<U256, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:220:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:220:5 | 220 | / pub fn _recover( 221 | | &mut self, 222 | | account: Address, 223 | | erc20: &mut Erc20, 224 | | ) -> Result<U256, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc __END__

Check warning on line 220 in contracts/src/token/erc20/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:220:5 | 220 | / pub fn _recover( 221 | | &mut self, 222 | | account: Address, 223 | | erc20: &mut Erc20, 224 | | ) -> Result<U256, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc Raw Output: contracts/src/token/erc20/extensions/wrapper.rs:220:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc20/extensions/wrapper.rs:220:5 | 220 | / pub fn _recover( 221 | | &mut self, 222 | | account: Address, 223 | | erc20: &mut Erc20, 224 | | ) -> Result<U256, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc __END__
Ifechukwudaniel marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
account: Address,
erc20: &mut Erc20,
) -> Result<U256, Error> {
let token = IErc20Solidity::new(self.underlying());
let value = token
.balance_of(Call::new_in(self), contract::address())
.map_err(|_| InvalidAsset { asset: contract::address() })?;
erc20._mint(account, value)?;
Ok(U256::from(value))
}
}
57 changes: 57 additions & 0 deletions docs/modules/ROOT/pages/erc20-wrapper.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
= 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]]
== Usage

In order to make your ERC20 `wrapped token`:

[source,rust]
----
use alloy_primitives::{Address, U256};
use openzeppelin_stylus::token::erc20::{
extensions::{Erc20Metadata, Erc20Wrapper, IERC20Wrapper},
Erc20,
};
use stylus_sdk::prelude::{entrypoint, public, storage};

#[entrypoint]
#[storage]
struct Erc20WrapperExample {
#[borrow]
pub erc20: Erc20,
#[borrow]
pub metadata: Erc20Metadata,
#[borrow]
pub wrapper: Erc20Wrapper,
}

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

fn deposit_to(
&mut self,
account: Address,
value: U256,
) -> Result<bool, Vec<u8>> {
Ok(self.wrapper.deposit_to(account, value, &mut self.erc20)?)
}

fn withdraw_to(
&mut self,
account: Address,
value: U256,
) -> Result<bool, Vec<u8>> {
Ok(self.wrapper.withdraw_to(account, value, &mut self.erc20)?)
}
}
----
2 changes: 2 additions & 0 deletions docs/modules/ROOT/pages/erc20.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,5 @@ Additionally, there are multiple custom extensions, including:
* xref:erc20-permit.adoc[ERC-20 Permit]: gasless approval of tokens (standardized as https://eips.ethereum.org/EIPS/eip-2612[`EIP-2612`]).

* xref:erc20-flash-mint.adoc[ERC-20 Flash-Mint]: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as https://eips.ethereum.org/EIPS/eip-3156[`EIP-3156`]).

* xref:erc20-wrapper.adoc[ERC-20 Wrapper]: Extension of the ERC-20 token contract to support token wrapping .
24 changes: 24 additions & 0 deletions examples/erc20-wrapper/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "erc20-wrapper"
edition.workspace = true
license.workspace = true
repository.workspace = true
publish = false
version.workspace = true

[dependencies]
openzeppelin-stylus.workspace = true
alloy-primitives.workspace = true
stylus-sdk.workspace = true

[dev-dependencies]
alloy.workspace = true
eyre.workspace = true
tokio.workspace = true
e2e.workspace = true

[features]
e2e = []

[lib]
crate-type = ["lib", "cdylib"]
Loading
Loading