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

[Feature]: ERC721Wrapper extension #461

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
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 @@ -11,6 +11,7 @@ members = [
"examples/erc721",
"examples/erc721-consecutive",
"examples/erc721-metadata",
"examples/erc721-wrapper",
"examples/erc1155",
"examples/erc1155-metadata-uri",
"examples/erc1155-supply",
Expand Down Expand Up @@ -38,6 +39,7 @@ default-members = [
"examples/erc721",
"examples/erc721-consecutive",
"examples/erc721-metadata",
"examples/erc721-wrapper",
"examples/erc1155",
"examples/erc1155-metadata-uri",
"examples/erc1155-supply",
Expand Down
2 changes: 2 additions & 0 deletions contracts/src/token/erc721/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ pub mod consecutive;
pub mod enumerable;
pub mod metadata;
pub mod uri_storage;
pub mod wrapper;

pub use burnable::IErc721Burnable;
pub use enumerable::{Erc721Enumerable, IErc721Enumerable};
pub use metadata::{Erc721Metadata, IErc721Metadata};
pub use uri_storage::Erc721UriStorage;
pub use wrapper::Erc721Wrapper;
213 changes: 213 additions & 0 deletions contracts/src/token/erc721/extensions/wrapper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
//! Extension of the ERC-721 token contract to support token wrapping.
//!
//! Users can deposit and withdraw an "underlying token" and receive a "wrapped
//! token" with a matching tokenId. This is useful in conjunction with other
//! modules.
use alloc::{vec, vec::Vec};

use alloy_primitives::{Address, U256};
use stylus_sdk::{
abi::Bytes,
call::Call,
contract, msg,
prelude::storage,
storage::{StorageAddress, TopLevelStorage},
stylus_proc::SolidityError,
};

use crate::token::erc721::{
self, Erc721, IErc721 as IErc721Solidity, RECEIVER_FN_SELECTOR,

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / wasm32-unknown-unknown

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / beta

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: unused import: `RECEIVER_FN_SELECTOR` --> contracts/src/token/erc721/extensions/wrapper.rs:19:47 | 19 | self, Erc721, IErc721 as IErc721Solidity, RECEIVER_FN_SELECTOR, | ^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:19:47:w:warning: unused import: `RECEIVER_FN_SELECTOR` --> contracts/src/token/erc721/extensions/wrapper.rs:19:47 | 19 | self, Erc721, IErc721 as IErc721Solidity, RECEIVER_FN_SELECTOR, | ^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default __END__

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: unused import: `RECEIVER_FN_SELECTOR` --> contracts/src/token/erc721/extensions/wrapper.rs:19:47 | 19 | self, Erc721, IErc721 as IErc721Solidity, RECEIVER_FN_SELECTOR, | ^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:19:47:w:warning: unused import: `RECEIVER_FN_SELECTOR` --> contracts/src/token/erc721/extensions/wrapper.rs:19:47 | 19 | self, Erc721, IErc721 as IErc721Solidity, RECEIVER_FN_SELECTOR, | ^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default __END__

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / nightly / doc

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / nightly / coverage

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / macos-latest / stable

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / Check WASM binary

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / tests

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / tests

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / Gas usage report

unused import: `RECEIVER_FN_SELECTOR`

Check warning on line 19 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / Gas usage report

unused import: `RECEIVER_FN_SELECTOR`
};

/// State of an [`Erc721Wrapper`] token.
#[storage]
pub struct Erc721Wrapper {
/// Erc721 contract storage.
pub underlying_address: StorageAddress,
/// The ERC-721 token.
pub erc721: Erc721,
}

unsafe impl TopLevelStorage for Erc721Wrapper {}

pub use sol::*;
#[cfg_attr(coverage_nightly, coverage(off))]
mod sol {
use alloy_sol_macro::sol;

sol! {
/// The received ERC-721 token couldn't be wrapped.
///
/// * `token_id` - Token id as a number.
#[derive(Debug)]
#[allow(missing_docs)]
error ERC721UnsupportedToken(uint256 token_id);

/// Indicates an error related to the ownership over a particular token.
/// Used in transfers.
///
/// * `sender` - Address whose tokens are being transferred.
/// * `token_id` - Token id as a number.
/// * `owner` - Address of the owner of the token.
#[derive(Debug)]
#[allow(missing_docs)]
error ERC721IncorrectOwner(address sender, uint256 token_id, address owner);
}
}

/// An [`Erc721Wrapper`] error.
#[derive(SolidityError, Debug)]
pub enum Error {
/// Error type from [`Erc721`] contract [`erc721::Error`].
Erc721(erc721::Error),
/// The received ERC-721 token couldn't be wrapped.
UnsupportedToken(ERC721UnsupportedToken),
/// Indicates an error related to the ownership over a particular token.
IncorrectOwner(ERC721IncorrectOwner),
}

pub use token::IErc721;
mod token {
#![allow(missing_docs)]
#![cfg_attr(coverage_nightly, coverage(off))]
use alloc::vec;

stylus_sdk::stylus_proc::sol_interface! {
/// Interface of the ERC-721 token.
interface IErc721 {
function ownerOf(uint256 token_id) external view returns (address);
}
}
}

impl Erc721Wrapper {
/// Allow a user to deposit underlying tokens and mint the corresponding
/// tokenIds.
///
/// Arguments:
///
/// * `account` - The account to deposit tokens to.
/// * `token_ids` - The tokenIds of the underlying tokens to deposit.
/// * `erc721` - A mutable reference to the Erc721 contract.
pub fn deposit_for(

Check warning on line 92 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:101:13 | 101 | / self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); | |__________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc = note: `-W clippy::missing-panics-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_panics_doc)]` Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:92:5:w:warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:101:13 | 101 | / self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); | |__________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc = note: `-W clippy::missing-panics-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_panics_doc)]` __END__

Check warning on line 92 in contracts/src/token/erc721/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/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, 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/erc721/extensions/wrapper.rs:92:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, 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 92 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:101:13 | 101 | / self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); | |__________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc = note: `-W clippy::missing-panics-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_panics_doc)]` Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:92:5:w:warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:101:13 | 101 | / self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); | |__________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc = note: `-W clippy::missing-panics-doc` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::missing_panics_doc)]` __END__

Check warning on line 92 in contracts/src/token/erc721/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/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, 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/erc721/extensions/wrapper.rs:92:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc721/extensions/wrapper.rs:92:5 | 92 | / pub fn deposit_for( 93 | | &mut self, 94 | | account: Address, 95 | | token_ids: Vec<U256>, 96 | | erc721: &mut Erc721, 97 | | ) -> Result<bool, 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__
&mut self,
account: Address,
token_ids: Vec<U256>,

Check warning on line 95 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:95:20 | 95 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value = note: `-W clippy::needless-pass-by-value` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_pass_by_value)]` Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:95:20:w:warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:95:20 | 95 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value = note: `-W clippy::needless-pass-by-value` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_pass_by_value)]` __END__

Check warning on line 95 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:95:20 | 95 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value = note: `-W clippy::needless-pass-by-value` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_pass_by_value)]` Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:95:20:w:warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:95:20 | 95 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value = note: `-W clippy::needless-pass-by-value` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_pass_by_value)]` __END__
erc721: &mut Erc721,
) -> Result<bool, Error> {
let sender = msg::sender();

token_ids.iter().for_each(|&token_id| {

Check warning on line 100 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:100:9 | 100 | / token_ids.iter().for_each(|&token_id| { 101 | | self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); ... | 106 | | .expect("mint failed"); 107 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each = note: `-W clippy::needless-for-each` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_for_each)]` help: try | 100 ~ for &token_id in token_ids.iter() { 101 + self.erc721 102 + .transfer_from(sender, contract::address(), token_id) 103 + .expect("transfer failed"); 104 + erc721 105 + ._safe_mint(account, token_id, &vec![].into()) 106 + .expect("mint failed"); 107 + } | Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:100:9:w:warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:100:9 | 100 | / token_ids.iter().for_each(|&token_id| { 101 | | self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); ... | 106 | | .expect("mint failed"); 107 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each = note: `-W clippy::needless-for-each` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_for_each)]` help: try | 100 ~ for &token_id in token_ids.iter() { 101 + self.erc721 102 + .transfer_from(sender, contract::address(), token_id) 103 + .expect("transfer failed"); 104 + erc721 105 + ._safe_mint(account, token_id, &vec![].into()) 106 + .expect("mint failed"); 107 + } | __END__

Check warning on line 100 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:100:9 | 100 | / token_ids.iter().for_each(|&token_id| { 101 | | self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); ... | 106 | | .expect("mint failed"); 107 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each = note: `-W clippy::needless-for-each` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_for_each)]` help: try | 100 ~ for &token_id in token_ids.iter() { 101 + self.erc721 102 + .transfer_from(sender, contract::address(), token_id) 103 + .expect("transfer failed"); 104 + erc721 105 + ._safe_mint(account, token_id, &vec![].into()) 106 + .expect("mint failed"); 107 + } | Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:100:9:w:warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:100:9 | 100 | / token_ids.iter().for_each(|&token_id| { 101 | | self.erc721 102 | | .transfer_from(sender, contract::address(), token_id) 103 | | .expect("transfer failed"); ... | 106 | | .expect("mint failed"); 107 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each = note: `-W clippy::needless-for-each` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::needless_for_each)]` help: try | 100 ~ for &token_id in token_ids.iter() { 101 + self.erc721 102 + .transfer_from(sender, contract::address(), token_id) 103 + .expect("transfer failed"); 104 + erc721 105 + ._safe_mint(account, token_id, &vec![].into()) 106 + .expect("mint failed"); 107 + } | __END__
self.erc721
.transfer_from(sender, contract::address(), token_id)
.expect("transfer failed");
erc721
._safe_mint(account, token_id, &vec![].into())
.expect("mint failed");
});

Ok(true)
}

/// Allow a user to burn wrapped tokens and withdraw the corresponding
/// tokenIds of the underlying tokens.
///
/// Arguments:
///
/// * `account` - The account to withdraw tokens to.
/// * `token_ids` - The tokenIds of the underlying tokens to withdraw.
/// * `erc721` - A mutable reference to the Erc721 contract.
pub fn withdraw_to(

Check warning on line 120 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:129:13 | 129 | / erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); | |________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:120:5:w:warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:129:13 | 129 | / erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); | |________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc __END__

Check warning on line 120 in contracts/src/token/erc721/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/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:120:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc __END__

Check warning on line 120 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:129:13 | 129 | / erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); | |________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:120:5:w:warning: docs for function which may panic missing `# Panics` section --> contracts/src/token/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | note: first possible panic found here --> contracts/src/token/erc721/extensions/wrapper.rs:129:13 | 129 | / erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); | |________________________________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_panics_doc __END__

Check warning on line 120 in contracts/src/token/erc721/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/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:120:5:w:warning: docs for function returning `Result` missing `# Errors` section --> contracts/src/token/erc721/extensions/wrapper.rs:120:5 | 120 | / pub fn withdraw_to( 121 | | &mut self, 122 | | account: Address, 123 | | token_ids: Vec<U256>, 124 | | erc721: &mut Erc721, 125 | | ) -> Result<bool, Error> { | |____________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#missing_errors_doc __END__
&mut self,
account: Address,
token_ids: Vec<U256>,

Check warning on line 123 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:123:20 | 123 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:123:20:w:warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:123:20 | 123 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value __END__

Check warning on line 123 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:123:20 | 123 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:123:20:w:warning: this argument is passed by value, but not consumed in the function body --> contracts/src/token/erc721/extensions/wrapper.rs:123:20 | 123 | token_ids: Vec<U256>, | ^^^^^^^^^ help: consider changing the type to: `&[U256]` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value __END__
erc721: &mut Erc721,
) -> Result<bool, Error> {
let sender = msg::sender();

token_ids.iter().for_each(|&token_id| {

Check warning on line 128 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:128:9 | 128 | / token_ids.iter().for_each(|&token_id| { 129 | | erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); ... | 134 | | .expect("transfer failed"); 135 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each help: try | 128 ~ for &token_id in token_ids.iter() { 129 + erc721 130 + ._update(Address::ZERO, token_id, sender) 131 + .expect("update failed"); 132 + self.erc721 133 + .safe_transfer_from(contract::address(), account, token_id) 134 + .expect("transfer failed"); 135 + } | Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:128:9:w:warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:128:9 | 128 | / token_ids.iter().for_each(|&token_id| { 129 | | erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); ... | 134 | | .expect("transfer failed"); 135 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each help: try | 128 ~ for &token_id in token_ids.iter() { 129 + erc721 130 + ._update(Address::ZERO, token_id, sender) 131 + .expect("update failed"); 132 + self.erc721 133 + .safe_transfer_from(contract::address(), account, token_id) 134 + .expect("transfer failed"); 135 + } | __END__

Check warning on line 128 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:128:9 | 128 | / token_ids.iter().for_each(|&token_id| { 129 | | erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); ... | 134 | | .expect("transfer failed"); 135 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each help: try | 128 ~ for &token_id in token_ids.iter() { 129 + erc721 130 + ._update(Address::ZERO, token_id, sender) 131 + .expect("update failed"); 132 + self.erc721 133 + .safe_transfer_from(contract::address(), account, token_id) 134 + .expect("transfer failed"); 135 + } | Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:128:9:w:warning: needless use of `for_each` --> contracts/src/token/erc721/extensions/wrapper.rs:128:9 | 128 | / token_ids.iter().for_each(|&token_id| { 129 | | erc721 130 | | ._update(Address::ZERO, token_id, sender) 131 | | .expect("update failed"); ... | 134 | | .expect("transfer failed"); 135 | | }); | |___________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_for_each help: try | 128 ~ for &token_id in token_ids.iter() { 129 + erc721 130 + ._update(Address::ZERO, token_id, sender) 131 + .expect("update failed"); 132 + self.erc721 133 + .safe_transfer_from(contract::address(), account, token_id) 134 + .expect("transfer failed"); 135 + } | __END__
erc721
._update(Address::ZERO, token_id, sender)
.expect("update failed");
self.erc721
.safe_transfer_from(contract::address(), account, token_id)
.expect("transfer failed");
});

Ok(true)
}

/// Overrides [`erc721::IERC721Receiver::on_erc_721_received`] to allow
/// minting on direct ERC-721 transfers to this contract.
pub fn on_erc721_received(
&mut self,
operator: Address,

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / wasm32-unknown-unknown

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / beta

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / beta / clippy

[clippy] reported by reviewdog 🐶 warning: unused variable: `operator` --> contracts/src/token/erc721/extensions/wrapper.rs:144:9 | 144 | operator: Address, | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_operator` | = note: `#[warn(unused_variables)]` on by default Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:144:9:w:warning: unused variable: `operator` --> contracts/src/token/erc721/extensions/wrapper.rs:144:9 | 144 | operator: Address, | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_operator` | = note: `#[warn(unused_variables)]` on by default __END__

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / stable / clippy

[clippy] reported by reviewdog 🐶 warning: unused variable: `operator` --> contracts/src/token/erc721/extensions/wrapper.rs:144:9 | 144 | operator: Address, | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_operator` | = note: `#[warn(unused_variables)]` on by default Raw Output: contracts/src/token/erc721/extensions/wrapper.rs:144:9:w:warning: unused variable: `operator` --> contracts/src/token/erc721/extensions/wrapper.rs:144:9 | 144 | operator: Address, | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_operator` | = note: `#[warn(unused_variables)]` on by default __END__

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / nightly / doc

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / nightly / coverage

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / macos-latest / stable

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / Check WASM binary

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / features

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / tests

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / tests

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / Gas usage report

unused variable: `operator`

Check warning on line 144 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / Gas usage report

unused variable: `operator`
from: Address,
token_id: U256,
data: Bytes,
) -> Result<(), Error> {
let sender = msg::sender();

if self.underlying() != sender {
return Err(Error::UnsupportedToken(ERC721UnsupportedToken {
token_id,
}));
}

self.erc721._safe_mint(from, token_id, &data)?;
// RECEIVER_FN_SELECTOR
Ok(())
}

/// Returns the underlying token.
pub fn underlying(&self) -> Address {
self.underlying_address.get()
}
}

// ************** ERC-721 Internal **************

impl Erc721Wrapper {
/// Mints wrapped tokens to cover any underlying tokens that would have been
/// function taht can be exposed with access control if desired.

Check warning on line 172 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable / typos

"taht" should be "that".
///
/// Arguments:
///
/// * `&mut self` - Write access to the contract's state.
/// * `account` - The account to mint tokens to.
/// * `token_id` - A mutable reference to the Erc20 contract.
///
/// # Errors
///
/// If the underlying token is not owned by the contract, the error
/// [`Error::`] is returned.
fn _recover(
&mut self,
account: Address,
token_id: U256,
) -> Result<U256, Error> {
let underlying = IErc721::new(self.underlying());
let owner = match underlying.owner_of(Call::new_in(self), token_id) {
Ok(owner) => owner,
Err(e) => return Err(Error::Erc721(e.into())),
};
if owner != contract::address() {
return Err(Error::IncorrectOwner(ERC721IncorrectOwner {
sender: contract::address(),
token_id,
owner,
}));
}
self.erc721._safe_mint(account, token_id, &vec![].into())?;
Ok(token_id)
}
}

#[cfg(all(test, feature = "std"))]
mod tests {
use alloy_primitives::{address, uint, Address, U256};

Check warning on line 208 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable

unused imports: `Address`, `U256`, `address`, and `uint`

Check warning on line 208 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / beta

unused imports: `Address`, `U256`, `address`, and `uint`

Check warning on line 208 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / nightly / coverage

unused imports: `Address`, `U256`, `address`, and `uint`

Check warning on line 208 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / macos-latest / stable

unused imports: `Address`, `U256`, `address`, and `uint`
use stylus_sdk::msg;

Check warning on line 209 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable

unused import: `stylus_sdk::msg`

Check warning on line 209 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / beta

unused import: `stylus_sdk::msg`

Check warning on line 209 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / nightly / coverage

unused import: `stylus_sdk::msg`

Check warning on line 209 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / macos-latest / stable

unused import: `stylus_sdk::msg`

#[motsu::test]
fn recover(contract: Erc721Wrapper) {}

Check failure on line 212 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / stable

cannot find type `Erc721Wrapper` in this scope

Check failure on line 212 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / beta

cannot find type `Erc721Wrapper` in this scope

Check failure on line 212 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / ubuntu / nightly / coverage

cannot find type `Erc721Wrapper` in this scope

Check failure on line 212 in contracts/src/token/erc721/extensions/wrapper.rs

View workflow job for this annotation

GitHub Actions / macos-latest / stable

cannot find type `Erc721Wrapper` in this scope
}
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/erc721-wrapper.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
= ERC-721 Wrapper
2 changes: 2 additions & 0 deletions docs/modules/ROOT/pages/erc721.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,5 @@ Additionally, there are multiple custom extensions, including:
* xref:erc721-pausable.adoc[ERC-721 Pausable]: A primitive to pause contract operation.

* xref:erc721-uri-storage.adoc[ERC-721 Uri Storage]: A more flexible but more expensive way of storing metadata.

* xref:erc721-wrapper.adoc[ERC-721 Wrapper]: Wrapper to create an ERC-721 backed by another ERC-721, with deposit and withdraw methods.
24 changes: 24 additions & 0 deletions examples/erc721-wrapper/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "erc721-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"]
15 changes: 15 additions & 0 deletions examples/erc721-wrapper/src/constructor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

contract Erc721WrapperExample {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256))
private _allowances;
uint256 private _totalSupply;

address private _underlyingToken;

constructor(address underlyingToken_) {
_underlyingToken = underlyingToken_;
}
}
39 changes: 39 additions & 0 deletions examples/erc721-wrapper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#![cfg_attr(not(test), no_main)]
extern crate alloc;

use alloy_primitives::{Address, U256};
use openzeppelin_stylus::token::erc721::{extensions::Erc721Wrapper, Erc721};
use stylus_sdk::prelude::{entrypoint, public, storage};

#[entrypoint]
#[storage]
struct Erc721WrapperExample {
#[borrow]
pub erc721: Erc721,
#[borrow]
pub wrapper: Erc721Wrapper,
}

#[public]
#[inherit(Erc721)]
impl Erc721WrapperExample {
fn underlying(&self) -> Address {
self.wrapper.underlying()
}

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

fn withdraw_to(
&mut self,
account: Address,
values: Vec<U256>,
) -> Result<bool, Vec<u8>> {
Ok(self.wrapper.withdraw_to(account, values, &mut self.erc721)?)
}
}
39 changes: 39 additions & 0 deletions examples/erc721-wrapper/tests/abi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#![allow(dead_code)]
use alloy::sol;

sol!(
#[sol(rpc)]
contract Erc20Wrapper {
function name() external view returns (string name);
function symbol() external view returns (string symbol);
function totalSupply() external view returns (uint256 totalSupply);
function balanceOf(address account) external view returns (uint256 balance);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256 allowance);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

#[derive(Debug)]
function decimals() external view returns (uint8 decimals);
#[derive(Debug)]
function underlying() external view returns (address underlying);
#[derive(Debug)]
function depositFor(address account, uint256 value) external returns (bool);
#[derive(Debug)]
function withdrawTo(address account, uint256 value) external returns (bool);

error ERC721InvalidOwner(address owner);
error ERC721NonexistentToken(uint256 tokenId);
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
error ERC721InvalidSender(address sender);
error ERC721InvalidReceiver(address receiver);
error ERC721InsufficientApproval(address operator, uint256 tokenId);
error ERC721InvalidApprover(address approver);
error ERC721InvalidOperator(address operator);

#[derive(Debug, PartialEq)]
event Transfer(address indexed from, address indexed to, uint256 value);
#[derive(Debug, PartialEq)]
event Approval(address indexed owner, address indexed spender, uint256 value);
}
);
Loading
Loading