Skip to main content

Creating an NFT project

This guide follows the below workflow:

  1. Creating your project
  2. Customizing your token parameters
  3. Deploying your token contract
  4. Minting and sending tokens
  5. Building the NFT dApp


Non-Fungible Tokens, or NFTs, have been a hot topic during this past year. They've quickly become an essential component of the decentralized digital world.

In this guide, we will learn how to write, deploy, mint and transfer our own NFTs. We'll also learn how to build a dApp website we can share with other users, so they can also mint and transfer tokens.

Creating your project#

In the Setup section we learned how to create and configure a new Archway project.

If you haven't created a project before, navigate to Setup to learn what to install and familiarize yourself with so you can complete this step.

Now let’s create a new project, and on the template selection list select the CW721 with on-chain metadata template.

$ archway new basic-nftCreating new Archway project...✔ Do you want to use a starter template? … yes? Choose a template › - Use arrow-keys. Return to submit.    Increment    CW20    CW721 with off-chain metadata❯   CW721 with on-chain metadata    [] Select a testnet to use › Constantine🔧   Generating template ...[ 1/35]   Done: .cargo/config# and so on, until... create mode 100644 schema/tokens_response.json create mode 100644 src/
Successfully created project basic-nft with network configuration constantine-1$ cd basic-nft

Designing Your Tokens#

The asset metadata is a critical element for any NFT. It defines information like the name, image URL, and other properties that can be pulled by NFT marketplaces to show relevant information for the users. Things like rarity, custom traits, etc., all are stored here.

In this example, we will keep our metadata on-chain. In other words, the contract will store the metadata in its internal state.

In the cw721-base code, NFT metadata is contained in the extension property of the TokenInfo struct:

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]pub struct TokenInfo<T> {    /// The owner of the newly minted NFT    pub owner: Addr,    /// Approvals are stored here, as we clear them all upon transfer and cannot accumulate much    pub approvals: Vec<Approval>,
    /// Universal resource identifier for this NFT    /// Should point to a JSON file that conforms to the ERC721    /// Metadata JSON Schema    pub token_uri: Option<String>,
    /// You can add any custom metadata here when you extend cw721-base    pub extension: T,}

To use this extension property, here's how we define our metadata in the CW721 with on-chain metadata template we cloned into our project.

#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]pub struct Trait {    pub display_type: Option<String>,    pub trait_type: String,    pub value: String,}
#[derive(Serialize, Deserialize, Clone, PartialEq, JsonSchema, Debug, Default)]pub struct Metadata {    pub image: Option<String>,    pub image_data: Option<String>,    pub external_url: Option<String>,    pub description: Option<String>,    pub name: Option<String>,    pub attributes: Option<Vec<Trait>>,    pub background_color: Option<String>,    pub animation_url: Option<String>,    pub youtube_url: Option<String>,}

This code is located in src/ of your project, you can also view it at