Native Assets (NFTs/FTs)
Introduction
Cardano supports native assets—both Fungible Tokens (FTs) (like a custom currency) and Non-Fungible Tokens (NFTs) (unique collectibles). Anvil provides straightforward ways to mint, send, or burn these assets, whether they follow CIP-25 (the classic NFT metadata standard) or CIP-68 (a more advanced approach allowing evolving or updatable data).
In this section
We’ll show how CIP-25 metadata might be integrated in a transaction payload.
We’ll highlight how you can combine CIP-68 references similarly (should you want dynamic or updatable NFTs).
We’ll note how to incorporate these tokens into your transaction using mint or outputs.
NFTs vs. FTs: Dollar Bills vs. Art
Fungible Tokens (FT)
Analogy: Think of them like dollar bills—each bill has the same value and is interchangeable with any other.
1 FT = 1 FT, regardless of its “serial number.”
Use Cases:
In-Game Currencies: A consistent token players can trade.
Community Tokens: Reward points or governance tokens.
Stablecoins: Pegged to fiat currency.
Non-Fungible Tokens (NFT)
Analogy: Think of them like a one-of-a-kind painting—unique art with no duplicates.
1 NFT cannot simply be swapped for another NFT of the same “collection” because each is different.
Use Cases:
Digital Art & Collectibles: Rare items or artwork minted under a policy.
Event Tickets: Each ticket is unique, can’t be replaced by another.
Real-World Asset Tokens: Tokenizing property deeds, certificates, or identity credentials.
Policy IDs: The Artist’s Collection
Tokens on Cardano—whether NFT or FT—are grouped under a Policy ID.
Policy ID = A unique hash generated from a minting script or policy. See Native Scripts.
Collection: If an artist mints multiple NFTs under the same policy ID, they effectively form a “series” or “collection.”
Locking: The policy can be time-locked or multi-signature locked, controlling whether more tokens can be minted in the future.
In our analogy: Policy ID = The “brand” or “collection” label that says “all these paintings or bills come from the same source.”
CIP-25 / CIP-68 Metadata (for NFTs)
When you mint an NFT, you usually include metadata that describes the token’s name, image, description, attributes, etc. The most common metadata standards:
CIP-25 (Label 721): Legacy standard for NFT metadata, widely supported by wallets and marketplaces.
CIP-68: Newer approach that places more data in the on-chain datum, allowing dynamic NFTs or advanced features. Many still store a CIP-25–style JSON under label 721 for backward compatibility.
Example:
{
"version": "cip-25",
"assetName": {"name": "my_collection_nft_01", "format": "utf8"},
"metadata": {
"name": "My Collection NFT #1",
"image": "ipfs://QmExampleHash",
"mediaType": "image/png",
"description": "Unique artwork minted with the Anvil API",
"quantity": 1
}
}
Depending on your approach, you embed this in your transaction’s metadata—Anvil can help you structure that under label 721.
CIP-25 Payload
Minting
{
// Address to pay for the TX and receive any leftover ADA from the transaction.
"changeAddress": "addr_test1...",
// UTXOs from the wallet paying for fees (list of CBOR UTXOs)
"utxos": ["8282...", "8282..."],
// Message to include in the transaction
"message": "Asset minted with anvil api",
// Array of assets to mint
"mint": [
{
"version": "cip-25",
"assetName": {"name": "anvil_api_cip_25", "format": "utf8"},
"metadata": {
"name": "anvil_api_cip_25 #1",
"image": [
"https://ada-anvil.s3.ca-central-1.amazonaws.com/",
"logo_pres_V2_3.png"
],
"mediaType": "image/png",
"description": "Testing CIP-25 using anvil API",
},
"policyId": "4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfb",
"quantity": 1,
// Destination to send minted asset.
"destAddress": "addr_test1..."
}
],
// Optional but recommended for performance and latency. Required for new/unregistered scripts.
"preloadedScripts": [
{
"type": "simple",
"script": {
"type": "all",
"scripts": [
{
// Defines the policy wallet that will sign the transaction
"type": "sig",
"keyHash": "fdf151b600df2492005221876c7d7e33056496572c7363c33a1e3609",
},
{
// Defines the slot number that this policy can mint/burn tokens
"type": "before",
"slot": "100000000",
},
],
},
// The hash of the native script, which is the Policy ID.
"hash": "4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfb",
}
],
}
CIP-68 Payload
{
// Address receive any leftover UTxOs from the transaction. Usually the
"changeAddress": "addr_test1...",
// UTXOs from the wallet paying for fees (list of CBOR UTXOs)
"utxos": ["8282...", "8282..."],
"mint": [
{
// Reference Token - Label 100 -> Sent to Metadata Manager Wallet or Script Address
"version": "cip68",
//Name of the asset. Must be the same for both tokens
"assetName": { "name": "youruniquecip68asset", "format": "utf8", "label": 100 },
"metadata": {
"name": "Your NFT Name",
"image": "ipfs://your-image-hash",
"mediaType": "image/png",
"description": "A description for your CIP-68 asset"
},
"policyId": "8e024681ee83f54bd5f9a0334641...",
"quantity": 1,
// Destination to send minted asset.
"destAddress": "addr_test2..."
},
{
// User Token - Label 222 -> Sent to User Wallet
"version": "cip68",
// Asset name must be identical to the (100) token's assetName
"assetName": { "name": "youruniquecip68asset", "format": "utf8", "label": 222 },
"policyId": "8e024681ee83f54bd5f9a033464...",
"quantity": 1,
// Destination to send minted asset.
"destAddress": "addr_test1..."
}
],
// The `preloadedScripts` array provides script data for minting authorization.
// - Native scripts: contains the actual native script
// - Plutus scripts: contains blueprint data (native script derived from blueprint)
// Optional but recommended for performance and latency. Required for new/unregistered scripts.
"preloadedScripts": [ /* ... script details ... */ ],
// The `scriptInteractions` array is ONLY required for smart contract validation.
// It is not used for the native script / Metadata-Manager Wallet approach.
// It is ONLY required for blueprints that are not registered yet.
// The full payload format is covered in the smart contract guide.
"scriptInteractions": [ /* ... validator, redeemer, datum ... */ ],
}
Explanation
changeAddress: Where leftover funds or minted assets return if they’re not explicitly assigned.
message: This sets CIP-20–style text if you want a short on-chain memo.
mint array:
version: "cip-25" tells Anvil you’re embedding CIP-25–compliant metadata.
assetName: The token’s name as a JSON object
name: The name of the asset.
format: The format of the name. Can be "utf8" or "hex".
Example: {name: "MyAssetName", format: "utf8"}
metadata: CIP-25 fields like name, image, mediaType, description.
policyId: The unique 56-hex string for your minting native script.
quantity: How many tokens to mint (1 for a single NFT).
destAddress: If you want the minted asset to go to a specific address different from your changeAddress.
preloadedScripts: Example of a native script using
type": "all"
(ScriptAll). Includes a signature requirement and time-lock.
Minting vs. Sending
Mint: Use the
mint
array. If you want to send additional tokens after minting, include them in theoutputs[]
.Transferring an existing token: Just specify it under
outputs[].assets[]
. No need to definemint
.
Key Steps to Use
Assemble the payload:
changeAddress
orutxos
+ themint
array if creating tokens.Optionally add
CIP-20
orCIP-25
metadata undermetadata
ormessage
.Call
POST /transactions/build
.Sign the resulting transaction with your policy key and/or user’s key.
Submit the signed transaction to
POST /transactions/submit
.
Conclusion
NFT & FT usage on Cardano with Anvil revolves around two primary tasks:
Minting tokens by specifying them in the
mint
array (plus a reference native script if needed).Transferring tokens by listing them in
outputs[].assets[]
.
For CIP-25 or CIP-68 metadata, you embed JSON describing your asset (NFT name, image, etc.) so wallets and explorers can parse it. The snippet above with preloadedScripts and policyId is a typical CIP-25 single NFT example.
Whether you’re distributing a fungible currency or a one-of-a-kind collectible, the approach is the same—CIP standards define the metadata, and Anvil’s transaction builder handles the heavy lifting.
Last updated
Was this helpful?