Quick Start Examples

TS/JS + Fetch

This example requires several utility and configuration files. Create the following files in the same directory as your main script.

Need to create wallets?

You can use the Anvil Wallet CLI to generate the required wallet JSON files for these examples.

// See Authentication page for API key details.
export const X_API_KEY = "testnet_EyrkvCWDZqjkfLSe1pxaF0hXxUcByHEhHuXIBjt9";
export const NETWORK = "preprod";
export const API_URL = `https://${NETWORK}.api.ada-anvil.app/v2/services`;
export const HEADERS = {
  "Content-Type": "application/json",
  "x-api-key": X_API_KEY,
};

You will also need the shared utility functions, which you can find in the utils/shared.ts file in the examples repository.

Now, you can run the main script:

/**
 * CIP-68 NFT Minting Example
 *
 * This script demonstrates how to mint a CIP-68 Non-Fungible Token (NFT), which includes both a reference token (label 100)
 * and a user-facing token (label 222). It handles the entire process from wallet loading to transaction submission.
 *
 * This involves:
 * 1. Loading customer, policy, and metadata manager wallets.
 * 2. Creating a time-locked native script signed by the policy wallet.
 * 3. Defining the asset metadata for both the reference and user tokens according to the CIP-68 standard.
 * 4. Building the transaction payload with the minting details.
 * 5. Building the transaction via the Anvil API.
 * 6. Signing the transaction with the customer, policy, and metadata manager private keys.
 * 7. Submitting the fully signed transaction to the blockchain.
 *
 * Prerequisites:
 * - `wallet-customer.json`: A funded wallet file to pay for the transaction.
 * - `wallet-policy.json`: A wallet file to act as the policy key.
 * - `wallet-meta-manager.json`: A wallet to manage metadata updates (its key is in the reference token datum).
 * - `ANVIL_API_KEY`: An environment variable for Anvil API authentication.
 *
 * Execution:
 * `deno run --allow-all --env-file=.env cip68.ts`
 */

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";

// 1. 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"));

// 2. Create native script (expires 2026-01-01 signed by policy wallet)
const slot = await timeToSlot(new Date("2026-01-01"));

// 2.1. Get keyhash of policy wallet
const keyhash = await getKeyhash(policyWallet.base_address_preprod);
if (!keyhash) {
  throw new Error("Unable to get key hash for policy, missing or invalid skey");
}

// 2.2. Create native script
const nativeScript = await createNativeScript(keyhash, slot);

// 3. Prepare mint payload
const counter = new Date().getTime();
const assets: {
  version: string;
  assetName: { name: string; format: "utf8" | "hex"; label: 100 | 222 };
  metadata?: {
    name: string;
    image: string | string[];
    mediaType: string;
    description: string;
  };
  policyId: string;
  quantity: 1;
  destAddress?: string;
}[] = [];

// Mint 2 assets (Reference Token & User Token)
assets.push(
  {
    // Reference Token - Label 100 -> Metadata Manager Address
    version: "cip68",
    assetName: { name: `anvilapicip68_${counter}`, format: "utf8", label: 100 },
    metadata: {
      name: `anvil-api-${counter}`,
      image: [
        "https://ada-anvil.s3.ca-central-1.amazonaws.com/",
        "logo_pres_V2_3.png",
      ],
      mediaType: "image/png",
      description: "Testing CIP-68 using anvil API",
    },
    policyId: nativeScript.hash,
    quantity: 1,
    destAddress: metaManagerWallet.base_address_preprod,
  },
  {
    // User Token - Label 222 -> Customer Address
    version: "cip68",
    assetName: { name: `anvilapicip68_${counter}`, format: "utf8", label: 222 },
    policyId: nativeScript.hash,
    quantity: 1,
    destAddress: customerWallet.base_address_preprod,
  },
);

// 4. Build transaction via Anvil API
const buildBody = {
  changeAddress: customerWallet.base_address_preprod,
  mint: assets,
  preloadedScripts: [nativeScript],
};

console.log("Build Body: ", buildBody);

const buildResult = await fetch(`${API_URL}/transactions/build`, {
  method: "POST",
  body: JSON.stringify(buildBody),
  headers: HEADERS,
});
const buildJson = await buildResult.json();

console.log("Build Output: ", buildJson);

if (!buildResult.ok) {
  throw new Error(buildJson.message ?? `Unable to build tx`);
}

// 5. Sign transaction
const tx = FixedTransaction.from_bytes(
  Buffer.from(buildJson.complete, "hex"),
);
tx.sign_and_add_vkey_signature(
  PrivateKey.from_bech32(policyWallet.skey),
);
tx.sign_and_add_vkey_signature(
  PrivateKey.from_bech32(customerWallet.skey),
);

// 6. Submit transaction
const submitResult = await fetch(`${API_URL}/transactions/submit`, {
  method: "POST",
  body: JSON.stringify({
    signatures: [],
    transaction: tx.to_hex(),
  }),
  headers: HEADERS,
});

const submitJson = await submitResult.json();
if (!submitResult.ok) throw new Error(submitJson.message ?? "Unable to submit tx");

console.log("Submitted Transaction Hash: ", submitJson.txId ?? submitJson);

/*
Build Body:  {
  changeAddress: "addr_test1qqwadht4defe0cqem6a56ytwz96g4y7j7z0a02y5aj8c4unm5k2xfvhpn4kukwhsfakq22dy94yf9y8nt9dddzpkmuys4r5q8h",
  mint: [
    {
      version: "cip68",
      assetName: {
        name: "anvilapicip68_1752701331052",
        format: "utf8",
        label: 100
      },
      metadata: {
        name: "anvil-api-1752701331052",
        image: [
          "https://ada-anvil.s3.ca-central-1.amazonaws.com/",
          "logo_pres_V2_3.png"
        ],
        mediaType: "image/png",
        description: "Testing CIP-68 using anvil API"
      },
      policyId: "4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfb",
      quantity: 1,
      destAddress: "addr_test1qz7jcka6zwj0tz52rl73te7y7avl2ckzmkfguwl42h728jeqzph40hhsxq32p2t4r3qcnhsrk9nnq5m2yv04dhuf3hfsuqphqk"
    },
    {
      version: "cip68",
      assetName: {
        name: "anvilapicip68_1752701331052",
        format: "utf8",
        label: 222
      },
      policyId: "4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfb",
      quantity: 1
    }
  ],
  preloadedScripts: [
    {
      type: "simple",
      script: { type: "all", scripts: [ [Object], [Object] ] },
      hash: "4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfb"
    }
  ]
}
Build Output:  {
  hash: "758bb17313d91d0960ac3629b9830da99ec74b8f49225901e190ad361c6a1091",
  complete: "84a700d901028182582072be679ccc4cadce0109beeda0dd182b8439204f252db7b4acbffd2f568f53a801018383583900bd2c5bba13a4f58a8a1ffd15e7c4f759f562c2dd928e3bf555fca3cb20106f57def03022a0a9751c4189de03b16730536a231f56df898dd3821a00157084a1581c4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfba1581f000643b0616e76696c61706963697036385f31373532373031333331303532015820809f3e00c6702e74a9ec87763e2c9a7334754f6a20583f9268affcc5bc81c82c82583900e4c0e5e76be5cf9ea49b889cb6e54baed815859c35b2d9fe84b04b222435fcd97a6b0717fbd3658537d3dfd3360267449dcd2cd4de5928e01a0020ce70825839001dd6dd756e5397e019debb4d116e11748a93d2f09fd7a894ec8f8af27ba59464b2e19d6dcb3af04f6c0529a42d489290f3595ad68836df09821ac815ef6ea2581c4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfba2581b616e76696c61706963697032355f3137353237303032373635353201581f000de140616e76696c61706963697036385f3137353237303133333130353201581c5db632e917cab856ac7dd4ce76b3ef928b82d1d63037f4fbd1cb88c4a1581b616e76696c61706963697032355f3137343532373438333532343501021a00036975031a05c87d06081a05c860e609a1581c4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfba2581f000643b0616e76696c61706963697036385f3137353237303133333130353201581f000de140616e76696c61706963697036385f31373532373031333331303532010b58206bb381d54ea424e4c4d6e48f7403378bf9751e3a650ed086bbccd01af3bb81f8a201d90102818201828200581c3910f0db63599cd9cb1484d5591491629470761a89cde0473e4b94f682051a06a6008004d901029fd8799fa4446e616d6557616e76696c2d6170692d3137353237303133333130353245696d6167659f583068747470733a2f2f6164612d616e76696c2e73332e63612d63656e7472616c2d312e616d617a6f6e6177732e636f6d2f526c6f676f5f707265735f56325f332e706e67ff496d656469615479706549696d6167652f706e674b6465736372697074696f6e581e54657374696e67204349502d3638207573696e6720616e76696c2041504901fffff5f6",
  stripped: "84a700d901028182582072be679ccc4cadce0109beeda0dd182b8439204f252db7b4acbffd2f568f53a801018383583900bd2c5bba13a4f58a8a1ffd15e7c4f759f562c2dd928e3bf555fca3cb20106f57def03022a0a9751c4189de03b16730536a231f56df898dd3821a00157084a1581c4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfba1581f000643b0616e76696c61706963697036385f31373532373031333331303532015820809f3e00c6702e74a9ec87763e2c9a7334754f6a20583f9268affcc5bc81c82c82583900e4c0e5e76be5cf9ea49b889cb6e54baed815859c35b2d9fe84b04b222435fcd97a6b0717fbd3658537d3dfd3360267449dcd2cd4de5928e01a0020ce70825839001dd6dd756e5397e019debb4d116e11748a93d2f09fd7a894ec8f8af27ba59464b2e19d6dcb3af04f6c0529a42d489290f3595ad68836df09821ac815ef6ea2581c4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfba2581b616e76696c61706963697032355f3137353237303032373635353201581f000de140616e76696c61706963697036385f3137353237303133333130353201581c5db632e917cab856ac7dd4ce76b3ef928b82d1d63037f4fbd1cb88c4a1581b616e76696c61706963697032355f3137343532373438333532343501021a00036975031a05c87d06081a05c860e609a1581c4d5bd6249f0d9e4b2762ce334e2973dc7fd414ec1e08b4b0c2159bfba2581f000643b0616e76696c61706963697036385f3137353237303133333130353201581f000de140616e76696c61706963697036385f31373532373031333331303532010b58206bb381d54ea424e4c4d6e48f7403378bf9751e3a650ed086bbccd01af3bb81f8a0f5f6",
  witnessSet: "a201d90102818201828200581c3910f0db63599cd9cb1484d5591491629470761a89cde0473e4b94f682051a06a6008004d901029fd8799fa4446e616d6557616e76696c2d6170692d3137353237303133333130353245696d6167659f583068747470733a2f2f6164612d616e76696c2e73332e63612d63656e7472616c2d312e616d617a6f6e6177732e636f6d2f526c6f676f5f707265735f56325f332e706e67ff496d656469615479706549696d6167652f706e674b6465736372697074696f6e581e54657374696e67204349502d3638207573696e6720616e76696c2041504901ffff"
}
Submitted Transaction Hash:  {
  txHash: "758bb17313d91d0960ac3629b9830da99ec74b8f49225901e190ad361c6a1091"
}
*/

Learn More

For a step-by-step explanation, see the Mint a CIP-68 NFT Guide.