ERC-721 Enumerable

The OpenZeppelin ERC-721 Enumerable extension is used to provide additional functionality to the standard ERC-721 token. Specifically, it allows for enumeration of all the token IDs in the contract as well as all the token IDs owned by each account. This is useful for applications that need to list or iterate over tokens, such as marketplaces or wallets.

Usage

In order to make an ERC-721 token with Enumerable flavour, you need to create a specified contract as follows:

use openzeppelin_stylus::{
    token::erc721::{
        self,
        extensions::{enumerable, Erc721Enumerable, IErc721Burnable},
        Erc721, IErc721,
    },
    utils::introspection::erc165::IErc165,
};

#[derive(SolidityError, Debug)]
enum Error {
    Enumerable(enumerable::Error),
    Erc721(erc721::Error),
}

#[entrypoint]
#[storage]
struct Erc721Example {
    #[borrow]
    erc721: Erc721,
    #[borrow]
    enumerable: Erc721Enumerable,
}

#[public]
#[inherit(Erc721, Erc721Enumerable)]
impl Erc721Example {
    fn burn(&mut self, token_id: U256) -> Result<(), Error> {
        // Retrieve the owner.
        let owner = self.erc721.owner_of(token_id)?;

        self.erc721.burn(token_id)?;

        // Update the extension's state.
        self.enumerable._remove_token_from_owner_enumeration(
            owner,
            token_id,
            &self.erc721,
        )?;
        self.enumerable._remove_token_from_all_tokens_enumeration(token_id);

        Ok(())
    }

    fn mint(&mut self, to: Address, token_id: U256) -> Result<(), Error> {
        self.erc721._mint(to, token_id)?;

        // Update the extension's state.
        self.enumerable._add_token_to_all_tokens_enumeration(token_id);
        self.enumerable._add_token_to_owner_enumeration(
            to,
            token_id,
            &self.erc721,
        )?;

        Ok(())
    }

    fn safe_transfer_from(
        &mut self,
        from: Address,
        to: Address,
        token_id: U256,
    ) -> Result<(), Error> {
        // Retrieve the previous owner.
        let previous_owner = self.erc721.owner_of(token_id)?;

        self.erc721.safe_transfer_from(from, to, token_id)?;

        // Update the extension's state.
        self.enumerable._remove_token_from_owner_enumeration(
            previous_owner,
            token_id,
            &self.erc721,
        )?;
        self.enumerable._add_token_to_owner_enumeration(
            to,
            token_id,
            &self.erc721,
        )?;

        Ok(())
    }

    #[selector(name = "safeTransferFrom")]
    fn safe_transfer_from_with_data(
        &mut self,
        from: Address,
        to: Address,
        token_id: U256,
        data: Bytes,
    ) -> Result<(), Error> {
        // Retrieve the previous owner.
        let previous_owner = self.erc721.owner_of(token_id)?;

        self.erc721.safe_transfer_from_with_data(from, to, token_id, data)?;

        // Update the extension's state.
        self.enumerable._remove_token_from_owner_enumeration(
            previous_owner,
            token_id,
            &self.erc721,
        )?;
        self.enumerable._add_token_to_owner_enumeration(
            to,
            token_id,
            &self.erc721,
        )?;

        Ok(())
    }

    fn transfer_from(
        &mut self,
        from: Address,
        to: Address,
        token_id: U256,
    ) -> Result<(), Error> {
        // Retrieve the previous owner.
        let previous_owner = self.erc721.owner_of(token_id)?;

        self.erc721.transfer_from(from, to, token_id)?;

        // Update the extension's state.
        self.enumerable._remove_token_from_owner_enumeration(
            previous_owner,
            token_id,
            &self.erc721,
        )?;
        self.enumerable._add_token_to_owner_enumeration(
            to,
            token_id,
            &self.erc721,
        )?;

        Ok(())
    }

    fn supports_interface(interface_id: FixedBytes<4>) -> bool {
        Erc721::supports_interface(interface_id)
            || Erc721Enumerable::supports_interface(interface_id)
    }
}