🔃Deploy and Interact

This section covers deploying the contract, initializing it, and interacting with it on the testnet.

Step 1: Build the Smart Contract

To build the smart contract, use the following command.

cargo concordium build --verifiable docker.io/concordium/verifiable-sc:1.70.0 -o module.wasm.v1 -e

When you run the command, you'll see the following:

Note the following:

  • This build embeds the schema, so you no longer have to keep the schema as a separate compilation output.

  • Concordium strongly recommends the use of embedded schema.

  • You should run Docker on your system and let it pull the required image.

  • Ensure verifiability by including the --verifiable flag to verify that the contract source matches the deployed module.

  • You should run Docker on your system and let it pull the required image.

  • Do not include the Cargo.lock file in .gitignore.

Step 2: Deploy the Contract

Deploy the module using the following command:

concordium-client module deploy module.wasm.v1 --sender <YOUR_ACCOUNT_ADDRESS>
 --name <YOUR_CONTRACT_NAME> --grpc-port 20000 --grpc-ip node.testnet.concordium.com

When you run the command, you should see the following:

Step 3: Initialize the Contract

Initialize the contract with the specified parameters:

concordium-client contract init <MODULE-REF> --sender <YOUR_ACCOUNT_ADDRESS> --energy 30000 --contract cis2_dynamic_nft --grpc-port 20000 --grpc-ip node.testnet.concordium.com

Your contract will be initialized as follows:

Step 4: Mint Tokens

Mint tokens for different states of our pet, each represented by metadata. The metadata and images are publicly available on IPFS for demonstration purposes.

Little Puppy CIS2 Compatible Metadata File

{
  "name": "Little Puppy",
  "unique": true,
  "description": "My baby",
  "display": {
    "url": "https://ipfs.io/ipfs/Qmedq3GPcMtePE24NGrVmbi4XZRFnPTQNM47XnwismcBGx"
  },
  "attributes": [
    {
      "type": "string",
      "name": "Fluffy",
      "value": "999"
    }
  ]
}

Cool Boy CIS2 Compatible Metadata File

{
  "name": "Cool Boy",
  "unique": true,
  "description": "Good looking, funny and my best friend.",
  "display": {
    "url": "https://ipfs.io/ipfs/QmWyTzZZKcEfhuW1hArMFhFacp5PBYC1tWN4sEjoAVYhWh"
  },
  "attributes": [
    {
      "type": "string",
      "name": "Charisma",
      "value": "999"
    }
  ]
}

Strong Dog CIS2 Compatible Metadata File

{
  "name": "Strong Dog",
  "unique": true,
  "description": "Powerful, strong and my hero.",
  "display": {
    "url": "https://ipfs.io/ipfs/QmdxwBZ2vLTeS8bRaNLXYLZ28KtJi1x3q6a1eKuSyQKErG"
  },
  "attributes": [
    {
      "type": "string",
      "name": "Power",
      "value": "999"
    }
  ]
}

Step 5: Create MintParams JSON File

Create a JSON file for MintParams, including the owner's address and the tokens to be minted. Ensure that it matches the struct defined in the smart contract. Follow these guidelines:

  • Struct Requirements: Remember the struct you created in the smart contract; it requires an owner and corresponding tokens. Each token entry should hold a list of MetadataUrl for a token ID and its amount.

  • Metadata Selection: You will include only the first two metadata entries to facilitate addMetadata and upgrade functions testing.

  • IPFS Upload: Don't forget to upload the metadata files to IPFS. When minting a token, provide a hyperlink to the metadata file and optionally include the SHA(256) hash of the content.

Here's an example JSON file structure:

{
    "owner": {
        "Account": [
            "<YOUR-ADDRESS>"
        ]
    },
    "tokens": [
        [
            "01",
            {
                "metadata_url": [
                    {
                        "url": "https://ipfs.io/ipfs/Qmc7HPBm18uLEGcA7FZztEUzjc5UAbsqkXPHupNPfMw1SN",
                        "hash": {
                            "Some": [
                                "7cf0a806783a71d25d03dacb94c80109c3d5e66986b987cc6eb68c7da75cb1a6"
                            ]
                        }
                    },
                    {
                        "url": "https://ipfs.io/ipfs/QmX2QxwLvJkLqnEXvca6MpmLjNAPygenJwQg1iP4EdNKDg",
                        "hash": {
                            "Some": [
                                "197738868672d271a5fa81353b4d97ba977c3002ca095b482bdd74b89be22fb7"
                            ]
                        }
                    }
                ],
                "token_amount": "1"
            }
        ]
    ]
}

Step 6: Mint the Token

Mint the token using the created MintParams JSON file and run the following command:

concordium-client contract update <CONTRACT-INDEX> --entrypoint mint --parameter-json mint-params.json --sender <YOUR-ACCOUNT> --energy 30000 --grpc-port 20000 --grpc-ip node.testnet.concordium.com

When you run the command, you will see the following in your terminal:

Step 7: Verify Token Minting

After successfully minting the token, verify its presence in your wallet with the following:

  1. Open your Concordium wallet.

  2. Navigate to the section displaying your assets or tokens.

  3. Look for the newly minted token.

  4. Verify that the token appears correctly with the expected metadata and attributes.

The screenshot below shows the wallet:

Step 8: Upgrade Metadata

  1. Test whether this NFT is dynamic or not. You should be able to upgrade the metadata and evolve this little puppy into a grown dog. The upgrade function requires the token ID as a string in the JSON file.

"01"
  1. Run the following command to upgrade the metadata:

concordium-client contract update <YOUR-CONTRACT-INDEX> --entrypoint upgrade --parameter-json upgrade.json --sender <YOUR-ADDRESS> --energy 30000 --grpc-port 20000 --grpc-ip node.testnet.concordium.com

After running the command, you will see the following in your terminal:

  1. The transaction is now complete. Go to the wallet and verify:

Note that an oracle or any other interaction can trigger this step.

Step 9: Add Metadata

Finalize the tutorial by adding new metadata to the contract. Let's make the dog evolve even more.

  1. Check the AddParams struct to create the right form of JSON file. It expects tokensthat holds both token ID and MetadataUrl which is essentially url and hash:

{
    "tokens": [
        [
            "01",
            {
                "url": "https://ipfs.io/ipfs/Qmc7HPBm18uLEGcA7FZztEUzjc5UAbsqkXPHupNPfMw1SN",
                "hash": {
                    "Some": [
                        "7cf0a806783a71d25d03dacb94c80109c3d5e66986b987cc6eb68c7da75cb1a6"
                    ]
                }
            }
        ]
    ]
}
  1. Wait for the transaction's finalization as follows:

  1. Upgrade it once again with the same command in the previous step:

  1. Check your wallet to see the change that has been made:

Step 10: View Token Metadata History

  1. To view the history of the token metadata, follow these steps:

    • Invoke the tokenMetadataList function to view it.

    • The tokenMetadataList function should accept a vector of token IDs to return:

      • All the tokens in the contract.

      • The history of the tokens in the form of a TokenMetadataList struct, which is defined as Vec<Vec<MetadataUrl>>.

[
    "01"
] 
  1. Invoke the tokenMetadataList function to view the token's history:

concordium-client contract invoke <YOUR-CONTRACT-INDEX> --entrypoint tokenMetadataList --parameter-json history.json --energy 30000 --grpc-port 20000 --grpc-ip node.testnet.concordium.com

When you run the command, you will be able to see all previous forms of the token you have from the contract state:

Last updated