Aptos Token(Nft)

Non-Fungible Token

Overview of NFT

An NFT is a non-fungible token or data stored on a blockchain that uniquely defines ownership of an asset. NFTs were first defined in EIP-721 and later expanded upon in EIP-1155. NFTs are typically defined using the following properties:

  • name: The name of the asset. It must be unique within a collection.

  • description: The description of the asset.

  • uri: A URL pointer to off-chain for more information about the asset. The asset could be media such as an image or video or more metadata.

  • supply: The total number of units of this NFT. Many NFTs have only a single supply, while those that have more than one are referred to as editions.

Additionally, most NFTs are part of a collection or a set of NFTs with a common attribute, for example, a theme, creator, or minimally contract. Each collection has a similar set of attributes:

  • name: The name of the collection. The name must be unique within the creator's account.

  • description: The description of the collection.

  • uri: A URL pointer to off-chain for more information about the asset. The asset could be media such as an image or video or more metadata.

  • supply: The total number of NFTs in this collection.

  • maximum: The maximum number of NFTs that this collection can have. If maximum is set to 0, then supply is untracked.

Token resources

As shown in the diagram above, token-related data are stored at both the creator’s account and the owner’s account.

Struct-level resources

The following tables describe fields at the struct level. For the definitive list, see the Aptos Token Framework.

Resource stored at the creator’s address

Field
Description

Maintains a table called collection_data, which maps the collection name to the CollectionData. It also stores all the TokenData that this creator creates.

Stores the collection metadata. The supply is the number of tokens created for the current collection. The maxium is the upper bound of tokens in this collection.

Specifies which field is mutable.

Acts as the main struct for holding the token metadata. Properties is a where users can add their own properties that are not defined in the token data. Users can mint more tokens based on the TokenData, and those tokens share the same TokenData.

Controls which fields are mutable.

An ID used for representing and querying TokenData on-chain. This ID mainly contains three fields including creator address, collection name and token name.

Specifies the denominator and numerator for calculating the royalty fee. It also has the payee account address for depositing the royalty.

PropertyValue

Contains both value of a property and type of property.

Resource stored at the owner’s address

Field
Description

The main struct for storing the token owned by this address. It maps TokenId to the actual token.

The amount is the number of tokens.

TokenDataId points to the metadata of this token. The property_version represents a token with mutated PropertyMap from default_properties in the TokenData.

For more detailed descriptions, see Aptos Token Framework.

Token creation

Every Aptos token belongs to a collection. The developer first needs to create a collection through create_collection_script and then create the token belonging to the collection create_token_script. To achieve parallel TokenData and Token creation, a developer can create unlimited collection and TokenData where the maximum of the collection and TokenData are set as 0. With this setting, the token contract won’t track the supply of types of token (TokenData count) and supply of token within each token type. As the result, the TokenData and token can be created in parallel.

/// create a empty token collection with parameters
public entry fun create_collection_script(
        creator: &signer,
        name: String,
        description: String,
        uri: String,
        maximum: u64,
        mutate_setting: vector<bool>,
    ) acquires Collections {
    
/// create token with raw inputs
 public entry fun create_token_script(
        account: &signer,
        collection: String,
        name: String,
        description: String,
        balance: u64,
        maximum: u64,
        uri: String,
        royalty_payee_address: address,
        royalty_points_denominator: u64,
        royalty_points_numerator: u64,
        mutate_setting: vector<bool>,
        property_keys: vector<String>,
        property_values: vector<vector<u8>>,
        property_types: vector<String>
    ) acquires Collections, TokenStore {    

Aptos also enforces simple validation of the input size and prevents duplication:

  • Token name - unique within each collection

  • Collection name - unique within each account

  • Token and collection name length - smaller than 128 characters

  • URI length - smaller than 512 characters

  • Property map - can hold at most 1000 properties, and each key should be smaller than 128 characters

Token burn

We provide burn and burn_by_creator functions for token owners and token creators to burn (or destroy) tokens. However, these two functions are also guarded by configs that are specified during the token creation so that both creator and owner are clear on who can burn the token. Burn is allowed only when the BURNABLE_BY_OWNER property is set to true in default_properties. Burn by creator is allowed when BURNABLE_BY_CREATOR is true in default_properties. Once all the tokens belonging to a TokenData are burned, the TokenData will be removed from the creator’s account. Similarly, if all TokenData belonging to a collection are removed, the CollectionData will be removed from the creator’s account.

/// The token is owned at address owner
    public entry fun burn_by_creator(
        creator: &signer,
        owner: address,
        collection: String,
        name: String,
        property_version: u64,
        amount: u64,
    ) acquires Collections, TokenStore {
    
/// Burn a token by the token owner
    public entry fun burn(
        owner: &signer,
        creators_address: address,
        collection: String,
        name: String,
        property_version: u64,
        amount: u64
    ) acquires Collections, TokenStore {

Token transfer

We provide three different modes for transferring tokens between the sender and receiver.

Two-step transfer

To protect users from receiving undesired NFTs, they must be first offered NFTs, and then accept the offered NFTs. Then only the offered NFTs will be deposited in the users' token stores. This is the default token transfer behavior. For example:

  1. If Alice wants to send Bob an NFT, she must first offer Bob this NFT. This NFT is still stored under Alice’s account.

  2. Only when Bob claims the NFT, will the NFT be removed from Alice’s account and stored in Bob’s token store.

Transfer with opt-in

If a user wants to receive direct transfer of the NFT, skipping the initial steps of offer and claim, then the user can call opt_in_direct_transfer to allow other people to directly transfer the NFTs into the user's token store. After opting into direct transfer, the user can call transfer to transfer tokens directly. For example, Alice and anyone can directly send a token to Bob's token store once Bob opts in.

public entry fun opt_in_direct_transfer(
         account: &signer,
         opt_in: bool
         ) acquires TokenStore {

/// Transfers `amount` of tokens from `from` to `to`.
/// The receiver `to` has to opt-in direct transfer first
public entry fun transfer_with_opt_in(
        from: &signer,
        creator: address,
        collection_name: String,
        token_name: String,
        token_property_version: u64,
        to: address,
        amount: u64,
    ) acquires TokenStore {

Multi-agent transfer

The sender and receiver can both sign a transfer transaction to directly transfer a token from the sender to receiver direct_transfer_script. For example, once Alice and Bob both sign the transfer transaction, the token will be directly transferred from Alice's account to Bob.

public entry fun direct_transfer_script(
        sender: &signer,
        receiver: &signer,
        creators_address: address,
        collection: String,
        name: String,
        property_version: u64,
        amount: u64,
    ) acquires TokenStore {

Last updated