Guides
Deno & Fetch#
Quick-Start Example
This streamlined tutorial shows how to mint a CIP-68 NFT on Cardano using Deno + Fetch and the Anvil API.
This guide demonstrates the Native Script Validation approach using a Metadata-Manager Wallet. It's a straightforward way to create updatable NFTs without deploying a full smart contract. See the reasons why for more details.
We'll:
- Load wallets (Customer, Policy, Metadata Manager)
- Create a native script using our Native Script utilities
- Build a mint payload that creates both tokens (
100+222) in the same transaction. - Call
transactions/build - Sign with the Policy & Customer (
skeys) keys. Customer in the backend for simplicity. - Submit the transaction
- Verify on-chain that the assets are minted:
- The reference token is sent to the metadata manager wallet
- The user token is sent to the customer wallet
Prerequisites#
Three Wallets – You'll need three wallets with these fields:
- Customer Wallet: Pays fees, receives user token (label 222)
base_address_preprod: Testnet address (addr_test1...)skey: Signing key (ed25519e_sk1...)
- Policy Wallet: Controls minting policy
base_address_preprod: Testnet address (addr_test1...)skey: Signing key (ed25519e_sk1...)
- Metadata Manager Wallet: Receives reference token (label 100)
base_address_preprod: Testnet address (addr_test1...)skey: Signing key (optional for this script. Used when updating metadata)
Create wallets with our Wallet CLI. Ensure customer wallet has ADA for fees.
Anvil API Key – A valid Anvil API key. See Authentication.
Utility Helpers – Import helpers from the utilities-functions guide to keep this file short.
Project Structure#
For the absolute minimum setup, you only need:
your-project/
├── mint.ts # Main minting script
├── utils/
│ ├── shared.ts # Utility functions (timeToSlot, getKeyhash, etc.)
│ └── constant.ts # API configuration (URLs, headers)
├── wallet-customer.json # Customer wallet (pays fees, receives user token)
├── wallet-policy.json # Policy wallet (controls minting policy)
└── wallet-meta-manager.json # Metadata manager wallet (receives reference token)
Quick-Start Script#
import { Buffer } from "node:buffer";
import {
FixedTransaction,
PrivateKey,
} from "npm:@emurgo/cardano-serialization-lib-nodejs@14.1.1";
import {
timeToSlot,
getKeyhash,
createNativeScript,
} from "../utils/shared.ts";
import { API_URL, HEADERS } from "../utils/constant.ts";
// Load wallets
const customerWallet = JSON.parse(Deno.readTextFileSync("wallet-customer.json"));
const policyWallet = JSON.parse(Deno.readTextFileSync("wallet-policy.json"));
const metaManagerWallet = JSON.parse(Deno.readTextFileSync("wallet-meta-manager.json"));
// Create native script
const slot = await timeToSlot(new Date("2026-01-01"));
const keyhash = await getKeyhash(policyWallet.base_address_preprod);
const nativeScript = await createNativeScript(keyhash!, slot);
const counter = Date.now();
const assetName = `anvilapicip68_${counter}`;
// Build mint payload
const buildBody = {
changeAddress: customerWallet.base_address_preprod,
mint: [
{
// Reference token - label 100, sent to Metadata-Manager wallet
version: "cip68",
assetName: { name: assetName, format: "utf8", label: 100 },
metadata: {
name: `anvil-api-${counter}`,
image: "ipfs://YOUR_IPFS_HASH_HERE",
mediaType: "image/png",
description: "Anvil API CIP-68 Mint Example",
},
policyId: nativeScript.hash,
quantity: 1,
destAddress: metaManagerWallet.base_address_preprod,
},
{
// User token - label 222, sent to Customer wallet
version: "cip68",
assetName: { name: assetName, format: "utf8", label: 222 },
policyId: nativeScript.hash,
quantity: 1,
destAddress: customerWallet.base_address_preprod,
},
],
preloadedScripts: [nativeScript],
};
// Build transaction
const buildResult = await fetch(`${API_URL}/transactions/build`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify(buildBody),
});
const buildJson = await buildResult.json();
if (!buildResult.ok) {
throw new Error(buildJson.message);
}
// Sign transaction
const tx = FixedTransaction.from_bytes(Buffer.from(buildJson.complete, "hex"));
tx.sign_and_add_vkey_signature(PrivateKey.from_bech32(policyWallet.skey));
// Sign with customer wallet. Normally this would come from the clientside via your customers browser extenstion
// This is here for simplicity. See full minting examples below.
tx.sign_and_add_vkey_signature(PrivateKey.from_bech32(customerWallet.skey));
// Submit transaction
const submitResult = await fetch(`${API_URL}/transactions/submit`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({ transaction: tx.to_hex() }),
});
const submitJson = await submitResult.json();
if (!submitResult.ok) {
throw new Error(submitJson.message);
}
console.log("Submitted Transaction Hash:", submitJson.txHash);Utility Files Reference#
You'll need to create the utility files. See the Utility Functions documentation for detailed API endpoint information and examples.
The utility files provide these key functions:
timeToSlot(date)- Converts timestamps to Cardano slotsgetKeyhash(address)- Extracts payment key hash from addressescreateNativeScript(keyHash, ttl)- Creates time-locked native scripts- API configuration - Anvil API endpoints and headers
💡 Tip: The anvil-api-examples repository contains the most up-to-date utility functions and is the recommended source.
Running the Script#
# Run the script
deno run --allow-all mint.tsTroubleshooting#
Common Issues#
Error: "Module not found"
- Check that your import paths match your project structure
- Ensure
utils/shared.tsandutils/constant.tsexist
Error: "Failed to get key hash for address"
- Verify your wallet addresses are valid testnet addresses
- Check that wallet files contain proper JSON format
- Ensure addresses start with
addr_test1
Error: "API call failed: Input validation failed"
- Usually means wallet address parsing failed
- Double-check wallet file format and addresses
Error: "Unable to build tx"
- Ensure customer wallet has sufficient ADA for fees
- Check that API key is valid
- Verify network connectivity
CIP-68 Specific Notes#
Two tokens are minted in the same transaction:
- Reference token (label 100) - Contains metadata, sent to metadata manager wallet
- User token (label 222) - The actual NFT, sent to customer wallet
Full Example Script#
For complete, fully-annotated examples see the examples repository: