# Native Scripts

### Introduction

Native scripts are a fundamental component of the Cardano blockchain that define who has permission to mint or burn assets under a specific policy ID. These scripts create the cryptographic foundation of your NFT or token collection and establish the rules for minting authority. This guide explains how native scripts work, their structure, and best practices for implementation.

### What is a Native Script?

A native script is a logical expression that defines the conditions in which assets can be minted or burned under a specific policy ID. The policy ID is derived by hashing the native script, creating a unique identifier for your asset collection on the blockchain.

When included in a minting or burning transaction, native scripts are evaluated by the Cardano network to verify that the transaction satisfies all conditions before allowing new assets to be created or burned.

For a detailed, step-by-step guide on creating native scripts using the Anvil API, see our [Creating Native Scripts](/guides/nft-and-ft/native-scripts/create-native-script.md) guide.

### Native Script Structure

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:

```json
// Base structure for all native scripts
{
  "type": "sig" | "before" | "after" | "all" | "any" | "atLeast",
  // Additional properties based on the type
}
```

The underlying zod schema validates the following structures:

```typescript
// Main Native Script Schema
export const nativeScriptSchema = z.discriminatedUnion("type", [
  // Signature requirement
  z.object({ type: z.literal("sig"), keyHash: z.string() }),
  
  // Time constraints
  z.object({ type: z.enum(["before", "after"]), slot: z.number() }),
  
  // Logical AND/OR
  z.object({ 
    type: z.enum(["any", "all"]), 
    scripts: z.array(/*recursive native scripts*/) 
  }),
  
  // At least N of M
  z.object({ 
    type: z.literal("atLeast"), 
    required: z.number(),
    scripts: z.array(/*recursive native scripts*/) 
  }),
]);
```

#### Script Types

**Signature Scripts**

Signature scripts (`sig`) require a specific key to sign the transaction. This is the most common constraint used to ensure only authorized parties can mint tokens:

```json
{
  "type": "sig",
  "keyHash": "KEY_HASH_HERE"
}
```

The `keyHash` is the hash of the verification key that must sign the transaction.

**Time Constraints**

Time constraints limit minting to specific time windows using slot numbers:

```json
{
  "type": "before",
  "slot": 100000000
}
```

or

```json
{
  "type": "after",
  "slot": 50000000
}
```

* `before`: The transaction must be submitted before the specified slot number
* `after`: The transaction must be submitted after the specified slot number

**Logical Operators**

> **In Simple Terms**: `all` means "AND" (everything must be true), `any` means "OR" (at least one thing must be true). So if you want to allow either Alice OR Bob to sign, use `any`. If you need both Alice AND Bob to sign, use `all`.

Logical operators combine multiple constraints:

```json
{
  "type": "all",
  "scripts": [
    // Array of other scripts that must ALL evaluate to true
  ]
}
```

or

```json
{
  "type": "any",
  "scripts": [
    // Array of other scripts where at least ONE must evaluate to true
  ]
}
```

**Threshold Requirements**

The `atLeast` operator allows you to specify a minimum number of conditions that must be met:

```json
{
  "type": "atLeast",
  "required": 2,
  "scripts": [
    // Array of scripts where at least 'required' number must evaluate to true
  ]
}
```

This is particularly useful for multi-signature scenarios where you might want to require, for example, at least 2 out of 3 possible signers to authorize minting.

### Common Native Script Patterns

#### Basic Single-Signature Policy

```json
{
  "type": "sig",
  "keyHash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}
```

#### Time-Limited Single-Signature Policy (Recommended for NFTs)

```json
{
  "type": "all",
  "scripts": [
    {
      "type": "sig",
      "keyHash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    },
    {
      "type": "before",
      "slot": 98765432
    }
  ]
}
```

#### Multi-Signature Policy (Any of Two Keys)

```json
{
  "type": "any",
  "scripts": [
    {
      "type": "sig",
      "keyHash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    },
    {
      "type": "sig",
      "keyHash": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
    }
  ]
}
```

#### Multi-Signature Policy with Threshold (2 of 3 Keys Required)

```json
{
  "type": "atLeast",
  "required": 2,
  "scripts": [
    {
      "type": "sig",
      "keyHash": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    },
    {
      "type": "sig",
      "keyHash": "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
    },
    {
      "type": "sig",
      "keyHash": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
    }
  ]
}
```

### Best Practices

#### Security Considerations

1. **Always Include a Signature Requirement**: While technically optional, you should always include at least one signature constraint in your native scripts for security. A native script without signature requirements allows anyone to mint tokens with your native script ID.
2. **Time-Limited Policies**: For NFT collections, consider implementing time-limited minting windows using both signature and time constraints. This pattern ensures your collection becomes immutable after a certain date, which is important for NFT value and trust.
3. **Multi-Signature Requirements**: For projects with multiple stakeholders, consider using nested logical operators to require multiple approvals.

#### Implications for Token Operations

**Time-Limited Policies and Token Operations**

When using time-limited policies (with a `before` constraint), understand the implications for various operations:

1. **Minting New Tokens**:
   * Only possible before the specified slot time
   * Attempting to mint after this time will fail validation
   * Keep track of your policy's deadline to avoid transaction failures
2. **Burning Tokens**:
   * Requires the same native script verification as minting
   * Cannot burn tokens after the time limit expires
   * To burn tokens, use a negative quantity in your mint request
3. **Metadata Updates**:
   * On-chain metadata (label 721) cannot be modified after being written
   * For updatable NFTs, consider using CIP-68 which stores data in datums
   * Time-limitations affect your ability to issue updated versions of tokens

> **Important**: If your use case requires future updates to tokens, avoid time-limited policies or ensure the time window is sufficient for your project's lifecycle.

### Using Native Scripts with the Anvil API

#### When to Include Native Scripts

Native scripts are provided via the `preloadedScripts` array in your Anvil API request:

* **Required**: When minting tokens with a new policy ID that hasn't been used before
* **Optional**: When minting additional tokens with an existing policy ID

> **Performance Note**: Including the native script even for existing policies improves performance. Without it, the Anvil API will automatically fetch the script from the blockchain in the background, which adds processing time to your request.

#### Script Verification

When you provide a native script, the Anvil API performs several validations:

1. The native script is parsed and its hash is computed
2. The computed hash is compared to the policy ID specified in the `policyId` field
3. If the hashes don't match, the transaction is rejected with a `Policy script and policy Id do not match` error

#### Integration with Transaction Building

Native scripts are provided in the `preloadedScripts` array and automatically resolved during the transaction preparation phase. The system:

1. Identifies required policy IDs from mint assets
2. Looks for matching scripts in `preloadedScripts`
3. Falls back to blockchain lookup if not found
4. Validates script hash matches policy ID
5. Uses resolved scripts for transaction building

### Common Errors and Troubleshooting

* **Unable to retrieve script for policy**: The policy doesn't exist on-chain and wasn't provided in `preloadedScripts`
* **Policy script and policy ID do not match**: The provided script's hash doesn't match the specified policy ID
* **Missing policy scripts**: Required for first-time minting but wasn't included in the request

### References

* [Creating Native Scripts](https://github.com/Cardano-Forge/anvil-api/blob/main/docs/guides/nft-and-ft/create-native-script/README.md)
* [Cardano Developers - Native Scripts](https://developers.cardano.org/docs/get-started/cardano-cli/simple-scripts/)
* [CIP-25 Specification](https://cips.cardano.org/cip/CIP-25)
* [CIP-68 Specification](https://cips.cardano.org/cip/CIP-68)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://dev.ada-anvil.io/guides/nft-and-ft/native-scripts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
