# How to add NFT metadata to my Contract

**URL:** <https://forum.fuel.network/t/how-to-add-nft-metadata-to-my-contract/6271>\
**Category:** Sway\
**Tags:** testnet, feedback\
**Created:** [July 16, 2024, 10:28am UTC](https://forum.fuel.network/t/how-to-add-nft-metadata-to-my-contract/6271 "2024-07-16T10:28:19Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![mahesh\_d\_luffy](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@mahesh\_d\_luffy](https://forum.fuel.network/u/mahesh_d_luffy)\
**Post date:** [July 16, 2024, 10:28am UTC](https://forum.fuel.network/t/how-to-add-nft-metadata-to-my-contract/6271/1 "2024-07-16T10:28:19Z")

</div>

Hi Team could you help me to add metadata to my NFT contract ,

````auto
contract;

use standards::{src20::SRC20, src7::{Metadata, SRC7}, src3::SRC3};
use std::{
    asset::{
        burn,
        mint_to,
    },
    call_frames::msg_asset_id,
    constants::DEFAULT_SUB_ID,
    context::msg_amount,
    string::String,
};

configurable {
    /// The total supply of coins for the asset minted by this contract.
    TOTAL_SUPPLY: u64 = 1000,
    /// The decimals of the asset minted by this contract.
    DECIMALS: u8 = 9u8,
    /// The name of the asset minted by this contract.
    NAME: str[7] = __to_str_array("MyAsset"),
    /// The symbol of the asset minted by this contract.
    SYMBOL: str[5] = __to_str_array("MYTKN"),
    /// The metadata for the "social:x" key.
    SOCIAL_X: str[12] = __to_str_array("fuel_network"),
    /// The metadata for the "site:forum" key.
    SITE_FORUM: str[27] = __to_str_array("https://forum.fuel.network/"),
    /// The metadata for the "attr:health" key.
    ATTR_HEALTH: u64 = 100,
}

storage {
    /// The total supply of the asset minted by this contract.
    total_supply: u64 = 0,
    /// A flag to check if initial mint has been done.
    is_initialized: bool = false,
}

impl SRC7 for Contract {
    /// Returns metadata for the corresponding `asset` and `key`.
    ///
    /// # Arguments
    ///
    /// * `asset`: [AssetId] - The asset of which to query the metadata.
    /// * `key`: [String] - The key to the specific metadata.
    ///
    /// # Returns
    ///
    /// * [Option<Metadata>] - `Some` metadata that corresponds to the `key` or `None`.
    ///
    /// # Reverts
    ///
    /// * When the AssetId provided does not match the default SubId.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src7::{SRC7, Metadata};
    /// use std::string::String;
    ///
    /// fn foo(contract_id: ContractId, asset: AssetId) {
    /// let contract_abi = abi(SRC7, contract_id);
    /// let key = String::from_ascii_str("social:x");
    /// let data = contract_abi.metadata(asset, key);
    /// assert(data.unwrap() == Metadata::String(String::from_ascii_str("fuel_network")));
    /// }
    /// ```
    #[storage(read)]
    fn metadata(asset: AssetId, key: String) -> Option<Metadata> {
        require(asset == AssetId::default(), "Invalid AssetId provided");

        if key == String::from_ascii_str("social:x") {
            Some(Metadata::String(String::from_ascii_str(from_str_array(SOCIAL_X))))
        } else if key == String::from_ascii_str("site:forum") {
            Some(Metadata::String(String::from_ascii_str(from_str_array(SITE_FORUM))))
        } else if key == String::from_ascii_str("attr:health") {
            Some(Metadata::Int(ATTR_HEALTH))
        } else {
            None
        }
    }
}

impl SRC20 for Contract {
    #[storage(read)]
    fn total_assets() -> u64 {
        1
    }

    #[storage(read)]
    fn total_supply(asset: AssetId) -> Option<u64> {
        if asset == AssetId::default() {
            Some(storage.total_supply.read())
        } else {
            None
        }
    }

    #[storage(read)]
    fn name(asset: AssetId) -> Option<String> {
        if asset == AssetId::default() {
            Some(String::from_ascii_str(from_str_array(NAME)))
        } else {
            None
        }
    }

    #[storage(read)]
    fn symbol(asset: AssetId) -> Option<String> {
        if asset == AssetId::default() {
            Some(String::from_ascii_str(from_str_array(SYMBOL)))
        } else {
            None
        }
    }

    #[storage(read)]
    fn decimals(asset: AssetId) -> Option<u8> {
        if asset == AssetId::default() {
            Some(DECIMALS)
        } else {
            None
        }
    }
}

impl SRC3 for Contract {
    /// Unconditionally mints new assets using the default SubId.
    ///
    /// # Arguments
    ///
    /// * `recipient`: [Identity] - The user to which the newly minted asset is transferred to.
    /// * `sub_id`: [SubId] - The default SubId.
    /// * `amount`: [u64] - The quantity of coins to mint.
    ///
    /// # Number of Storage Accesses
    ///
    /// * Reads: `1`
    /// * Writes: `1`
    ///
    /// # Reverts
    ///
    /// * When the `sub_id` is not the default SubId.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src3::SRC3;
    /// use std::constants::DEFAULT_SUB_ID;
    ///
    /// fn foo(contract_id: ContractId) {
    /// let contract_abi = abi(SRC3, contract);
    /// contract_abi.mint(Identity::ContractId(contract_id), DEFAULT_SUB_ID, 100);
    /// }
    /// ```
    #[storage(read, write)]
    fn mint(recipient: Identity, sub_id: SubId, amount: u64) {
        require(sub_id == DEFAULT_SUB_ID, "Incorrect Sub Id");

        // Initialize total supply if not already initialized
        if !storage.is_initialized.read() {
            storage.total_supply.write(TOTAL_SUPPLY);
            storage.is_initialized.write(true);
        }

        // Increment total supply of the asset and mint to the recipient.
        storage
            .total_supply
            .write(amount + storage.total_supply.read());
        mint_to(recipient, DEFAULT_SUB_ID, amount);
    }

    /// Unconditionally burns assets sent with the default SubId.
    ///
    /// # Arguments
    ///
    /// * `sub_id`: [SubId] - The default SubId.
    /// * `amount`: [u64] - The quantity of coins to burn.
    ///
    /// # Number of Storage Accesses
    ///
    /// * Reads: `1`
    /// * Writes: `1`
    ///
    /// # Reverts
    ///
    /// * When the `sub_id` is not the default SubId.
    /// * When the transaction did not include at least `amount` coins.
    /// * When the transaction did not include the asset minted by this contract.
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src3::SRC3;
    /// use std::constants::DEFAULT_SUB_ID;
    ///
    /// fn foo(contract_id: ContractId, asset_id: AssetId) {
    /// let contract_abi = abi(SRC3, contract_id);
    /// contract_abi {
    /// gas: 10000,
    /// coins: 100,
    /// asset_id: asset_id,
    /// }.burn(DEFAULT_SUB_ID, 100);
    /// }
    /// ```
    #[payable]
    #[storage(read, write)]
    fn burn(sub_id: SubId, amount: u64) {
        require(sub_id == DEFAULT_SUB_ID, "Incorrect Sub Id");
        require(msg_amount() >= amount, "Incorrect amount provided");
        require(
            msg_asset_id() == AssetId::default(),
            "Incorrect asset provided",
        );
    
        // Decrement total supply of the asset and burn.
        let new_total_supply = storage.total_supply.read() - amount;
        storage.total_supply.write(new_total_supply);
        burn(DEFAULT_SUB_ID, amount);
    }
}

````

I have deployed the contract on testnet , not able to add NFT Metadata

---

<div class="post-metadata">

**Author:** ![Bixer](https://avatars.discourse-cdn.com/v4/letter/b/258eb7/32.png) [@Bixer](https://forum.fuel.network/u/Bixer)\
**Post date:** [July 16, 2024, 5:46pm UTC](https://forum.fuel.network/t/how-to-add-nft-metadata-to-my-contract/6271/2 "2024-07-16T17:46:34Z")

</div>

You need a write a storage write function an use it.  
Do you have cargo tests in rust written? Are you going to calling using the TypeScript SDK?

````auto
/// Set the metadata of an asset.
    ///
    /// # Arguments
    ///
    /// * `asset`: [AssetId] - The asset of which to set the metadata.
    /// * `metadata`: [Metadata] - The metadata to associate with the asset.
    ///
    /// # Reverts
    ///
    /// * When the caller is not the owner.
    ///
    /// # Number of Storage Accesses
    ///
    /// * Reads: `1`
    /// * Writes: `1`
    ///
    /// # Examples
    ///
    /// ```sway
    /// use src7::SRC7;
    /// use std::string::String;
    ///
    /// fn foo(contract_id: ContractId, asset: AssetId) {
    /// let contract_abi = abi(SRC7, contract_id);
    /// let metadata = Metadata {
    /// name: String::from("My NFT"),
    /// description: Some(String::from("This is my NFT")),
    /// image: Some(String::from("https://example.com/image.png")),
    /// external_url: None,
    /// animation_url: None,
    /// attributes: None,
    /// };
    /// contract_abi.set_metadata(asset, metadata);
    /// }
    /// ```
    #[storage(read, write)]
    fn set_metadata(asset: AssetId, metadata: Metadata) {
        only_owner();
        storage.metadata.insert(asset, metadata);
    }

````

---

<div class="post-metadata">

**Author:** ![naz3eh](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/naz3eh/32/2025_2.png) [@naz3eh](https://forum.fuel.network/u/naz3eh)\
**Post date:** [July 17, 2024, 5:56am UTC](https://forum.fuel.network/t/how-to-add-nft-metadata-to-my-contract/6271/3 "2024-07-17T05:56:20Z")

</div>

It seems that you haven’t imported the `metadata` from the `sway-libs`. You will need to add `use sway_libs::asset::metadata::*;` line at the top and then add the `SetMetaData` function in your contract.

I have put an example below and you can see how you can do it.

```auto
use sway_libs::asset::metadata::*;
use standards::src7::Metadata;
 
storage {
    metadata: StorageMetadata = StorageMetadata {},
}
 
impl SetAssetMetadata for Contract {
    #[storage(read, write)]
    fn set_metadata(asset: AssetId, key: String, metadata: Metadata) {
        _set_metadata(storage.metadata, asset, key, metadata);
    }
}

```

You can refer to the docs [here](https://docs.fuel.network/docs/sway-libs/asset/metadata/#importing-the-asset-library-metadata-functionality)

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex022/uploads/fuel/original/2X/5/57d5a345cc15a64b636e0d56e042857f8a0e80b1.png) [@system](https://forum.fuel.network/u/system)\
**Post date:** [August 7, 2024, 1:56am UTC](https://forum.fuel.network/t/how-to-add-nft-metadata-to-my-contract/6271/4 "2024-08-07T01:56:38Z")

</div>

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.
