# Admin Update Example

{% hint style="info" %}
**Want to understand the smart contract validation logic first?** Check out the [Update Logic Guide](/guides/nft-and-ft/mint-nft-cip-68/smart-contract/update-logic.md) to learn how the contract ensures proper authorization for metadata updates. Otherwise, you can dive right into the implementation below!
{% endhint %}

### Full Code Example

{% hint style="info" %}
**Want to see the complete code first?** Check out the [full working implementation](https://github.com/Cardano-Forge/anvil-api-examples/blob/main/smart-contracts/cip-68/mint-cip68/admin-update.ts) on GitHub, then come back here for the step-by-step breakdown.
{% endhint %}

### Implementation Overview

This example demonstrates:

* Spending existing reference tokens for metadata updates
* Using spend validators with proper redeemer structures
* Admin authorization patterns for metadata changes
* Complete end-to-end update workflow

### Prerequisites

This guide assumes you have completed the [Minting Example](/guides/nft-and-ft/mint-nft-cip-68/smart-contract/mint-example.md). Additionally, you need:

1. **Existing CIP-68 tokens** - Reference and user tokens from a successful mint
2. **Current reference token UTXO** - Transaction hash and output index where the reference token currently resides
3. **Understanding of spend validators** - Updates consume and recreate reference tokens with new metadata

### Step-by-Step Implementation

Let's build a CIP-68 metadata update script step by step. Each section will explain the concept and show the corresponding code.

#### Step 1: Setup and Configuration

Using the same setup from the minting example:

```typescript
import { Buffer } from "node:buffer";
import { FixedTransaction, PrivateKey } from "npm:@emurgo/cardano-serialization-lib-nodejs@14.1.1";
import customer from "./wallet-customer.json" with { type: "json" };
import adminWallet from "./wallet-mint-sc-policy.json" with { type: "json" };
import blueprint from "../aiken-mint-cip-68/plutus.json" with { type: "json" };
import { API_URL, HEADERS } from "../../../utils/constant.ts";

// Configuration - Update these values for your specific tokens
const CUSTOMER_ADDRESS = customer.base_address_preprod; // Change address for transaction
const ADMIN_KEY_HASH = adminWallet.key_hash; // Admin authorization key
const ASSET_NAME = "test"; // Name of the CIP-68 token to update

// NEW: Reference token UTXO to update
const TX_HASH = "d330e666c15e2f19e54b49aff64e69aa134d25242b7dadd95d6aba570a7c1861";
const TX_OUTPUT_INDEX = "0";
```

**Key difference from minting:**

* **TX\_HASH and TX\_OUTPUT\_INDEX** specify which existing reference token to update

#### Step 2: Apply Parameters to Blueprint

The apply-params process is identical to the minting example:

```typescript
const applyParamsResult = await fetch(`${API_URL}/blueprints/apply-params`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({
    params: { [blueprint.validators[0].hash]: [ADMIN_KEY_HASH] },
    blueprint: blueprint
  }),
}).then(res => res.json());

const parameterizedScript = applyParamsResult.preloadedScript;
const SCRIPT_HASH = Object.keys(applyParamsResult.addresses)[0];
const SC_ADDRESS = applyParamsResult.addresses[SCRIPT_HASH].bech32;
```

**Result:** Same parameterized script and address as your original mint

#### Step 3: Build the Update Transaction

Now we build the spend transaction that will update the metadata. The key insight is that we **spend** the existing reference token and **recreate** it with new metadata:

```typescript
const input = {
  changeAddress: CUSTOMER_ADDRESS,
  message: "CIP-68 Admin Update Example",
  
  // Script Interactions - Define how to interact with the smart contract during transaction execution
  scriptInteractions: [
    {
      // Purpose: "spend" tells Cardano this is spending a UTXO locked at a smart contract address
      purpose: "spend",
      
      // Hash: The parameterized script hash of our CIP-68 validator
      hash: SCRIPT_HASH,
      
      // OutputRef: Specifies exactly which UTXO we want to spend (the reference token)
      outputRef: {
        txHash: TX_HASH,        // Transaction hash containing the reference token UTXO
        index: TX_OUTPUT_INDEX, // Output index within that transaction (usually 0)
      },
      
      // Redeemer: The data passed to the smart contract's spend validator for authorization
      redeemer: {
        type: "json",
        value: {
          // output_index: Tells the validator which transaction output contains the updated reference token
          output_index: 0,
          
          // update: "AdminUpdate" triggers admin authorization path in the smart contract
          // This makes the validator check that the transaction is signed by the admin key
          // (as opposed to "UserUpdate" which would require fee payment)
          update: "AdminUpdate"
        },
      },
    },
  ],
```

**What's happening here:**

* **Script interactions**: Tells the smart contract we're spending a UTXO locked at the contract address
* **OutputRef**: Specifies exactly which reference token UTXO we want to update
* **Redeemer**: Contains the authorization data - "AdminUpdate" means admin signature is required

#### Step 4: Define the Updated Output

We need to send the reference token back to the smart contract with updated metadata:

```typescript
  outputs: [
    {
      // Send the updated reference token back to the smart contract address with the new metadata
      address: SC_ADDRESS,
      assets: [
        {
          assetName: {name: assetName, label: 100, format: "utf8"},
          policyId: SCRIPT_HASH,
          quantity: 1,
        },
      ],
      // Details how and where the datum is stored to be used later.
      datum: {
        type: "inline",
        shape: {
          validatorHash: SCRIPT_HASH,
          purpose: "spend", // Marked as spend purpose so the spend validator can update the metadata later.
        },
        value: {
          // Updated CIP-68 Metadata goes here. Follows official CIP-68 spec metadata format. (metadata, version, datum)
          metadata: [
            ["name", "test"],
            ["nickname", "admin_updated"] // Updated nickname to show the admin update
          ],
          version: 1
        }
      },
    },
  ],
  
  // Admin must sign to pass smart contract validation
  requiredSigners: [META_MANAGER_KEY_HASH],
  preloadedScripts: [parameterizedScript]
};
```

**What's happening here:**

* **Output**: The reference token is sent back to the smart contract with updated metadata
* **Datum**: Contains the new metadata following CIP-68 specification
* **Required signers**: Admin must sign the transaction for authorization
* **Preloaded scripts**: Include the parameterized script for validation

#### Step 5: Build and Submit Transaction

Now we build, sign, and submit the transaction:

```typescript
const contractDeployed = await fetch(`${API_URL}/transactions/build`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify(input),
});

if (!contractDeployed.ok) {
  const errorText = await contractDeployed.text();
  console.error("❌ Transaction build failed:", errorText);
  Deno.exit(1);
}

const transaction = await contractDeployed.json();
console.log("✅ Transaction built successfully");

// Sign the transaction using CSL.
const txToSubmitOnChain = FixedTransaction.from_bytes(Buffer.from(transaction.complete, "hex"));
txToSubmitOnChain.sign_and_add_vkey_signature(PrivateKey.from_bech32(adminWallet.skey));

// Submit the transaction to the blockchain.
const urlSubmit = `${API_URL}/transactions/submit`;
const submitted = await fetch(urlSubmit, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({transaction: txToSubmitOnChain.to_hex()}),
});

const output = await submitted.json();
if (!submitted.ok) {
  console.error("❌ Transaction submission failed:", output);
  Deno.exit(1);
}

console.log("✅ Admin update transaction submitted successfully");
console.log("Transaction hash:", output.transactionId);
```

**What's happening here:**

* The tx-builder validates our spend transaction and creates a Cardano transaction
* We sign with the admin's private key (required for "AdminUpdate" authorization)
* The transaction is submitted to the Cardano network
* On success, we get back a transaction hash for tracking

### Running the Example

1. **Find your reference token UTXO**:
   * Use CardanoScan to search for your policy ID from the mint
   * Locate the reference token (label 100) at the smart contract address
   * Update `TX_HASH` and `TX_OUTPUT_INDEX` in your script
2. **Modify the metadata** in the `datum.value.metadata` section as desired
3. **Run the update script**:

   ```bash
   deno run --allow-all admin-update.ts
   ```

#### Expected Output

```
🔄 Applying parameters to blueprint...
✅ Parameters applied successfully
Parameterized script hash: 5da506b0b8d9c7d9df247c7684aead8eb6fdac1cbfb2dd7cc33d6499
Script address: addr_test1wpw62p4shrvu0kwly378dp9w4k8tdldvrjlm9htucv7kfxggmdaj6
✅ Transaction built successfully
✅ Admin update transaction submitted successfully
Transaction hash: d330e666c15e2f19e54b49aff64e69aa134d25242b7dadd95d6aba570a7c1861
```

### Understanding the Update Process

#### Spend Validator Logic

The CIP-68 update process uses a **spend validator** that:

1. **Validates Authorization**: Checks that the admin has signed the transaction
2. **Preserves Token Integrity**: Ensures the reference token stays at the smart contract
3. **Allows Metadata Changes**: Permits updates to the inline datum containing metadata
4. **Maintains CIP-68 Compliance**: Enforces proper metadata structure and versioning

#### Authorization Patterns

**Admin Update (shown in this example):**

* Requires admin signature
* No fee payment needed
* Full metadata update permissions

**User Update (alternative pattern):**

* Requires user token ownership proof
* Fee payment to admin
* Limited metadata update permissions

#### Transaction Flow

1. **Input**: Spend the existing reference token UTXO
2. **Validation**: Smart contract validates admin signature
3. **Output**: Create new reference token UTXO with updated metadata
4. **Result**: Metadata is updated while preserving token integrity

### Key Requirements

* **Track UTXO locations**: Reference tokens move with each update
* **Use same script hash**: From your original mint parameterization
* **Admin signature required**: Only the minting admin can perform admin updates

### Next Steps

This example demonstrates the complete CIP-68 admin update workflow. For production use:

1. **Add UTXO discovery** to automatically find current reference token locations
2. **Implement user updates** with fee payment and user token validation
3. **Add batch operations** for updating multiple tokens
4. **Create metadata validation** to ensure proper format and constraints
5. **Implement update history tracking** for audit trails

### References

* [CIP-68 Specification](https://cips.cardano.org/cip/CIP-68) - Official standard
* [Smart Contract Logic Guide](https://github.com/Cardano-Forge/anvil-api/blob/main/docs/guides/nft-and-ft/mint-nft-cip-68/smart-contract/logic.md) - Validator implementation details
* [Minting Example](/guides/nft-and-ft/mint-nft-cip-68/smart-contract/mint-example.md) - How to create CIP-68 tokens
* [Working example implementation](https://github.com/Cardano-Forge/anvil-api-examples/blob/main/smart-contracts/cip-68/mint-cip68/admin-update.ts)


---

# 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/mint-nft-cip-68/smart-contract/admin-update-example.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.
