ARC69 NFT Metadata and IPFS Integration

This tutorial guides you through creating an ARC69-compliant NFT with metadata stored on the blockchain and the image hosted on IPFS. It complements the video tutorial.

YouTube Tutorial

Generating an Account

Use the following Python code to generate a new account for managing your ARC69 assets:

from algosdk.account import generate_account

private_key, address = generate_account()
print(private_key, address)

Funding the Account

Once the account is generated, it needs funding to submit transactions. Visit the Algorand Testnet Faucet to add funds.

Displaying the NFT Image

For this tutorial, the image used is "Charmander.png". Make sure to place this image in the public/images/ directory and reference it appropriately. Here’s the file path:

Charmander NFT Image

ARC69 Metadata Structure

In an ARC69 NFT, the image is immutable, but metadata (stored in the note field) can be updated. Images are hosted off-chain on IPFS, which ensures efficient and decentralized storage.

In this example, we’ll use Pinata as our IPFS service. Generate an API key, secret, and JWT on Pinata and store them in your .env file.

Example Code: Minting an ARC69 NFT

Below is a code snippet for minting an ARC69 NFT, including metadata in the note field. This code uploads the image to IPFS and sets up the NFT on Algorand.

from algosdk.v2client.algod import AlgodClient
from algosdk.transaction import wait_for_confirmation, AssetConfigTxn
from dotenv import load_dotenv
from pinata import Pinata
from algosdk.account import address_from_private_key
import os
import json

load_dotenv()

pinata_api_key = os.getenv('api_key')
pinata_api_secret = os.getenv('api_secret')
pinata_jwt = os.getenv('jwt')
pinata_client = Pinata(api_key=pinata_api_key, secret_key=pinata_api_secret, access_token=pinata_jwt)

algod_token = os.getenv('algod_token')
algod_server = os.getenv('algod_server')
algod_client = AlgodClient(algod_token, algod_server)

private_key = os.getenv('private_key')
address = address_from_private_key(private_key)

# Minting ARC69 NFT
image_path = './charmander.png'
response = pinata_client.pin_file(image_path)
image_ipfs_hash = response['data']['IpfsHash']
viewable_hash = f'https://gateway.pinata.cloud/ipfs/' + image_ipfs_hash

metadata = {
    "standard": "arc69",
    "mime_type": "image/png",
    "properties": {
        "Type": "Fire",
        "Description": "A fire pokemon with a fiery tail",
        "Level": "1",
        "Experience": "0",
    }
}

params = algod_client.suggested_params()

asset_config_transaction = AssetConfigTxn(
    sender=address,
    sp=params,
    total=1,
    decimals=0,
    default_frozen=False,
    manager=address,
    reserve=address,
    asset_name="Test Charmander",
    unit_name="TC#1",
    url=viewable_hash,
    strict_empty_address_check=False,
    note=json.dumps(metadata).encode()
)

signed_ac_tx = asset_config_transaction.sign(private_key)
tx_id = algod_client.send_transaction(signed_ac_tx)
print(tx_id)

wait_for_confirmation(algod_client, tx_id)
asset_index = algod_client.pending_transaction_info(tx_id)['asset-index']
print(asset_index)
    

Example Code: Updating ARC69 Metadata

After minting, you can update specific metadata fields, such as experience or level, by sending an asset configuration transaction with updated metadata in the note field.

metadata = {
    "standard": "arc69",
    "mime_type": "image/png",
    "properties": {
        "Type": "Fire",
        "Description": "A fire pokemon with a fiery tail",
        "Level": "4",
        "Experience": "15",
    }
}

asset_config_transaction = AssetConfigTxn(
    index=asset_index,
    sender=address,
    sp=params,
    manager=address,
    reserve=address,
    strict_empty_address_check=False,
    note=json.dumps(metadata).encode()
)

signed_ac_tx = asset_config_transaction.sign(private_key)
tx_id = algod_client.send_transaction(signed_ac_tx)
print(tx_id)

Code Editor