Deno & Fetch
A Deno-based script for minting CIP-25 assets on the Cardano blockchain using the Anvil API. This guide provides a complete, example for building, signing, and submitting a transaction to mint a CIP-2
Quick-Start Example
This streamlined tutorial shows how to mint a CIP-25 NFT on Cardano using Deno + Fetch and the Anvil API. Everything lives in a single file (mint.ts
) so you can copy-paste and run.
We'll:
Load wallets (Customer, Policy)
Create a native script using our Native Script utilities
Build a mint payload for one CIP-25 asset
Call
transactions/build
Sign with the Policy & Customer keys (customer signature is done in the backend for simplicity)
Submit the transaction
Verify the NFT on-chain
Prerequisites
Two Wallets β You'll need two wallets with these fields:
Customer Wallet: Pays fees, receives the minted NFT
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...
)
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, createNativeScript)
β βββ constant.ts # API configuration (URLs, headers)
βββ wallet-customer.json # Customer wallet (pays fees, receives NFT)
βββ wallet-policy.json # Policy wallet (controls minting policy)
Quick-Start Script
import { Buffer } from "node:buffer";
import {
FixedTransaction,
PrivateKey,
} from "npm:@emurgo/[email protected]";
import {
createNativeScript,
timeToSlot,
getKeyhash,
} 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"));
// 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);
// Prepare mint payload
const counter = Date.now();
const assetName = `anvilapicip25_${counter}`;
// Build transaction
const buildBody = {
changeAddress: customerWallet.base_address_preprod,
mint: [
{
// CIP-25 asset with Metadata
version: "cip25",
assetName: { name: assetName, format: "utf8" },
metadata: {
name: `anvil-api-${counter}`,
image: `ipfs://YOUR_IPFS_HASH_HERE`,
mediaType: "image/png",
description: "Anvil API CIP-25 Mint Example",
},
policyId: nativeScript.hash,
quantity: 1,
},
],
preloadedScripts: [nativeScript],
};
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"));
// Sign with policy wallet
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: Date): Promise<number>
- Converts timestamps to Cardano slotsgetKeyhash(address: string): Promise<string>
- Extracts payment key hash from addressescreateNativeScript(keyHash: string, ttl: number): Promise<{policyId: string, script: string}>
- Creates time-locked native scriptsAPI 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.ts
Troubleshooting
Common Issues
Error: "Module not found"
Check that your import paths match your project structure
Ensure
utils/shared.ts
andutils/constant.ts
exist
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
Full Example Script
For complete, fully-annotated examples see the examples repository:
Last updated
Was this helpful?