Contractless/docs/NFT_TRANSACTIONS.md

14 KiB

NFT Transactions

Contractless supports native NFT creation, NFT lookup, NFT transfers, NFT burns, and NFT use inside swaps or loan collateral. This guide focuses on NFT creation and lookup tools, metadata requirements, IPFS/RWA preparation, and the difference between standalone NFTs and collections.

Contractless stores the NFT transaction and the metadata CID on chain. It does not store your image, media, document, or full metadata JSON on chain. You must upload and pin those files before creating the NFT transaction.

Important permanence note: Anyone who owns an NFT or RWA should run a local IPFS node and pin the metadata and media for the NFTs/RWAs they care about. On other chains, NFT platforms and hosting services have disappeared in the past, causing people to lose access to the images, documents, or metadata tied to assets they still technically owned on chain. Pinning your own NFTs and RWAs helps ensure the data continues to exist even if the seller, marketplace, minting platform, or public gateway goes offline.

CLI Tools

NFT-related CLI tools:

Tool Purpose
create_nft_tx Creates and signs a new NFT creation transaction JSON.
lookup_nft Looks up one NFT by name and item number.
lookup_nft_list Lists NFTs known to the connected node.

On Windows, add .exe to each command name.

When a tool asks for a wallet path or file path, press <Tab> to search and auto-complete files and folders.

NFT Creation Transaction Fields

The NFT creation transaction is transaction type 4.

Struct fields:

Field Size Meaning
txtype 1 byte Transaction type. For NFT creation this is 4.
time / timestamp 4 bytes UTC timestamp when the transaction is created.
creator 22 bytes Creator short address.
series 1 byte 0 for a standalone NFT, 1 for a collection/series.
nft_name 15 bytes Unique NFT or collection name, padded to 15 bytes.
item_ipfs 100 bytes Metadata CID, padded to 100 bytes.
count 4 bytes 1 for standalone NFTs; collection item count for series NFTs.
desc 100 bytes Short on-chain description, padded to 100 bytes.
txfee 8 bytes Fee paid by creator in base currency. Minimum is 0.5 CLC or CLTC.
signature 666 bytes Creator signature.

Important limits:

  • NFT names must normalize to 3 to 15 alphanumeric characters.
  • NFT names must be unique. First confirmed creation gets the name.
  • item_ipfs must be a CID and must fit in the fixed 100 byte field.
  • desc is only a short on-chain description. Use the off-chain metadata JSON for full descriptions.
  • Standalone NFTs must use series = 0 and count = 1.
  • Collections must use series = 1 and count >= 2.

Standalone NFT vs Collection vs RWA

Standalone NFT

A standalone NFT is one item. It uses:

series = 0
count = 1

The wallet and lookup tooling refer to standalone NFTs with item number 0.

Use a standalone NFT for:

  • One-of-one artwork.
  • A single certificate.
  • A single RWA record.
  • A single media item.

Collection / Series

A collection creates many numbered NFTs from one creation transaction. It uses:

series = 1
count = <number of items>

If count = 100, the chain creates 100 numbered NFT assets:

collectionname_1
collectionname_2
collectionname_3
...
collectionname_100

The creator receives all items at creation. This means if you create a large series, every NFT in that series appears in your wallet until you transfer, swap, burn, or lock those items as collateral.

This matters for wallet usability. A 10,000 item series creates 10,000 owned NFT records immediately. The GUI paginates NFTs, but large collections still mean more wallet data and more metadata to cache over time.

Use a collection for:

  • Generative art collections.
  • Trading-card style collections.
  • Ticket batches.
  • Numbered certificate sets.
  • Numbered RWA records.

RWA / Non-Image NFT

An RWA is not a separate on-chain transaction type. It is an NFT whose metadata describes a real-world asset or non-image record.

Use an RWA NFT for:

  • Equipment certificates.
  • Property or inventory records.
  • Authenticity certificates.
  • Legal or business documents.
  • Membership or access records.

RWA metadata should include normal NFT fields plus a contractless object that identifies it as an RWA.

IPFS Hosting

Contractless does not provide IPFS hosting. Before creating an NFT, upload and pin your metadata and media files with a provider.

Hosting providers that currently offer IPFS or decentralized storage services include:

Public gateways can be checked here:

https://ipfs.github.io/public-gateway-checker/

Active gateways can still fail to return specific data if they cannot find or stream a provider. The default GUI gateway is:

https://gateway.pinata.cloud/ipfs/

Metadata Rules

Contractless follows common NFT metadata conventions. The chain does not enforce every JSON field, but the GUI wallet expects common fields so it can display names, descriptions, images, traits, and RWA details.

Recommended common fields:

Field Purpose
name User-facing NFT name.
description Full description shown in wallets and marketplaces.
image Image URI, usually ipfs://....
image_url Optional image URI fallback.
animation_url Optional video, audio, HTML, or animation URI.
external_url Optional website or public detail page.
attributes Trait list.
contractless Optional Contractless-specific metadata, especially for RWAs.

Use ipfs:// URIs inside metadata. The wallet converts them through the configured IPFS gateway.

Single Image NFT Metadata

For a standalone NFT, upload the image first. Then upload one metadata JSON file. Use the CID of that metadata JSON in create_nft_tx.

Example:

{
  "name": "Example Artwork #1",
  "description": "A short description of the NFT.",
  "image": "ipfs://IMAGE_CID/example.png",
  "external_url": "https://example.com/nft/1",
  "attributes": [
    { "trait_type": "Background", "value": "Blue" },
    { "trait_type": "Edition", "value": "1 of 1" }
  ]
}

For this format:

  • item_ipfs should be the CID of the metadata JSON.
  • series should be 0.
  • count should be 1.
  • lookup_nft <name> 0 is used for lookup.

Collection / Series Metadata

For a collection, pin one parent folder that contains both a metadata folder and an images folder. Use the CID of the parent folder in the NFT transaction.

Do not use:

  • The CID of one numbered JSON file.
  • The CID of the metadata folder alone.
  • The CID of the images folder alone.

Use the CID of this parent folder:

collection-root/        <- use this folder CID in the transaction
  metadata/
    1.json
    2.json
    3.json

  images/
    1.png
    2.png
    3.png

The GUI wallet builds metadata paths like:

ipfs://PARENT_FOLDER_CID/metadata/1.json
ipfs://PARENT_FOLDER_CID/metadata/2.json
ipfs://PARENT_FOLDER_CID/metadata/3.json

Each numbered JSON file should describe one item and point to the matching image.

Example metadata/1.json:

{
  "name": "Example Collection #1",
  "description": "Item 1 from Example Collection.",
  "image": "ipfs://PARENT_FOLDER_CID/images/1.png",
  "attributes": [
    { "trait_type": "Background", "value": "Blue" },
    { "trait_type": "Rarity", "value": "Common" }
  ]
}

For this format:

  • item_ipfs should be the CID of collection-root/.
  • series should be 1.
  • count should match the number of JSON files/items.
  • lookup_nft <name> 1 looks up item 1.
  • lookup_nft <name> 2 looks up item 2.

The current CLI lookup_nft output formats series IPFS display as ipfs://<CID>/<series>.json. The GUI wallet uses the recommended metadata/<series>.json path. For collection creation, follow the parent-folder structure above.

RWA / Non-Image Metadata

For a real-world asset or non-image NFT, keep the common NFT fields and add structured details under attributes and contractless.

Example:

{
  "name": "Equipment Certificate #42",
  "description": "Ownership record for a physical asset.",
  "image": "ipfs://IMAGE_CID/certificate-preview.png",
  "external_url": "https://example.com/certificates/42",
  "attributes": [
    { "trait_type": "Asset Type", "value": "Equipment" },
    { "trait_type": "Serial Number", "value": "EQ-2026-0042" },
    { "trait_type": "Issuer", "value": "Example Agency" }
  ],
  "contractless": {
    "metadata_type": "rwa",
    "issuer": "Example Agency",
    "document": "ipfs://DOCUMENT_CID/asset-record.pdf",
    "jurisdiction": "US",
    "record_date": "2026-07-12"
  }
}

For RWA records:

  • Use contractless.metadata_type = "rwa" so the GUI can label the NFT as an RWA.
  • Use image for a preview image or certificate preview.
  • Use contractless.document for the primary document if there is one.
  • Avoid putting private personal data in public metadata. IPFS data is public if the CID is shared or discovered.

RWAs can be standalone or collections. For example, one equipment certificate can be standalone, while a batch of numbered tickets or certificates can be a collection.

create_nft_tx

Creates a signed NFT creation transaction JSON and saves it under:

./transactions/<hash>.json

The command prints the signed JSON to the terminal. Creating the file does not guarantee the transaction is mined. Broadcast the transaction with broadcast_transaction or through the GUI wallet.

Usage:

create_nft_tx

Interactive prompts:

Are you creating a 1/1 or a collection?
Please enter the name for your NFT. This can be 3 to 15 characters and must be 100% unique. First come first serve:
Enter your IPFS CID for your NFT. This will be stored in a fixed 100 character field, so shorter CIDs are padded with spaces:
Please enter the number of items in your collection, enter 1 for 1/1s:
Enter your nft description, A max of 100 characters:
Please enter the amount for the fee: (eg. 0.005, minimum fee 0.50000000):
Please enter the path to your wallet file:
What is your wallet decryption key?

Prompt notes:

Prompt What To Enter
1/1 or collection Enter collection for a collection. Anything else is treated as standalone.
NFT name Unique 3 to 15 character alphanumeric name.
IPFS CID Standalone: metadata JSON CID. Collection: parent folder CID.
Number of items 1 for standalone. Collection count for series.
Description Short on-chain description, max 100 characters.
Fee Minimum 0.5 CLC or CLTC.
Wallet path Path to the creator wallet file. Use <Tab> for completion.
Wallet key Creator wallet decryption key.

Output JSON shape:

{
  "txtype": 4,
  "timestamp": 1780000000,
  "creator": "creator_short_address.cltc",
  "series": 0,
  "nft_name": "example        ",
  "item_ipfs": "bafy...padded...",
  "count": 1,
  "desc": "short description padded...",
  "txfee": 50000000,
  "hash": "transaction_hash",
  "signature": "creator_signature"
}

lookup_nft

Looks up one NFT by NFT name and item number.

Usage:

lookup_nft <nft_name> <item_number>

Use item number 0 for a standalone NFT:

lookup_nft example 0

Use item numbers 1 through count for collection items:

lookup_nft example 1
lookup_nft example 2

Interactive prompts:

Please enter the path to your wallet file:
What is your wallet decryption key?

The wallet is used for authenticated RPC handshake. The lookup itself does not spend funds.

Expected output shape:

{
  "nft_name": "example",
  "series": 1,
  "ipfs": "ipfs://CID/1.json",
  "asset_name": "example_1",
  "genesis": "creation_txid",
  "creator": "creator_short_address.cltc",
  "current_holder": "holder_short_address.cltc",
  "history_count": 1,
  "history": [
    {
      "txid": "transaction_id",
      "block": 123,
      "txtype": 4,
      "action": "create_nft",
      "to": "creator_short_address.cltc"
    }
  ]
}

Common history actions:

Action Meaning
create_nft NFT was created.
transfer NFT was transferred.
swap NFT moved through a swap.
loan_locked NFT was locked as loan collateral.
loan_payment NFT moved through loan payment handling.
collateral_claimed NFT collateral was claimed.
loan_issued NFT moved as part of loan issuance.

lookup_nft_list

Returns the NFT list known to the connected peer.

Usage:

lookup_nft_list

Interactive prompts:

Please enter the path to your wallet file:
What is your wallet decryption key?

Expected output shape:

{
  "nfts": {
    "creation_txid": [
      {
        "nft_name": "example",
        "series": 0
      },
      {
        "nft_name": "collection",
        "series": 1
      }
    ]
  }
}

The list is grouped by creation transaction hash. A collection can produce many rows under the same creation hash because each numbered item is its own NFT asset.

Ownership and Wallet Display

NFT balances are tracked like native assets, but NFTs use a fixed unit internally. Wallets display NFT ownership based on whether the active address has a positive balance for that NFT asset.

Standalone ownership:

asset = example
series = 0

Collection ownership:

asset = collection
series = 1
asset = collection
series = 2
asset = collection
series = 3

When you create a collection, the creator receives every item from 1 through count. If you create a large collection, expect the NFT page to show many items.

NFT Transfers, Burns, Swaps, and Loans

NFTs can be used by other native transaction types:

  • Transfer: move the NFT to another address.
  • Burn: destroy the NFT.
  • Swap: trade the NFT for another asset.
  • Loan collateral: lock the NFT as collateral.
  • Collateral claim: transfer locked NFT collateral when claim rules are met.

For numbered collection items, the transaction must include the correct NFT series/item number. For standalone NFTs, the series is 0.

Details for those transaction flows are covered in the transfer, burn, swap, and loan documentation.