Creating Native Scripts
Comprehensive guide to creating and managing Native scripts for creating rules for minting tokens on Cardano using the Anvil API.
Introduction
This guide provides step-by-step instructions for creating native scripts using the Anvil API's utility endpoints. For conceptual information about native scripts, their structure, and common patterns, see the Native Scripts Overview.
Workflow Overview
The process of creating and using native scripts with the Anvil API follows these key steps:
Parse Wallet Address - obtain key hash(es) for signature requirements (supports multisig with multiple addresses)
Convert DateTime to Slot - create a time constraint (optional but recommended)
Create JSON Native Script - combine key hash(s) and time constraints
Convert to Native Script and get policy ID - use the Anvil API to create a machine-readable format
Use in Transaction - include the script when minting tokens
Prerequisites
An Anvil API key
A wallet address for signing transactions
Basic understanding of native scripts and their role in minting tokens
Using the Utils Endpoints
The Anvil API provides several utility endpoints to assist with creating and managing native scripts:
/utils/addresses/parse
Parses an address and returns its payment and stake credentials
/utils/native-scripts/parse
Returns information about a provided native script (e.g., policy ID)
/utils/native-scripts/serialize
Creates a native script from it's JSON schema definition
/utils/network/time-to-slot
Converts a date/time to a Cardano slot number
/utils/network/slot-to-time
Converts a Cardano slot number to a date/time
Step-by-Step Guide to Creating a Native Script for Minting rules.
Step 1: Obtain a key used for policy actions.
To create a signature-based native script, you first need to obtain the key hash of the wallet that will sign the minting transactions. You can get this by parsing a wallet address using the address parsing endpoint:
// Example request
await fetch('https://preprod.api.ada-anvil.app/v2/services/utils/addresses/parse', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': 'YOUR_API_KEY'
},
body: JSON.stringify({
address: 'stake_address_or_payment_address_here'
})
});
// Example response
{
"payment": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"stake": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
}
The payment
value from the response is what you'll use as the keyHash
in your native script.
Step 2: Convert Time to Slot (Optional)
To add a time constraint to your native script, convert a future DateTime to a Cardano slot number:
// Example request
await fetch('https://preprod.api.ada-anvil.app/v2/services/utils/network/time-to-slot', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': 'YOUR_API_KEY'
},
body: JSON.stringify({
timestamp: '2030-01-01T00:00:00Z'
})
});
// Example response
{
"slot": 98765432
}
This slot number will be used in your native script to create a time-limited minting policy.
Step 3: Create JSON Native Script
Now that you have both the key hash (from Step 1) and optionally a slot number for time constraint (from Step 2), you can create the JSON structure for your native script.
Native scripts in the Anvil API follow a specific JSON structure that maps to Cardano's native script format. Each script uses a discriminated union with a type
field that determines the script's behavior.
Here's how to combine the signature requirement and time constraint into a complete native script:
{
"type": "all",
"scripts": [
{
"type": "sig",
// Required Key hash from Step 1
"keyHash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
},
{
"type": "before",
// Required Slot number from Step 2
"slot": 98765432
}
]
}
This JSON structure represents a native script that requires both the signature from the specified key hash AND the transaction to be submitted before the specified slot number.
Step 4: Serialize the Native Script via API
While the JSON representation is a clear way to define the native script, it must be serialized into a specific hex format to be included in a transaction. The Anvil API provides a utility endpoint to handle this conversion. Here's how you can call the API with the JSON native script from Step 3:
// The JSON native script from Step 3
const nativeScriptJSON = {
type: "all",
scripts: [
{
type: "sig",
// Required Key hash from Step 1
keyHash: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
},
{
type: "before",
// Required Slot number from Step 2
slot: 98765432
}
]
};
async function serializeNativeScript(nativeScriptJSON) {
const response = await fetch("https://preprod.api.ada-anvil.app/v2/services/utils/native-scripts/serialize", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": "YOUR_API_KEY"
},
body: JSON.stringify({ schema: nativeScriptJSON }),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`API call failed: ${errorText}`);
}
const { script, policyId } = await response.json();
console.log("CBOR Hex-encoded Script:", script);
console.log("Policy ID:", policyId);
return { script, policyId };
}
// Get the serialized script and policy ID
const { script: hexEncodedScript, policyId } = await serializeNativeScript(nativeScriptJSON);
The API returns two crucial pieces of information:
script
: The CBOR hex-encoded native script. This is what you will include in the transaction body.policyId
: The unique identifier for your native script, derived from hashing the script.
Step 5: Use in Transaction
The final step is to use your native script when building transactions that mint or burn assets. You'll include the native script in the preloadedScripts
section of your transaction request:
const data = {
changeAddress: "addr_test...",
utxos: ["8282...", "8282..."],
mint: [
{
version: "cip25",
assetName: { name: "MyAsset", format: "utf8" },
metadata: {
name: "My Asset",
image: ["ipfs://Qm..."],
// Additional metadata fields
},
policyId, // The policy ID from Step 4
quantity: 1,
// Destination address for the minted asset
destAddress: "addr_test..."
}
],
// This is required for the first mint transaction. Anvil API will fetch the scripts from the provided policy ID for any subsequent transactions.
preloadedScripts: [
{
type: "simple",
script: {
// Your native script from Step 3
type: "all",
scripts: [
{
type: "sig",
keyHash: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
},
{
type: "before",
slot: 98765432
}
]
},
hash: policyId // The policy ID from Step 4
}
]
};
const tx = await fetch(`https://preprod.api.ada-anvil.app/v2/services/transactions/build`, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
"X-Api-Key": "YOUR_API_KEY"
}
});
This transaction, when signed and submitted, will mint a new asset under the policy ID you generated.
Additional Native Script Patterns
For more native script patterns including multi-signature policies, threshold requirements, and complex logical combinations, see the Native Scripts Overview.
Conclusion
You now have a complete native script that can be used for minting tokens. The script includes both signature requirements and time constraints, providing security and immutability for your token collection.
For security considerations, best practices, and additional script patterns, refer to the Native Scripts Overview.
Related Resources
Last updated
Was this helpful?