/**
 * Issuance Routes E2E Tests
 */

import * as Mosaic from "@sdp/issuance/mosaic";
import { MosaicService } from "@sdp/issuance/mosaic/service";
import * as FeePaymentAdapters from "@sdp/payments/fee-payment";
import { hashString } from "@sdp/payments/hash";
import * as SolanaRpc from "@sdp/rpc/solana";
import type { Address } from "@sdp/solana/address";
import * as MosaicSdk from "@solana/mosaic-sdk";
import { findAssociatedTokenPda, TOKEN_2022_PROGRAM_ADDRESS } from "@solana-program/token-2022";
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { getDb } from "@/db";
import app from "@/index";
import { AppError } from "@/lib/errors";
import * as AuthorityResolution from "@/routes/issuance/handlers/authority-resolution";
import { createKVStoreSet } from "@/runtime/kv-redis";
import { rootLogger } from "@/runtime/logger";
import { reserveMintSupplyAtApprovedEffectBoundary } from "@/services/policy/approved-operation-replay";
import * as SolanaServices from "@/services/solana";
import { TokenService } from "@/services/token.service";
import { TEST_ORG, TEST_USER } from "@/test/fixtures/organizations";
import {
  TEST_ACTIVE_TOKEN,
  TEST_ALLOWLIST_TOKEN,
  TEST_PROJECT,
  TEST_PROJECT_API_KEY,
  TEST_PROJECT_CACHED_KEY,
  TEST_SOLANA_ADDRESSES,
} from "@/test/fixtures/tokens";
import { env } from "@/test/helpers/env";
import { clearTestDatabase, seedTestDatabase } from "@/test/mocks/db";

// Check if running in mock mode (no RPC access)
const isMockMode = (env as { SOLANA_MOCK?: string }).SOLANA_MOCK === "true";

async function seedIssuedToken(
  overrides: Partial<typeof TEST_ACTIVE_TOKEN> = {}
): Promise<typeof TEST_ACTIVE_TOKEN> {
  const token = {
    ...TEST_ACTIVE_TOKEN,
    ...overrides,
  };

  await getDb(env)
    .prepare(
      `INSERT INTO issued_tokens (
        id, project_id, organization_id, signing_wallet_id, mint_address, mint_authority,
        metadata_authority, freeze_authority, abl_list_address, name, symbol, decimals,
        description, uri, image_url, template, total_supply_cached, total_supply_updated_at,
        max_supply, is_mintable, freeze_authority_enabled, allowlist_enabled, status,
        deployed_at, created_by, created_at, updated_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
    )
    .bind(
      token.id,
      token.projectId,
      token.organizationId,
      token.signingWalletId,
      token.mintAddress,
      token.mintAuthority,
      token.metadataAuthority ?? null,
      token.freezeAuthority,
      token.ablListAddress,
      token.name,
      token.symbol,
      token.decimals,
      token.description,
      token.uri,
      token.imageUrl,
      token.template,
      "0",
      token.totalSupplyUpdatedAt ?? token.updatedAt,
      null,
      token.isMintable ? 1 : 0,
      token.isFreezable ? 1 : 0,
      token.requiresAllowlist ? 1 : 0,
      token.status,
      token.deployedAt,
      token.createdBy,
      token.createdAt,
      token.updatedAt
    )
    .run();

  return token;
}

async function seedIssuanceTransaction(input: {
  id: string;
  tokenId?: string;
  organizationId?: string;
  type: string;
  status?: string;
  params: Record<string, unknown>;
  createdAt?: string;
}) {
  const createdAt = input.createdAt ?? "2024-01-03T00:00:00.000Z";

  await getDb(env)
    .prepare(
      `INSERT INTO issuance_transactions (
        id, token_id, organization_id, type, status, idempotency_key, idempotency_fingerprint,
        signature, serialized_tx, operation_params, slot, block_time, fee, error,
        initiated_by_key_id, created_at, updated_at
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
    )
    .bind(
      input.id,
      input.tokenId ?? TEST_ACTIVE_TOKEN.id,
      input.organizationId ?? TEST_ORG.id,
      input.type,
      input.status ?? "confirmed",
      null,
      null,
      null,
      null,
      JSON.stringify(input.params),
      null,
      null,
      null,
      null,
      TEST_PROJECT_API_KEY.id,
      createdAt,
      createdAt
    )
    .run();
}

async function seedOrganization(input: { id: string; name: string; slug: string }) {
  await getDb(env)
    .prepare(
      "INSERT OR REPLACE INTO organizations (id, name, slug, tier, status) VALUES (?, ?, ?, 'individual', 'active')"
    )
    .bind(input.id, input.name, input.slug)
    .run();
}

async function seedProject(input: {
  id: string;
  organizationId: string;
  name: string;
  slug: string;
}) {
  await getDb(env)
    .prepare(
      `INSERT OR REPLACE INTO projects (id, organization_id, name, slug, environment, status, created_by)
       VALUES (?, ?, ?, ?, 'sandbox', 'active', ?)`
    )
    .bind(input.id, input.organizationId, input.name, input.slug, TEST_USER.id)
    .run();
}

function toTestIdPart(value: string): string {
  return value.replace(/[^A-Za-z0-9_]/g, "_").slice(0, 64);
}

async function seedIssuanceActivityWallet(
  walletId = "wal_issuance_activity",
  publicKey = TEST_SOLANA_ADDRESSES.wallet1
) {
  const walletRowId = `cwlt_issuance_activity_${toTestIdPart(walletId)}`;

  await getDb(env).batch([
    getDb(env)
      .prepare(
        `INSERT INTO custody_configs
           (id, organization_id, project_id, provider, config_encrypted, encryption_version, default_wallet_id, status)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?)
         ON CONFLICT DO NOTHING`
      )
      .bind(
        "cust_cfg_issuance_activity",
        TEST_ORG.id,
        TEST_PROJECT.id,
        "local",
        "test-config",
        "sdp-custody-encryption-v1",
        walletId,
        "active"
      ),
    getDb(env)
      .prepare(
        `INSERT INTO custody_wallets
           (id, custody_config_id, wallet_id, public_key, label, purpose, status)
         VALUES (?, ?, ?, ?, ?, ?, ?)`
      )
      .bind(
        walletRowId,
        "cust_cfg_issuance_activity",
        walletId,
        publicKey,
        "Issuance Activity Wallet",
        "transfer",
        "active"
      ),
  ]);

  return { walletId, publicKey };
}

async function deriveAssociatedTokenAccount(owner: string, mint: string): Promise<string> {
  const [tokenAccount] = await findAssociatedTokenPda({
    owner: owner as Address,
    mint: mint as Address,
    tokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
  });
  return tokenAccount;
}

describe("Issuance Routes", () => {
  let apiKeyHash: string;

  beforeAll(async () => {
    await seedTestDatabase(env as Parameters<typeof seedTestDatabase>[0]);

    // Pre-compute API key hash
    apiKeyHash = await hashString(
      TEST_PROJECT_API_KEY.raw,
      (env as { API_KEY_PEPPER: string }).API_KEY_PEPPER
    );
  });

  afterAll(async () => {
    await clearTestDatabase(env as Parameters<typeof clearTestDatabase>[0]);
  });

  beforeEach(async () => {
    const db = getDb(env);
    const kv = createKVStoreSet(env);

    // Clear rate limit KV to prevent 429 errors between tests
    const keys = await kv.rateLimits.list();
    for (const key of keys.keys) {
      await kv.rateLimits.delete(key.name);
    }

    // Clear token-related tables
    await db
      .prepare("DELETE FROM frozen_accounts")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM token_allowlist_statuses")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM token_allowlists")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM issuance_transaction_statuses")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM issuance_transactions")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM issued_token_extensions")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM issued_tokens")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM project_members")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM api_keys WHERE project_id IS NOT NULL")
      .run()
      .catch(() => {});
    await db
      .prepare("DELETE FROM projects")
      .run()
      .catch(() => {});

    // Seed organization
    await db
      .prepare(
        "INSERT OR REPLACE INTO organizations (id, name, slug, tier, status) VALUES (?, ?, ?, 'individual', 'active')"
      )
      .bind(TEST_ORG.id, TEST_ORG.name, TEST_ORG.slug)
      .run();

    // Seed user
    await db
      .prepare(
        "INSERT OR REPLACE INTO users (id, email, email_verified, status) VALUES (?, ?, 1, 'active')"
      )
      .bind(TEST_USER.id, TEST_USER.email)
      .run();

    // Seed project
    await db
      .prepare(
        `INSERT OR REPLACE INTO projects (id, organization_id, name, slug, environment, status, created_by)
         VALUES (?, ?, ?, ?, ?, ?, ?)`
      )
      .bind(
        TEST_PROJECT.id,
        TEST_PROJECT.organizationId,
        TEST_PROJECT.name,
        TEST_PROJECT.slug,
        TEST_PROJECT.environment,
        TEST_PROJECT.status,
        TEST_PROJECT.createdBy
      )
      .run();

    // Seed project-scoped API key
    await db
      .prepare(
        `INSERT OR REPLACE INTO api_keys
         (id, organization_id, project_id, created_by, name, key_prefix, key_hash, role, permissions, status)
         VALUES (?, ?, ?, ?, 'Project Test Key', ?, ?, 'api_admin', '["*"]', 'active')`
      )
      .bind(
        TEST_PROJECT_API_KEY.id,
        TEST_ORG.id,
        TEST_PROJECT.id,
        TEST_USER.id,
        TEST_PROJECT_API_KEY.prefix,
        apiKeyHash
      )
      .run();

    // Cache API key in KV
    await kv.apiKeys.put(`key:${apiKeyHash}`, JSON.stringify(TEST_PROJECT_CACHED_KEY));
  });

  describe("approved mint submission boundary", () => {
    async function seedExecutingMintOperation(params: {
      id: string;
      attemptId: string;
      leaseExpiresAt: string;
    }) {
      await getDb(env)
        .prepare(
          `INSERT INTO wallet_operations
             (id, organization_id, project_id, wallet_id, api_key_id, source,
              operation_family, operation_type, raw_payload, status,
              execution_started_at, execution_attempt_id, execution_lease_expires_at,
              execution_attempts)
           VALUES (?, ?, ?, ?, ?, 'api', 'issuance', 'issuance_mint_execute',
                   '{}'::jsonb, 'executing', ?, ?, ?, 1)`
        )
        .bind(
          params.id,
          TEST_ORG.id,
          TEST_PROJECT.id,
          "wallet_approved_mint_boundary",
          TEST_PROJECT_API_KEY.id,
          new Date().toISOString(),
          params.attemptId,
          params.leaseExpiresAt
        )
        .run();
    }

    function approvedMintContext(operationId: string, attemptId: string) {
      const values: Record<string, unknown> = {
        apiKey: TEST_PROJECT_CACHED_KEY,
        projectId: TEST_PROJECT.id,
        approvedWalletOperationId: operationId,
        approvedWalletOperationAttemptId: attemptId,
      };
      return {
        env,
        get(key: string) {
          return values[key];
        },
      } as never;
    }

    it("does not reserve supply after the approved execution lease expires", async () => {
      const token = await seedIssuedToken({ id: "tok_approved_mint_expired" });
      await getDb(env)
        .prepare(
          "UPDATE issued_tokens SET total_supply_cached = '100', max_supply = '1000' WHERE id = ?"
        )
        .bind(token.id)
        .run();
      await seedExecutingMintOperation({
        id: "wop_approved_mint_expired",
        attemptId: "attempt_approved_mint_expired",
        leaseExpiresAt: "2000-01-01T00:00:00.000Z",
      });

      await expect(
        reserveMintSupplyAtApprovedEffectBoundary(
          approvedMintContext("wop_approved_mint_expired", "attempt_approved_mint_expired"),
          token.id,
          "200"
        )
      ).rejects.toMatchObject({
        code: "FORBIDDEN",
        message: "Approved-operation execution lease was lost",
      });

      const state = await getDb(env)
        .prepare(
          `SELECT token.total_supply_cached, operation.execution_effect_started_at
           FROM issued_tokens token
           CROSS JOIN wallet_operations operation
           WHERE token.id = ? AND operation.id = ?`
        )
        .bind(token.id, "wop_approved_mint_expired")
        .first<{ total_supply_cached: string; execution_effect_started_at: string | null }>();
      expect(state).toEqual({
        total_supply_cached: "100",
        execution_effect_started_at: null,
      });
    });

    it("rolls back the effect fence when the atomic cap reservation is refused", async () => {
      const token = await seedIssuedToken({ id: "tok_approved_mint_capped" });
      await getDb(env)
        .prepare(
          "UPDATE issued_tokens SET total_supply_cached = '900', max_supply = '1000' WHERE id = ?"
        )
        .bind(token.id)
        .run();
      await seedExecutingMintOperation({
        id: "wop_approved_mint_capped",
        attemptId: "attempt_approved_mint_capped",
        leaseExpiresAt: "2099-01-01T00:00:00.000Z",
      });

      await expect(
        reserveMintSupplyAtApprovedEffectBoundary(
          approvedMintContext("wop_approved_mint_capped", "attempt_approved_mint_capped"),
          token.id,
          "200"
        )
      ).rejects.toMatchObject({ code: "MAX_SUPPLY_EXCEEDED" });

      const state = await getDb(env)
        .prepare(
          `SELECT token.total_supply_cached, operation.execution_effect_started_at
           FROM issued_tokens token
           CROSS JOIN wallet_operations operation
           WHERE token.id = ? AND operation.id = ?`
        )
        .bind(token.id, "wop_approved_mint_capped")
        .first<{ total_supply_cached: string; execution_effect_started_at: string | null }>();
      expect(state).toEqual({
        total_supply_cached: "900",
        execution_effect_started_at: null,
      });
    });
  });

  describe("GET /v1/issuance/tokens/{tokenId}/transactions", () => {
    it("filters the per-token list by type with an accurate total", async () => {
      const token = await seedIssuedToken();
      await seedIssuanceTransaction({
        id: "ptx_mint",
        type: "mint",
        params: {},
        createdAt: "2024-02-02T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ptx_burn",
        type: "burn",
        params: {},
        createdAt: "2024-02-01T00:00:00.000Z",
      });

      const res = await app.request(
        `/v1/issuance/tokens/${token.id}/transactions?type=mint&page=1&pageSize=10`,
        {
          method: "GET",
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(1);
      expect(body.data.map((tx: { id: string }) => tx.id)).toEqual(["ptx_mint"]);
    });

    it("rejects an invalid type with 400", async () => {
      const token = await seedIssuedToken();

      const res = await app.request(
        `/v1/issuance/tokens/${token.id}/transactions?type=not_a_real_type`,
        {
          method: "GET",
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(400);
    });
  });

  describe("GET /v1/issuance/transactions", () => {
    async function cacheProjectApiKey(overrides: Record<string, unknown>) {
      const { apiKeys } = createKVStoreSet(env);
      await apiKeys.put(
        `key:${apiKeyHash}`,
        JSON.stringify({
          ...TEST_PROJECT_CACHED_KEY,
          ...overrides,
        })
      );
    }

    it("returns matching wallet transactions across all types when type is omitted", async () => {
      const token = await seedIssuedToken();
      const wallet = await seedIssuanceActivityWallet();
      const tokenAccount = await deriveAssociatedTokenAccount(
        wallet.publicKey,
        token.mintAddress ?? TEST_SOLANA_ADDRESSES.mint
      );

      await seedIssuanceTransaction({
        id: "ttx_wallet_mint",
        type: "mint",
        params: { destination: wallet.publicKey, amount: "12" },
        createdAt: "2024-01-05T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_wallet_burn_ata",
        type: "burn",
        params: { source: tokenAccount, amount: "2" },
        createdAt: "2024-01-04T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_wallet_force_burn",
        type: "force_burn",
        params: { source: wallet.publicKey, amount: "1" },
        createdAt: "2024-01-03T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_wallet_update_authority",
        type: "update_authority",
        params: {
          role: "mint",
          currentAuthority: wallet.publicKey,
          newAuthority: TEST_SOLANA_ADDRESSES.wallet3,
        },
        createdAt: "2024-01-02T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_unrelated_burn",
        type: "burn",
        params: { source: TEST_SOLANA_ADDRESSES.wallet2, amount: "1" },
        createdAt: "2024-01-06T00:00:00.000Z",
      });

      const res = await app.request(
        `/v1/issuance/transactions?walletId=${wallet.walletId}&page=1&pageSize=10`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(4);
      const transactionIds = body.data.map(
        (entry: { transaction: { id: string } }) => entry.transaction.id
      );
      expect(transactionIds).toEqual([
        "ttx_wallet_mint",
        "ttx_wallet_burn_ata",
        "ttx_wallet_force_burn",
        "ttx_wallet_update_authority",
      ]);
      expect(body.data[0].token).toMatchObject({
        id: token.id,
        symbol: token.symbol,
        mintAddress: token.mintAddress,
      });
    });

    it("scopes omitted wallet filters to all token-readable selected-wallet bindings", async () => {
      const token = await seedIssuedToken();
      const walletA = await seedIssuanceActivityWallet(
        "wal_selected_tokens_a",
        TEST_SOLANA_ADDRESSES.wallet1
      );
      const walletB = await seedIssuanceActivityWallet(
        "wal_selected_tokens_b",
        TEST_SOLANA_ADDRESSES.wallet2
      );
      const walletC = await seedIssuanceActivityWallet(
        "wal_selected_tokens_c",
        TEST_SOLANA_ADDRESSES.wallet3
      );
      const walletATokenAccount = await deriveAssociatedTokenAccount(
        walletA.publicKey,
        token.mintAddress ?? TEST_SOLANA_ADDRESSES.mint
      );

      await seedIssuanceTransaction({
        id: "ttx_selected_wallet_a",
        type: "burn",
        params: { source: walletATokenAccount, amount: "1" },
        createdAt: "2024-01-05T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_selected_wallet_b",
        type: "burn",
        params: { source: walletB.publicKey, amount: "2" },
        createdAt: "2024-01-04T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_selected_wallet_c",
        type: "burn",
        params: { source: walletC.publicKey, amount: "3" },
        createdAt: "2024-01-06T00:00:00.000Z",
      });
      await cacheProjectApiKey({
        permissions: ["tokens:read"],
        walletBindings: [
          { walletId: walletA.walletId, permissions: ["tokens:read"] },
          { walletId: walletB.walletId, permissions: ["tokens:read"] },
        ],
      });

      const res = await app.request(
        "/v1/issuance/transactions?type=burn&page=1&pageSize=10",
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(2);
      expect(
        body.data.map((entry: { transaction: { id: string } }) => entry.transaction.id)
      ).toEqual(["ttx_selected_wallet_a", "ttx_selected_wallet_b"]);
    });

    it("omits selected-wallet bindings that lack wallet-level tokens:read", async () => {
      await seedIssuedToken();
      const walletA = await seedIssuanceActivityWallet(
        "wal_mixed_tokens_a",
        TEST_SOLANA_ADDRESSES.wallet1
      );
      const walletB = await seedIssuanceActivityWallet(
        "wal_mixed_tokens_b",
        TEST_SOLANA_ADDRESSES.wallet2
      );

      await seedIssuanceTransaction({
        id: "ttx_mixed_tokens_read",
        type: "burn",
        params: { source: walletA.publicKey, amount: "1" },
        createdAt: "2024-01-05T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_mixed_payments_only",
        type: "burn",
        params: { source: walletB.publicKey, amount: "2" },
        createdAt: "2024-01-06T00:00:00.000Z",
      });
      await cacheProjectApiKey({
        permissions: ["tokens:read"],
        walletBindings: [
          { walletId: walletA.walletId, permissions: ["tokens:read"] },
          { walletId: walletB.walletId, permissions: ["payments:read"] },
        ],
      });

      const res = await app.request(
        "/v1/issuance/transactions?type=burn&page=1&pageSize=10",
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(1);
      expect(body.data[0].transaction.id).toBe("ttx_mixed_tokens_read");
    });

    it("returns an empty page for selected-wallet keys with no token-readable bindings", async () => {
      await seedIssuedToken();
      const wallet = await seedIssuanceActivityWallet();
      await seedIssuanceTransaction({
        id: "ttx_no_token_binding",
        type: "burn",
        params: { source: wallet.publicKey, amount: "1" },
      });
      await cacheProjectApiKey({
        permissions: ["tokens:read"],
        walletBindings: [{ walletId: wallet.walletId, permissions: ["payments:read"] }],
      });

      const res = await app.request(
        "/v1/issuance/transactions?type=burn&page=1&pageSize=10",
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(0);
      expect(body.data).toEqual([]);
    });

    it("keeps unrestricted project keys org/project scoped when walletId is omitted", async () => {
      const token = await seedIssuedToken();
      await seedOrganization({
        id: "org_issuance_other",
        name: "Other Org",
        slug: "issuance-other-org",
      });
      await seedProject({
        id: "prj_issuance_other_project",
        organizationId: TEST_ORG.id,
        name: "Other Project",
        slug: "issuance-other-project",
      });
      await seedProject({
        id: "prj_issuance_other_org",
        organizationId: "org_issuance_other",
        name: "Other Org Project",
        slug: "issuance-other-org-project",
      });
      const sameOrgOtherProjectToken = await seedIssuedToken({
        id: "tok_other_project_transactions",
        projectId: "prj_issuance_other_project",
        mintAddress: null,
      });
      const otherOrgToken = await seedIssuedToken({
        id: "tok_other_org_transactions",
        organizationId: "org_issuance_other",
        projectId: "prj_issuance_other_org",
        mintAddress: null,
      });

      await seedIssuanceTransaction({
        id: "ttx_current_project",
        tokenId: token.id,
        type: "burn",
        params: { source: TEST_SOLANA_ADDRESSES.wallet1, amount: "1" },
        createdAt: "2024-01-05T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_same_org_other_project",
        tokenId: sameOrgOtherProjectToken.id,
        type: "burn",
        params: { source: TEST_SOLANA_ADDRESSES.wallet1, amount: "2" },
        createdAt: "2024-01-06T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_other_org",
        tokenId: otherOrgToken.id,
        organizationId: "org_issuance_other",
        type: "burn",
        params: { source: TEST_SOLANA_ADDRESSES.wallet1, amount: "3" },
        createdAt: "2024-01-07T00:00:00.000Z",
      });

      const res = await app.request(
        "/v1/issuance/transactions?type=burn&page=1&pageSize=10",
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(1);
      expect(body.data[0].transaction.id).toBe("ttx_current_project");
    });

    it("does not match force-burn rows by delegate authority", async () => {
      const token = await seedIssuedToken();
      const authorityWallet = await seedIssuanceActivityWallet(
        "wal_force_burn_authority",
        TEST_SOLANA_ADDRESSES.wallet1
      );
      const sourceWallet = await seedIssuanceActivityWallet(
        "wal_force_burn_source",
        TEST_SOLANA_ADDRESSES.wallet2
      );
      const sourceTokenAccount = await deriveAssociatedTokenAccount(
        sourceWallet.publicKey,
        token.mintAddress ?? TEST_SOLANA_ADDRESSES.mint
      );

      await seedIssuanceTransaction({
        id: "ttx_delegate_authority_force_burn",
        type: "force_burn",
        params: {
          source: sourceTokenAccount,
          amount: "1",
          delegateAuthority: authorityWallet.publicKey,
        },
      });

      const authorityRes = await app.request(
        `/v1/issuance/transactions?walletId=${authorityWallet.walletId}&type=force_burn&page=1&pageSize=10`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(authorityRes.status).toBe(200);
      const authorityBody = await authorityRes.json();
      expect(authorityBody.meta.total).toBe(0);
      expect(authorityBody.data).toEqual([]);

      const sourceRes = await app.request(
        `/v1/issuance/transactions?walletId=${sourceWallet.walletId}&type=force_burn&page=1&pageSize=10`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(sourceRes.status).toBe(200);
      const sourceBody = await sourceRes.json();
      expect(sourceBody.meta.total).toBe(1);
      expect(sourceBody.data[0].transaction.id).toBe("ttx_delegate_authority_force_burn");
    });

    it("does not duplicate wallet-filtered transactions when multiple token accounts match one row", async () => {
      const token = await seedIssuedToken();
      const tokenAccountA = await deriveAssociatedTokenAccount(
        TEST_SOLANA_ADDRESSES.wallet1,
        token.mintAddress ?? TEST_SOLANA_ADDRESSES.mint
      );
      const tokenAccountB = await deriveAssociatedTokenAccount(
        TEST_SOLANA_ADDRESSES.wallet2,
        token.mintAddress ?? TEST_SOLANA_ADDRESSES.mint
      );

      await seedIssuanceTransaction({
        id: "ttx_multi_token_account_match",
        type: "seize",
        params: {
          source: tokenAccountA,
          destination: tokenAccountB,
          amount: "1",
        },
      });

      const service = new TokenService(getDb(env));
      const result = await service.listTransactions({
        organizationId: TEST_ORG.id,
        projectId: TEST_PROJECT.id,
        types: ["seize"],
        walletScope: {
          publicKeys: [TEST_SOLANA_ADDRESSES.wallet1],
          tokenAccounts: [
            { tokenId: token.id, tokenAccount: tokenAccountA },
            { tokenId: token.id, tokenAccount: tokenAccountB },
          ],
        },
      });

      expect(result.total).toBe(1);
      expect(result.transactions.map((entry) => entry.transaction.id)).toEqual([
        "ttx_multi_token_account_match",
      ]);
    });

    it("paginates wallet-filtered transactions with stable totals and no duplicate rows", async () => {
      await seedIssuedToken();
      const wallet = await seedIssuanceActivityWallet();

      for (let index = 1; index <= 12; index += 1) {
        await seedIssuanceTransaction({
          id: `ttx_wallet_page_${index.toString().padStart(2, "0")}`,
          type: "burn",
          params: { source: wallet.publicKey, amount: String(index) },
          createdAt: `2024-01-${index.toString().padStart(2, "0")}T00:00:00.000Z`,
        });
      }

      const fetchPage = async (page: number) => {
        const res = await app.request(
          `/v1/issuance/transactions?walletId=${wallet.walletId}&type=burn&page=${page}&pageSize=5`,
          {
            method: "GET",
            headers: {
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
          },
          env
        );
        expect(res.status).toBe(200);
        return res.json();
      };

      const [pageOne, pageTwo, pageThree] = await Promise.all([
        fetchPage(1),
        fetchPage(2),
        fetchPage(3),
      ]);
      expect([pageOne.meta.total, pageTwo.meta.total, pageThree.meta.total]).toEqual([12, 12, 12]);

      const transactionIds = [pageOne, pageTwo, pageThree].flatMap((body) =>
        body.data.map((entry: { transaction: { id: string } }) => entry.transaction.id)
      );
      expect(transactionIds).toEqual([
        "ttx_wallet_page_12",
        "ttx_wallet_page_11",
        "ttx_wallet_page_10",
        "ttx_wallet_page_09",
        "ttx_wallet_page_08",
        "ttx_wallet_page_07",
        "ttx_wallet_page_06",
        "ttx_wallet_page_05",
        "ttx_wallet_page_04",
        "ttx_wallet_page_03",
        "ttx_wallet_page_02",
        "ttx_wallet_page_01",
      ]);
      expect(new Set(transactionIds).size).toBe(12);
    });

    it("uses transaction id as a deterministic pagination tiebreaker", async () => {
      await seedIssuedToken();
      const wallet = await seedIssuanceActivityWallet();

      for (let index = 1; index <= 7; index += 1) {
        await seedIssuanceTransaction({
          id: `ttx_same_time_${index.toString().padStart(2, "0")}`,
          type: "burn",
          params: { source: wallet.publicKey, amount: String(index) },
          createdAt: "2024-01-01T00:00:00.000Z",
        });
      }

      const fetchPage = async (page: number) => {
        const res = await app.request(
          `/v1/issuance/transactions?walletId=${wallet.walletId}&type=burn&page=${page}&pageSize=3`,
          {
            method: "GET",
            headers: {
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
          },
          env
        );
        expect(res.status).toBe(200);
        return res.json();
      };

      const [pageOne, pageTwo, pageThree] = await Promise.all([
        fetchPage(1),
        fetchPage(2),
        fetchPage(3),
      ]);
      expect([pageOne.meta.total, pageTwo.meta.total, pageThree.meta.total]).toEqual([7, 7, 7]);

      const transactionIds = [pageOne, pageTwo, pageThree].flatMap((body) =>
        body.data.map((entry: { transaction: { id: string } }) => entry.transaction.id)
      );
      expect(transactionIds).toEqual([
        "ttx_same_time_07",
        "ttx_same_time_06",
        "ttx_same_time_05",
        "ttx_same_time_04",
        "ttx_same_time_03",
        "ttx_same_time_02",
        "ttx_same_time_01",
      ]);
      expect(new Set(transactionIds).size).toBe(7);
    });

    it("matches wallet public keys when no token-account candidates are derived", async () => {
      const token = await seedIssuedToken({
        id: "tok_no_mint_candidates",
        mintAddress: null,
      });
      const wallet = await seedIssuanceActivityWallet();

      await seedIssuanceTransaction({
        id: "ttx_public_key_only_force_burn",
        tokenId: token.id,
        type: "force_burn",
        params: { source: wallet.publicKey, amount: "1" },
      });

      const res = await app.request(
        `/v1/issuance/transactions?walletId=${wallet.walletId}&type=force_burn&page=1&pageSize=10`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(1);
      expect(body.data[0].transaction.id).toBe("ttx_public_key_only_force_burn");
    });

    it("supports repeated type filters with status", async () => {
      const token = await seedIssuedToken();
      await seedIssuanceTransaction({
        id: "ttx_filter_burn",
        type: "burn",
        status: "confirmed",
        params: { source: TEST_SOLANA_ADDRESSES.wallet1, amount: "1" },
        createdAt: "2024-01-05T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_filter_force_burn",
        type: "force_burn",
        status: "confirmed",
        params: { source: TEST_SOLANA_ADDRESSES.wallet1, amount: "1" },
        createdAt: "2024-01-04T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_filter_pending_force_burn",
        type: "force_burn",
        status: "pending",
        params: { source: TEST_SOLANA_ADDRESSES.wallet1, amount: "1" },
        createdAt: "2024-01-06T00:00:00.000Z",
      });
      await seedIssuanceTransaction({
        id: "ttx_filter_mint",
        type: "mint",
        status: "confirmed",
        params: { destination: TEST_SOLANA_ADDRESSES.wallet1, amount: "1" },
        createdAt: "2024-01-07T00:00:00.000Z",
      });

      const res = await app.request(
        "/v1/issuance/transactions?type=burn&type=force_burn&status=confirmed&page=1&pageSize=10",
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(2);
      const transactionIds = body.data.map(
        (entry: { transaction: { id: string } }) => entry.transaction.id
      );
      expect(transactionIds).toEqual(["ttx_filter_burn", "ttx_filter_force_burn"]);
      expect(body.data[0].token.id).toBe(token.id);
    });

    it("returns 400 for invalid transaction type filters", async () => {
      const res = await app.request(
        "/v1/issuance/transactions?type=burn&type=unknown",
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.message).toBe("Invalid type query parameter");
    });

    it("allows explicit wallet filters for selected-wallet keys with wallet-level tokens:read", async () => {
      await seedIssuedToken();
      const wallet = await seedIssuanceActivityWallet();
      await seedIssuanceTransaction({
        id: "ttx_explicit_wallet_bound",
        type: "burn",
        params: { source: wallet.publicKey, amount: "1" },
      });
      await cacheProjectApiKey({
        permissions: ["tokens:read"],
        walletBindings: [{ walletId: wallet.walletId, permissions: ["tokens:read"] }],
      });

      const res = await app.request(
        `/v1/issuance/transactions?walletId=${wallet.walletId}&type=burn&page=1&pageSize=10`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBe(1);
      expect(body.data[0].transaction.id).toBe("ttx_explicit_wallet_bound");
    });

    it("returns 404 when the requested wallet does not exist", async () => {
      const res = await app.request(
        "/v1/issuance/transactions?walletId=wal_missing_issuance_transactions&type=burn",
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(404);
      const body = await res.json();
      expect(body.error.code).toBe("NOT_FOUND");
      expect(body.error.message).toMatch(/^Wallet not found\./);
    });

    it("enforces wallet-level tokens:read for wallet filters", async () => {
      const wallet = await seedIssuanceActivityWallet();
      await cacheProjectApiKey({
        permissions: ["tokens:read"],
        walletBindings: [{ walletId: wallet.walletId, permissions: ["payments:read"] }],
      });

      const res = await app.request(
        `/v1/issuance/transactions?walletId=${wallet.walletId}&type=burn`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(403);
    });

    it("rejects explicit wallet filters for unbound selected-wallet keys", async () => {
      const boundWallet = await seedIssuanceActivityWallet(
        "wal_bound_tokens_read",
        TEST_SOLANA_ADDRESSES.wallet1
      );
      const requestedWallet = await seedIssuanceActivityWallet(
        "wal_unbound_tokens_read",
        TEST_SOLANA_ADDRESSES.wallet2
      );
      await cacheProjectApiKey({
        permissions: ["tokens:read"],
        walletBindings: [{ walletId: boundWallet.walletId, permissions: ["tokens:read"] }],
      });

      const res = await app.request(
        `/v1/issuance/transactions?walletId=${requestedWallet.walletId}&type=burn`,
        {
          method: "GET",
          headers: {
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
        },
        env
      );

      expect(res.status).toBe(403);
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // Token CRUD Tests
  // ═══════════════════════════════════════════════════════════════════════════

  describe("POST /v1/issuance/tokens", () => {
    it("creates a new token", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Test Stablecoin",
            symbol: "TUSD",
            decimals: 6,
            description: "A test stablecoin",
            maxSupply: "1000000000000000",
            requiresAllowlist: true,
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token).toBeDefined();
      expect(body.data.token.id).toMatch(/^tok_/);
      expect(body.data.token.name).toBe("Test Stablecoin");
      expect(body.data.token.symbol).toBe("TUSD");
      expect(body.data.token.decimals).toBe(6);
      expect(body.data.token.status).toBe("pending");
      expect(body.data.token.requiresAllowlist).toBe(true);
      expect(body.data.token.projectId).toBe(TEST_PROJECT.id);
    });

    it("creates token with default decimals", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Default Decimals Token",
            symbol: "DDT",
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.decimals).toBe(9);
    });

    it("creates token with mixed-case symbol", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Mixed Case Symbol Token",
            symbol: "UsdX9",
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.symbol).toBe("UsdX9");
    });

    it("returns 400 for invalid symbol", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Invalid Symbol Token",
            symbol: "invalid_symbol",
          }),
        },
        env
      );

      expect(res.status).toBe(400);
    });

    it("returns 401 without auth", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ name: "Test", symbol: "TEST" }),
        },
        env
      );

      expect(res.status).toBe(401);
    });
  });

  describe("GET /v1/issuance/tokens", () => {
    beforeEach(async () => {
      // Create a token for listing
      await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ name: "Listed Token", symbol: "LIST" }),
        },
        env
      );
    });

    it("lists tokens for project", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data).toBeInstanceOf(Array);
      expect(body.data.length).toBeGreaterThan(0);
      expect(body.data[0].name).toBe("Listed Token");
      expect(body.meta.total).toBeGreaterThan(0);
    });

    it("supports pagination", async () => {
      const res = await app.request(
        "/v1/issuance/tokens?page=1&pageSize=10",
        {
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.page).toBe(1);
      expect(body.meta.pageSize).toBe(10);
    });

    it("filters by search, reporting the filtered total", async () => {
      const match = await app.request(
        "/v1/issuance/tokens?search=Listed",
        { headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` } },
        env
      );
      expect(match.status).toBe(200);
      const matchBody = await match.json();
      expect(matchBody.data.length).toBe(matchBody.meta.total);
      expect(matchBody.data.every((token: { name: string }) => token.name === "Listed Token")).toBe(
        true
      );

      const miss = await app.request(
        "/v1/issuance/tokens?search=NoSuchTokenAnywhere",
        { headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` } },
        env
      );
      const missBody = await miss.json();
      expect(missBody.data).toEqual([]);
      expect(missBody.meta.total).toBe(0);
      expect(missBody.meta.hasMore).toBe(false);
    });

    it("accepts a blank search as no filter", async () => {
      const res = await app.request(
        "/v1/issuance/tokens?search=",
        { headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` } },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.meta.total).toBeGreaterThan(0);
    });

    it.each([
      ["page=0", "non-positive page"],
      ["page=9007199254740991", "page beyond the offset bound"],
      ["pageSize=101", "page size above the cap"],
      ["pageSize=abc", "non-numeric page size"],
      ["status=bogus", "unknown status"],
      ["deploymentStatus=bogus", "unknown deployment status"],
      ["sortBy=created_at%3B+DROP+TABLE+issued_tokens", "unwhitelisted sort key"],
      ["sortDirection=sideways", "unknown sort direction"],
      ["createdAfter=yesterday", "unparseable timestamp"],
    ])("rejects %s (%s) with 400", async (query) => {
      const res = await app.request(
        `/v1/issuance/tokens?${query}`,
        { headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` } },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("BAD_REQUEST");
    });

    it("rejects an inverted created_at window with 400", async () => {
      const res = await app.request(
        "/v1/issuance/tokens?createdAfter=2026-06-01T00:00:00.000Z&createdBefore=2026-01-01T00:00:00.000Z",
        { headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` } },
        env
      );

      expect(res.status).toBe(400);
    });
  });

  describe("GET /v1/issuance/tokens/facets", () => {
    beforeEach(async () => {
      await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ name: "Facet Token", symbol: "FCT", template: "stablecoin" }),
        },
        env
      );
    });

    // "facets" is a literal path registered before /tokens/:tokenId — if the
    // parameterised route ever wins the match, this 404s as a missing token.
    it("returns facets rather than resolving 'facets' as a token id", async () => {
      const res = await app.request(
        "/v1/issuance/tokens/facets",
        { headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` } },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data.total).toBeGreaterThan(0);
      expect(body.data.templates).toEqual(
        expect.arrayContaining([{ template: "stablecoin", count: expect.any(Number) }])
      );
      // Undeployed drafts, so the derived state counts land on draft.
      expect(body.data.deploymentStatuses.draft).toBeGreaterThan(0);
    });
  });

  describe("GET /v1/issuance/tokens/:tokenId", () => {
    let tokenId: string;

    beforeEach(async () => {
      const createRes = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ name: "Detail Token", symbol: "DETAIL" }),
        },
        env
      );
      const created = await createRes.json();
      tokenId = created.data.token.id;
    });

    it("returns token details", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${tokenId}`,
        {
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data.token.id).toBe(tokenId);
      expect(body.data.token.name).toBe("Detail Token");
    });

    it("returns 404 for non-existent token", async () => {
      const res = await app.request(
        "/v1/issuance/tokens/tok_nonexistent12",
        {
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(404);
    });

    it("returns 404 when the token belongs to a different project in the same org", async () => {
      const otherProjectId = "prj_cross_project_isolation";
      await seedProject({
        id: otherProjectId,
        organizationId: TEST_ORG.id,
        name: "Other Project",
        slug: "cross-project-isolation",
      });
      const otherProjectToken = await seedIssuedToken({
        id: "tok_other_project_iso",
        projectId: otherProjectId,
        mintAddress: null,
        status: "pending",
      });

      const res = await app.request(
        `/v1/issuance/tokens/${otherProjectToken.id}`,
        {
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(404);
    });
  });

  describe("PATCH /v1/issuance/tokens/:tokenId", () => {
    let tokenId: string;

    beforeEach(async () => {
      const createRes = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ name: "Update Token", symbol: "UPDATE" }),
        },
        env
      );
      const created = await createRes.json();
      tokenId = created.data.token.id;
    });

    it("updates token details", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${tokenId}`,
        {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Updated Token Name",
            description: "New description",
          }),
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data.token.name).toBe("Updated Token Name");
      expect(body.data.token.description).toBe("New description");
    });

    it("rejects metadata updates while token deployment is in progress", async () => {
      await getDb(env)
        .prepare("UPDATE issued_tokens SET status = 'deploying' WHERE id = ?")
        .bind(tokenId)
        .run();

      const res = await app.request(
        `/v1/issuance/tokens/${tokenId}`,
        {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ name: "Divergent metadata" }),
        },
        env
      );

      expect(res.status).toBe(409);
      const row = await getDb(env)
        .prepare("SELECT name FROM issued_tokens WHERE id = ?")
        .bind(tokenId)
        .first<{ name: string }>();
      expect(row?.name).toBe("Update Token");
    });

    it("updates deployed token metadata on-chain before persisting local fields", async () => {
      const db = getDb(env);
      const activeTokenId = "tok_metadataupdate1";

      await db
        .prepare(
          `INSERT INTO issued_tokens (
            id, project_id, organization_id, signing_wallet_id, mint_address, mint_authority,
            metadata_authority, freeze_authority, name, symbol, decimals, description, uri,
            image_url, total_supply_cached, is_mintable, freeze_authority_enabled,
            allowlist_enabled, status, deployed_at, created_by
          ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '0', 1, 1, 0, 'active', ?, ?)`
        )
        .bind(
          activeTokenId,
          TEST_PROJECT.id,
          TEST_ORG.id,
          null,
          TEST_ACTIVE_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_SOLANA_ADDRESSES.wallet3,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          "Deployed Token",
          "DPLY",
          6,
          null,
          "https://example.com/original.json",
          null,
          "2024-01-02T00:00:00.000Z",
          TEST_PROJECT_API_KEY.id
        )
        .run();

      const resolveCurrentAuthoritySpy = vi
        .spyOn(AuthorityResolution, "resolveCurrentAuthorityForRole")
        .mockResolvedValueOnce(TEST_SOLANA_ADDRESSES.wallet3);
      const resolveAuthoritySignerSpy = vi
        .spyOn(AuthorityResolution, "resolveAuthoritySigner")
        .mockResolvedValueOnce({
          signer: { address: TEST_SOLANA_ADDRESSES.wallet3 } as never,
          walletId: "wal_test_metadata",
        });
      const updateMetadataSpy = vi
        .spyOn(MosaicService.prototype, "updateMetadata")
        .mockResolvedValueOnce({
          signature: "sig_metadata_update",
          slot: 123n,
        });

      try {
        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}`,
          {
            method: "PATCH",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              name: "On-chain Updated Name",
              description: "On-chain description",
              uri: "https://example.com/updated.json",
              imageUrl: "https://example.com/token.png",
            }),
          },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.token.name).toBe("On-chain Updated Name");
        expect(body.data.token.description).toBe("On-chain description");
        expect(body.data.token.uri).toBe("https://example.com/updated.json");
        expect(body.data.token.imageUrl).toBe("https://example.com/token.png");

        expect(resolveCurrentAuthoritySpy).toHaveBeenCalledWith(
          env,
          expect.anything(),
          expect.objectContaining({ id: activeTokenId }),
          "metadata"
        );
        expect(resolveAuthoritySignerSpy).toHaveBeenCalledWith(
          expect.objectContaining({
            auth: expect.objectContaining({ organizationId: TEST_ORG.id }),
            token: expect.objectContaining({ id: activeTokenId }),
            currentAuthority: TEST_SOLANA_ADDRESSES.wallet3,
          })
        );
        expect(updateMetadataSpy).toHaveBeenCalledWith({
          mint: TEST_ACTIVE_TOKEN.mintAddress,
          name: "On-chain Updated Name",
          description: "On-chain description",
          uri: "https://example.com/updated.json",
          imageUrl: "https://example.com/token.png",
          updateAuthority: expect.objectContaining({ address: TEST_SOLANA_ADDRESSES.wallet3 }),
          feePayer: expect.objectContaining({ address: TEST_SOLANA_ADDRESSES.wallet3 }),
        });
      } finally {
        resolveCurrentAuthoritySpy.mockRestore();
        resolveAuthoritySignerSpy.mockRestore();
        updateMetadataSpy.mockRestore();
      }
    });

    it("updates requiresAllowlist while the token is undeployed", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${tokenId}`,
        {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ requiresAllowlist: true }),
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data.token.requiresAllowlist).toBe(true);
    });

    it("rejects requiresAllowlist changes after deployment", async () => {
      const db = getDb(env);
      const deployedTokenId = "tok_allowlistlocked1";

      await db
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, total_supply_cached, is_mintable, freeze_authority_enabled, allowlist_enabled, status, deployed_at, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Locked Token', 'LOCK', 6, '0', 1, 1, 0, 'active', '2024-01-02T00:00:00.000Z', ?)`
        )
        .bind(
          deployedTokenId,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_ACTIVE_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();

      const res = await app.request(
        `/v1/issuance/tokens/${deployedTokenId}`,
        {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ requiresAllowlist: true }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.message).toContain("requiresAllowlist");
    });

    it("updates symbol and decimals while the token is undeployed", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${tokenId}`,
        {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ symbol: "RENAMED", decimals: 2 }),
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data.token.symbol).toBe("RENAMED");
      expect(body.data.token.decimals).toBe(2);
    });

    it("rejects symbol and decimals changes after deployment", async () => {
      const db = getDb(env);
      const deployedTokenId = "tok_symbollocked1";

      await db
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, total_supply_cached, is_mintable, freeze_authority_enabled, allowlist_enabled, status, deployed_at, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Locked Token', 'LOCK', 6, '0', 1, 1, 0, 'active', '2024-01-02T00:00:00.000Z', ?)`
        )
        .bind(
          deployedTokenId,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_ACTIVE_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();

      const res = await app.request(
        `/v1/issuance/tokens/${deployedTokenId}`,
        {
          method: "PATCH",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ symbol: "NEWSYM" }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.message).toContain("symbol and decimals");
    });

    // The supply cap has no on-chain counterpart: SDP enforces it at mint time,
    // so it stays editable for exactly as long as SDP holds the mint authority.
    describe("maxSupply", () => {
      // A deployed, still-mintable token with `supply` already minted.
      const insertMintableToken = async (id: string, supplyBaseUnits: string) => {
        await getDb(env)
          .prepare(
            `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
             name, symbol, decimals, total_supply_cached, max_supply, is_mintable, freeze_authority_enabled, allowlist_enabled, status, deployed_at, created_by)
             VALUES (?, ?, ?, ?, ?, ?, 'Capped Token', 'CAP', 6, ?, '1000000000', 1, 1, 0, 'active', '2024-01-02T00:00:00.000Z', ?)`
          )
          .bind(
            id,
            TEST_PROJECT.id,
            TEST_ORG.id,
            TEST_ACTIVE_TOKEN.mintAddress,
            TEST_ACTIVE_TOKEN.mintAuthority,
            TEST_ACTIVE_TOKEN.freezeAuthority,
            supplyBaseUnits,
            TEST_PROJECT_API_KEY.id
          )
          .run();
      };

      const patchMaxSupply = (id: string, maxSupply: string | null) =>
        app.request(
          `/v1/issuance/tokens/${id}`,
          {
            method: "PATCH",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ maxSupply }),
          },
          env
        );

      it("updates the cap on an undeployed draft", async () => {
        const res = await patchMaxSupply(tokenId, "2500.5");

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.token.maxSupply).toBe("2500.5");
      });

      it("clears the cap with null", async () => {
        expect((await patchMaxSupply(tokenId, "2500")).status).toBe(200);

        const res = await patchMaxSupply(tokenId, null);

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.token.maxSupply).toBeNull();
      });

      it("updates the cap on a deployed token that still has its mint authority", async () => {
        const deployedTokenId = "tok_capmintable1";
        await insertMintableToken(deployedTokenId, "500000000");

        const res = await patchMaxSupply(deployedTokenId, "2000");

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.token.maxSupply).toBe("2000");
      });

      it("rejects a cap below the already-minted supply", async () => {
        const deployedTokenId = "tok_capbelowsupply1";
        // 1500 minted, so a 1000 cap could never be satisfied.
        await insertMintableToken(deployedTokenId, "1500000000");

        const res = await patchMaxSupply(deployedTokenId, "1000");

        expect(res.status).toBe(400);
        const body = await res.json();
        expect(body.error.message).toContain("already-minted supply");
      });

      it("rejects a cap with more precision than the token's decimals", async () => {
        const deployedTokenId = "tok_capprecision1";
        await insertMintableToken(deployedTokenId, "0");

        const res = await patchMaxSupply(deployedTokenId, "1000.1234567");

        expect(res.status).toBe(400);
        const body = await res.json();
        expect(body.error.message).toContain("maxSupply");
      });

      it("rejects a cap change once the supply is locked on-chain", async () => {
        const db = getDb(env);
        const lockedTokenId = "tok_capsupplylocked1";
        await insertMintableToken(lockedTokenId, "1000000000");
        // What lock-supply leaves behind: no mint authority, minting disabled.
        await db
          .prepare("UPDATE issued_tokens SET mint_authority = NULL, is_mintable = 0 WHERE id = ?")
          .bind(lockedTokenId)
          .run();

        const res = await patchMaxSupply(lockedTokenId, "2000");

        expect(res.status).toBe(400);
        const body = await res.json();
        expect(body.error.message).toContain("locked on-chain");
      });
    });
  });

  describe("POST /v1/issuance/tokens/:tokenId/supply/refresh", () => {
    let activeTokenId: string;

    beforeEach(async () => {
      if (!(env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL) {
        (env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL = "https://rpc.invalid.test";
      }

      const db = getDb(env);

      await db
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, total_supply_cached, is_mintable, freeze_authority_enabled, allowlist_enabled, status, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Refresh Token', 'RFSH', 9, '0', 1, 1, 0, 'active', ?)`
        )
        .bind(
          TEST_ACTIVE_TOKEN.id,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_ACTIVE_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();

      activeTokenId = TEST_ACTIVE_TOKEN.id;
    });

    it("refreshes cached supply from RPC", async () => {
      const fetchSpy = vi.spyOn(globalThis, "fetch").mockResolvedValue(
        new Response(
          JSON.stringify({
            jsonrpc: "2.0",
            id: "1",
            result: {
              value: {
                amount: "1500000000",
              },
            },
          }),
          { status: 200, headers: { "Content-Type": "application/json" } }
        )
      );

      const res = await app.request(
        `/v1/issuance/tokens/${activeTokenId}/supply/refresh`,
        {
          method: "POST",
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      fetchSpy.mockRestore();

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data.token.id).toBe(activeTokenId);
      expect(body.data.token.totalSupply).toBe("1.5");
      expect(body.data.token.totalSupplyUpdatedAt).toBeDefined();
    });

    it("returns 400 for undeployed token", async () => {
      const createRes = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ name: "Pending Token", symbol: "PND" }),
        },
        env
      );
      const created = await createRes.json();
      const pendingTokenId = created.data.token.id;

      const res = await app.request(
        `/v1/issuance/tokens/${pendingTokenId}/supply/refresh`,
        {
          method: "POST",
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("TOKEN_NOT_DEPLOYED");
    });

    it("returns 502 when RPC call fails", async () => {
      const fetchSpy = vi
        .spyOn(globalThis, "fetch")
        .mockResolvedValue(new Response("upstream unavailable", { status: 503 }));

      const res = await app.request(
        `/v1/issuance/tokens/${activeTokenId}/supply/refresh`,
        {
          method: "POST",
          headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
        },
        env
      );

      fetchSpy.mockRestore();

      expect(res.status).toBe(502);
      const body = await res.json();
      expect(body.error.code).toBe("SOLANA_RPC_ERROR");
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // Mint Operation Tests
  // ═══════════════════════════════════════════════════════════════════════════

  describe("POST /v1/issuance/tokens/:tokenId/mint/prepare", () => {
    let activeTokenId: string;

    beforeEach(async () => {
      const db = getDb(env);

      // Insert an active (deployed) token directly
      await db
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, total_supply_cached, max_supply, is_mintable, freeze_authority_enabled, allowlist_enabled, status, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Active Token', 'ACTIVE', 9, '0', '1000000000000000000', 1, 1, 0, 'active', ?)`
        )
        .bind(
          TEST_ACTIVE_TOKEN.id,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_ACTIVE_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();

      activeTokenId = TEST_ACTIVE_TOKEN.id;
    });

    // Skip in mock mode - Mosaic SDK requires RPC to fetch mint details
    it.skipIf(isMockMode)("prepares mint transaction", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${activeTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet1,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(200);
      const body = await res.json();
      expect(body.data.transaction).toBeDefined();
      expect(body.data.transaction.id).toMatch(/^ttx_/);
      expect(body.data.transaction.type).toBe("mint");
      expect(body.data.transaction.status).toBe("pending");
    });

    it("returns 400 for inactive token", async () => {
      // Create a pending (not deployed) token
      const createRes = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ name: "Pending Token", symbol: "PEND" }),
        },
        env
      );
      const created = await createRes.json();
      const pendingTokenId = created.data.token.id;

      const res = await app.request(
        `/v1/issuance/tokens/${pendingTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet1,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("TOKEN_NOT_ACTIVE");
    });

    it("returns 400 when max supply would be exceeded", async () => {
      const db = getDb(env);

      // Update token to have small max supply
      await db
        .prepare(
          "UPDATE issued_tokens SET max_supply = '100000000000', total_supply_cached = '50000000000' WHERE id = ?"
        )
        .bind(activeTokenId)
        .run();

      const res = await app.request(
        `/v1/issuance/tokens/${activeTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet1,
              amount: "100", // Would exceed max supply
            },
          }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("MAX_SUPPLY_EXCEEDED");
    });

    it("counts a prepared mint against the cap before the transaction leaves", async () => {
      // A prepared transaction is a mint the client can settle at any point until
      // its blockhash expires, so it is reserved like an executed one — handing it
      // out is prepare's point of no return.
      const db = getDb(env);
      await db
        .prepare(
          "UPDATE issued_tokens SET max_supply = '500000000000', total_supply_cached = '100000000000' WHERE id = ?"
        )
        .bind(activeTokenId)
        .run();

      const createOrgSignerSpy = vi
        .spyOn(SolanaServices, "createOrgSigner")
        .mockResolvedValueOnce({ address: TEST_ACTIVE_TOKEN.mintAuthority } as never);
      const prepareMintToSpy = vi
        .spyOn(MosaicService.prototype, "prepareMintTo")
        .mockResolvedValueOnce({
          serializedTx: "cHJlcGFyZWQtbWludA==",
          blockhash: "11111111111111111111111111111111",
          lastValidBlockHeight: 0n,
          requiredSigners: [],
          tokenAccount: TEST_SOLANA_ADDRESSES.wallet1,
        } as never);

      try {
        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/mint/prepare`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              mint: { destination: TEST_SOLANA_ADDRESSES.wallet1, amount: "200" },
            }),
          },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.transaction.status).toBe("pending");
        expect(body.data.transaction.serializedTx).toBe("cHJlcGFyZWQtbWludA==");

        // The reservation is in the recorded supply, where cap checks and cap
        // changes will see it.
        const row = await db
          .prepare("SELECT total_supply_cached FROM issued_tokens WHERE id = ?")
          .bind(activeTokenId)
          .first<{ total_supply_cached: string }>();
        expect(row?.total_supply_cached).toBe("300000000000");
      } finally {
        createOrgSignerSpy.mockRestore();
        prepareMintToSpy.mockRestore();
      }
    });

    it("enforces the cap in the database even when prepare read a stale one", async () => {
      // The pre-flight check reads a cached token in this process; the reservation
      // is a conditional UPDATE on the token row. A stale generous cap, made
      // deterministic by stubbing `getToken`, must be refused by the database —
      // after the transaction is built, before it leaves.
      const db = getDb(env);
      await db
        .prepare(
          "UPDATE issued_tokens SET max_supply = '500000000000', total_supply_cached = '400000000000' WHERE id = ?"
        )
        .bind(activeTokenId)
        .run();

      const createOrgSignerSpy = vi
        .spyOn(SolanaServices, "createOrgSigner")
        .mockResolvedValueOnce({ address: TEST_ACTIVE_TOKEN.mintAuthority } as never);
      const prepareMintToSpy = vi
        .spyOn(MosaicService.prototype, "prepareMintTo")
        .mockResolvedValueOnce({
          serializedTx: "cmVmdXNlZC1taW50",
          blockhash: "11111111111111111111111111111111",
          lastValidBlockHeight: 0n,
          requiredSigners: [],
          tokenAccount: TEST_SOLANA_ADDRESSES.wallet1,
        } as never);

      const originalGetToken = TokenService.prototype.getToken;
      const getTokenSpy = vi
        .spyOn(TokenService.prototype, "getToken")
        .mockImplementation(async function (this: TokenService, params) {
          const token = await originalGetToken.call(this, params);
          return token ? { ...token, maxSupply: "100000" } : token;
        });

      try {
        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/mint/prepare`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              mint: { destination: TEST_SOLANA_ADDRESSES.wallet1, amount: "200" },
            }),
          },
          env
        );

        expect(res.status).toBe(400);
        const body = await res.json();
        expect(body.error.code).toBe("MAX_SUPPLY_EXCEEDED");

        // No reservation left behind, and — decisive for the wallet-authority
        // flow, where the client could sign and submit whatever it can read — the
        // failed row must not carry the serialized transaction the cap refused.
        const supply = await db
          .prepare("SELECT total_supply_cached FROM issued_tokens WHERE id = ?")
          .bind(activeTokenId)
          .first<{ total_supply_cached: string }>();
        expect(supply?.total_supply_cached).toBe("400000000000");

        const tx = await db
          .prepare(
            "SELECT status, serialized_tx FROM issuance_transactions WHERE token_id = ? AND type = 'mint' ORDER BY created_at DESC LIMIT 1"
          )
          .bind(activeTokenId)
          .first<{ status: string; serialized_tx: string | null }>();
        expect(tx?.status).toBe("failed");
        expect(tx?.serialized_tx).toBeNull();
      } finally {
        getTokenSpy.mockRestore();
        createOrgSignerSpy.mockRestore();
        prepareMintToSpy.mockRestore();
      }
    });

    it("returns 400 for paused token", async () => {
      const db = getDb(env);
      await db
        .prepare("UPDATE issued_tokens SET status = 'paused' WHERE id = ?")
        .bind(activeTokenId)
        .run();

      const res = await app.request(
        `/v1/issuance/tokens/${activeTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet1,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("TOKEN_PAUSED");
    });

    it("returns 400 for zero mint amount", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${activeTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet1,
              amount: "0",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("INVALID_TOKEN_AMOUNT");
    });
  });

  describe("Token Operation Policy", () => {
    const policyTokenId = "tok_operationpolicy";

    beforeEach(async () => {
      await getDb(env)
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, total_supply_cached, is_mintable, freeze_authority_enabled, allowlist_enabled, status, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Operation Policy Token', 'OPP', 9, '0', 1, 1, 0, 'active', ?)`
        )
        .bind(
          policyTokenId,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_ACTIVE_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();
    });

    it("rejects zero force-burn amount before authority resolution", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${policyTokenId}/force-burn/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            forceBurn: {
              source: TEST_SOLANA_ADDRESSES.wallet1,
              amount: "0",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("INVALID_TOKEN_AMOUNT");
    });

    it("rejects zero seize amount before authority resolution", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${policyTokenId}/seize/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            seize: {
              source: TEST_SOLANA_ADDRESSES.wallet1,
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "0",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.code).toBe("INVALID_TOKEN_AMOUNT");
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // Allowlist Tests
  // ═══════════════════════════════════════════════════════════════════════════

  describe("Allowlist Management", () => {
    let tokenId: string;

    beforeEach(async () => {
      const createRes = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Allowlist Token",
            symbol: "ALLOW",
            requiresAllowlist: true,
          }),
        },
        env
      );
      const created = await createRes.json();
      tokenId = created.data.token.id;
    });

    describe("POST /v1/issuance/tokens/:tokenId/allowlist", () => {
      it("adds address to allowlist", async () => {
        const res = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              address: TEST_SOLANA_ADDRESSES.wallet1,
              label: "Test Wallet",
            }),
          },
          env
        );

        expect(res.status).toBe(201);
        const body = await res.json();
        expect(body.data.entry.id).toMatch(/^tal_/);
        expect(body.data.entry.address).toBe(TEST_SOLANA_ADDRESSES.wallet1);
        expect(body.data.entry.label).toBe("Test Wallet");
        expect(body.data.entry.status).toBe("active");
      });

      it("syncs the control list on-chain when an ABL address is configured", async () => {
        const db = getDb(env);
        await db
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(TEST_SOLANA_ADDRESSES.wallet3, tokenId)
          .run();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockResolvedValueOnce(undefined as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                address: TEST_SOLANA_ADDRESSES.wallet1,
                label: "On-chain Wallet",
              }),
            },
            env
          );

          expect(res.status).toBe(201);
          expect(createOrgSignerSpy).toHaveBeenCalled();
          expect(addToListSpy).toHaveBeenCalledWith({
            list: TEST_SOLANA_ADDRESSES.wallet3,
            wallet: TEST_SOLANA_ADDRESSES.wallet1,
          });
        } finally {
          createOrgSignerSpy.mockRestore();
          addToListSpy.mockRestore();
        }
      });

      it("keeps a pending DB row and audit trail when on-chain confirmation is ambiguous", async () => {
        const db = getDb(env);
        await db
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(TEST_SOLANA_ADDRESSES.wallet3, tokenId)
          .run();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockRejectedValueOnce(new Error("on-chain add failed"))
          .mockResolvedValueOnce(undefined as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false);
        const deleteAllowlistEntrySpy = vi.spyOn(TokenService.prototype, "deleteAllowlistEntry");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                address: TEST_SOLANA_ADDRESSES.wallet1,
                label: "On-chain Wallet",
              }),
            },
            env
          );

          expect(res.status).toBe(500);
          expect(deleteAllowlistEntrySpy).not.toHaveBeenCalled();

          const entry = await db
            .prepare("SELECT id, status FROM token_allowlists WHERE token_id = ? AND address = ?")
            .bind(tokenId, TEST_SOLANA_ADDRESSES.wallet1)
            .first<{ id: string; status: string }>();
          expect(entry?.status).toBe("pending");
          const audit = await db
            .prepare(
              `SELECT id FROM audit_logs
               WHERE action = 'create' AND resource_type = 'token_allowlist'
                 AND resource_id = ?`
            )
            .bind(entry?.id)
            .first<{ id: string }>();
          expect(audit).not.toBeNull();

          const retry = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                address: TEST_SOLANA_ADDRESSES.wallet1,
                label: "On-chain Wallet",
              }),
            },
            env
          );
          expect(retry.status).toBe(201);
          const reconciled = await db
            .prepare("SELECT status FROM token_allowlists WHERE id = ?")
            .bind(entry?.id)
            .first<{ status: string }>();
          expect(reconciled?.status).toBe("active");
        } finally {
          createOrgSignerSpy.mockRestore();
          addToListSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          deleteAllowlistEntrySpy.mockRestore();
        }
      });

      it("keeps the DB row and reports success when addToList errors but on-chain membership is confirmed", async () => {
        const db = getDb(env);
        await db
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(TEST_SOLANA_ADDRESSES.wallet3, tokenId)
          .run();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockRejectedValueOnce(new Error("RPC confirmation timeout"));
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);
        const deleteAllowlistEntrySpy = vi.spyOn(TokenService.prototype, "deleteAllowlistEntry");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                address: TEST_SOLANA_ADDRESSES.wallet1,
                label: "Confirmed Despite RPC Error",
              }),
            },
            env
          );

          expect(res.status).toBe(201);
          expect(isWalletOnListSpy).toHaveBeenCalledTimes(1);
          expect(deleteAllowlistEntrySpy).not.toHaveBeenCalled();

          const entry = await db
            .prepare("SELECT id, status FROM token_allowlists WHERE token_id = ? AND address = ?")
            .bind(tokenId, TEST_SOLANA_ADDRESSES.wallet1)
            .first<{ id: string; status: string }>();
          expect(entry?.status).toBe("active");
        } finally {
          createOrgSignerSpy.mockRestore();
          addToListSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          deleteAllowlistEntrySpy.mockRestore();
        }
      });

      it("returns 409 for duplicate address", async () => {
        // Add first entry
        await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ address: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        // Try to add same address again
        const res = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ address: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        expect(res.status).toBe(409);
      });

      it("keeps a re-added entry pending when on-chain membership is uncertain", async () => {
        const db = getDb(env);
        await db
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(TEST_SOLANA_ADDRESSES.wallet3, tokenId)
          .run();

        const tokenService = new TokenService(getDb(env));
        const { entry } = await tokenService.addAllowlistEntry({
          tokenId,
          address: TEST_SOLANA_ADDRESSES.wallet1,
          addedBy: TEST_PROJECT_API_KEY.id,
          label: "Original Operator Add",
        });
        await tokenService.revokeAllowlistEntry(entry.id);

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockRejectedValueOnce(new Error("RPC confirmation timeout"));
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false);
        const deleteAllowlistEntrySpy = vi.spyOn(TokenService.prototype, "deleteAllowlistEntry");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                address: TEST_SOLANA_ADDRESSES.wallet1,
                label: "Re-add Attempt",
              }),
            },
            env
          );

          expect(res.status).toBeGreaterThanOrEqual(500);
          expect(deleteAllowlistEntrySpy).not.toHaveBeenCalled();

          const row = await db
            .prepare("SELECT id, status FROM token_allowlists WHERE token_id = ? AND address = ?")
            .bind(tokenId, TEST_SOLANA_ADDRESSES.wallet1)
            .first<{ id: string; status: string }>();
          expect(row?.id).toBe(entry.id);
          expect(row?.status).toBe("pending");
        } finally {
          createOrgSignerSpy.mockRestore();
          addToListSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          deleteAllowlistEntrySpy.mockRestore();
        }
      });
    });

    describe("GET /v1/issuance/tokens/:tokenId/allowlist", () => {
      it("lists allowlist entries", async () => {
        // Add an entry first
        await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              address: TEST_SOLANA_ADDRESSES.wallet1,
              label: "Listed Wallet",
            }),
          },
          env
        );

        const res = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data).toBeInstanceOf(Array);
        expect(body.data.length).toBe(1);
        expect(body.data[0].label).toBe("Listed Wallet");
      });
    });

    describe("DELETE /v1/issuance/tokens/:tokenId/allowlist/:entryId", () => {
      it("revokes allowlist entry", async () => {
        // Add an entry
        const addRes = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ address: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );
        const added = await addRes.json();
        const entryId = added.data.entry.id;

        // Delete it
        const res = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist/${entryId}`,
          {
            method: "DELETE",
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );

        expect(res.status).toBe(204);

        // Verify it's revoked
        const listRes = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );
        const listBody = await listRes.json();
        expect(listBody.data.length).toBe(0);
      });

      it("syncs control-list removals on-chain when an ABL address is configured", async () => {
        await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ address: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        const db = getDb(env);
        await db
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(TEST_SOLANA_ADDRESSES.wallet3, tokenId)
          .run();

        const listRes = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );
        const listBody = await listRes.json();
        const entryId = listBody.data[0].id;

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const removeFromListSpy = vi
          .spyOn(MosaicService.prototype, "removeFromList")
          .mockResolvedValueOnce(undefined as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist/${entryId}`,
            {
              method: "DELETE",
              headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
            },
            env
          );

          expect(res.status).toBe(204);
          expect(createOrgSignerSpy).toHaveBeenCalled();
          expect(removeFromListSpy).toHaveBeenCalledWith({
            list: TEST_SOLANA_ADDRESSES.wallet3,
            wallet: TEST_SOLANA_ADDRESSES.wallet1,
          });
        } finally {
          createOrgSignerSpy.mockRestore();
          removeFromListSpy.mockRestore();
        }
      });

      it("keeps the database entry active until a retry confirms on-chain removal", async () => {
        await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ address: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        const db = getDb(env);
        await db
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(TEST_SOLANA_ADDRESSES.wallet3, tokenId)
          .run();

        const listRes = await app.request(
          `/v1/issuance/tokens/${tokenId}/allowlist`,
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );
        const listBody = await listRes.json();
        const entryId = listBody.data[0].id;

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const removeFromListSpy = vi
          .spyOn(MosaicService.prototype, "removeFromList")
          .mockRejectedValueOnce(new Error("mosaic removal failed"))
          .mockResolvedValueOnce(undefined as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist/${entryId}`,
            {
              method: "DELETE",
              headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
            },
            env
          );

          expect(res.status).toBe(500);

          const stillActive = await db
            .prepare("SELECT status FROM token_allowlists WHERE id = ?")
            .bind(entryId)
            .first<{ status: string }>();
          expect(stillActive?.status).toBe("active");

          const retry = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist/${entryId}`,
            {
              method: "DELETE",
              headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
            },
            env
          );
          expect(retry.status).toBe(204);
          expect(removeFromListSpy).toHaveBeenCalledTimes(2);

          const revoked = await db
            .prepare("SELECT status FROM token_allowlists WHERE id = ?")
            .bind(entryId)
            .first<{ status: string }>();
          expect(revoked?.status).toBe("revoked");
        } finally {
          createOrgSignerSpy.mockRestore();
          removeFromListSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
        }
      });

      it("treats a timed-out removal as success when on-chain absence is confirmed", async () => {
        const db = getDb(env);
        await db
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(TEST_SOLANA_ADDRESSES.wallet3, tokenId)
          .run();
        const tokenService = new TokenService(db);
        const { entry } = await tokenService.addAllowlistEntry({
          tokenId,
          address: TEST_SOLANA_ADDRESSES.wallet1,
          addedBy: TEST_PROJECT_API_KEY.id,
          initialStatus: "pending",
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const removeFromListSpy = vi
          .spyOn(MosaicService.prototype, "removeFromList")
          .mockRejectedValueOnce(new Error("RPC confirmation timeout"));
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${tokenId}/allowlist/${entry.id}`,
            {
              method: "DELETE",
              headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
            },
            env
          );

          expect(res.status).toBe(204);
          const revoked = await db
            .prepare("SELECT status FROM token_allowlists WHERE id = ?")
            .bind(entry.id)
            .first<{ status: string }>();
          expect(revoked?.status).toBe("revoked");
        } finally {
          createOrgSignerSpy.mockRestore();
          removeFromListSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
        }
      });
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // Freeze/Unfreeze Tests
  // ═══════════════════════════════════════════════════════════════════════════

  describe.skipIf(isMockMode)("Freeze/Unfreeze Operations", () => {
    const seedFreezableToken = async (): Promise<string> => {
      const db = getDb(env);

      // Insert an active token with freeze capability
      await db
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, total_supply_cached, is_mintable, freeze_authority_enabled, allowlist_enabled, status, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Freezable Token', 'FRZ', 9, '0', 1, 1, 0, 'active', ?)`
        )
        .bind(
          TEST_ACTIVE_TOKEN.id,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_ACTIVE_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();

      return TEST_ACTIVE_TOKEN.id;
    };

    const mockResolvedTokenAccount = () =>
      vi.spyOn(MosaicSdk, "resolveTokenAccount").mockResolvedValue({
        tokenAccount: TEST_SOLANA_ADDRESSES.wallet2,
        isInitialized: true,
        isFrozen: false,
        balance: 0n,
        uiBalance: 0,
      } as Awaited<ReturnType<typeof MosaicSdk.resolveTokenAccount>>);

    describe("POST /v1/issuance/tokens/:tokenId/freeze", () => {
      it("freezes an account", async () => {
        const activeTokenId = await seedFreezableToken();
        mockResolvedTokenAccount();

        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/freeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              accountAddress: TEST_SOLANA_ADDRESSES.wallet1,
              reason: "Suspicious activity",
            }),
          },
          env
        );

        expect(res.status).toBe(201);
        const body = await res.json();
        expect(body.data.frozenAccount.id).toMatch(/^frz_/);
        expect(body.data.frozenAccount.accountAddress).toBe(TEST_SOLANA_ADDRESSES.wallet2);
        expect(body.data.frozenAccount.reason).toBe("Suspicious activity");
      });

      it("returns 400 for already frozen account", async () => {
        const activeTokenId = await seedFreezableToken();
        mockResolvedTokenAccount();

        // Freeze first
        await app.request(
          `/v1/issuance/tokens/${activeTokenId}/freeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ accountAddress: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        // Try to freeze again
        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/freeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ accountAddress: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        expect(res.status).toBe(400);
        const body = await res.json();
        expect(body.error.code).toBe("ACCOUNT_FROZEN");
      });

      it("returns a structured token-account error when the wallet does not hold this mint", async () => {
        const activeTokenId = await seedFreezableToken();
        mockResolvedTokenAccount();
        vi.mocked(MosaicSdk.resolveTokenAccount).mockResolvedValueOnce({
          tokenAccount: TEST_SOLANA_ADDRESSES.wallet2,
          isInitialized: false,
          isFrozen: true,
          balance: 0n,
          uiBalance: 0,
        } as Awaited<ReturnType<typeof MosaicSdk.resolveTokenAccount>>);

        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/freeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              accountAddress: TEST_SOLANA_ADDRESSES.wallet1,
            }),
          },
          env
        );

        expect(res.status).toBe(400);
        const body = (await res.json()) as {
          error: {
            code: string;
            message: string;
            details?: { field?: string; hint?: string };
          };
        };
        expect(body.error.code).toBe("TOKEN_ACCOUNT_NOT_FOUND");
        expect(body.error.message).toContain("wallet");
        expect(body.error.details?.field).toBe("accountAddress");
        expect(body.error.details?.hint).toContain("holds this token");
      });

      it("maps token-account parser failures to a structured wallet error", async () => {
        const activeTokenId = await seedFreezableToken();
        mockResolvedTokenAccount();
        vi.spyOn(MosaicService.prototype, "freezeAccount").mockRejectedValueOnce(
          new Error("Failed to parse token account data")
        );

        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/freeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              accountAddress: TEST_SOLANA_ADDRESSES.wallet1,
            }),
          },
          env
        );

        expect(res.status).toBe(400);
        const body = (await res.json()) as {
          error: {
            code: string;
            message: string;
            details?: { field?: string; hint?: string };
          };
        };
        expect(body.error.code).toBe("TOKEN_ACCOUNT_NOT_FOUND");
        expect(body.error.message).toContain("wallet");
        expect(body.error.details?.field).toBe("accountAddress");
        expect(body.error.details?.hint).toContain("matching token account");
      });

      it("can freeze an account again after it was unfrozen", async () => {
        const activeTokenId = await seedFreezableToken();
        const db = getDb(env);
        mockResolvedTokenAccount();

        const freezeSpy = vi.spyOn(MosaicService.prototype, "freezeAccount").mockResolvedValue({
          signature: "sig_freeze_refreeze",
          slot: 123n,
        });
        const thawSpy = vi.spyOn(MosaicService.prototype, "thawAccount").mockResolvedValue({
          signature: "sig_thaw_refreeze",
          slot: 124n,
        });

        try {
          const firstFreezeRes = await app.request(
            `/v1/issuance/tokens/${activeTokenId}/freeze`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                accountAddress: TEST_SOLANA_ADDRESSES.wallet1,
                reason: "Initial freeze",
              }),
            },
            env
          );

          expect(firstFreezeRes.status).toBe(201);
          const firstFreezeBody = await firstFreezeRes.json();
          const frozenRecordId = firstFreezeBody.data.frozenAccount.id as string;

          const unfreezeRes = await app.request(
            `/v1/issuance/tokens/${activeTokenId}/unfreeze`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({ accountAddress: TEST_SOLANA_ADDRESSES.wallet1 }),
            },
            env
          );

          expect(unfreezeRes.status).toBe(200);

          const secondFreezeRes = await app.request(
            `/v1/issuance/tokens/${activeTokenId}/freeze`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                accountAddress: TEST_SOLANA_ADDRESSES.wallet1,
                reason: "Frozen again",
              }),
            },
            env
          );

          expect(secondFreezeRes.status).toBe(201);
          const secondFreezeBody = await secondFreezeRes.json();
          expect(secondFreezeBody.data.frozenAccount.id).toBe(frozenRecordId);
          expect(secondFreezeBody.data.frozenAccount.reason).toBe("Frozen again");

          const storedRows = await db
            .prepare(
              `SELECT id, unfrozen_at, reason
               FROM frozen_accounts
               WHERE token_id = ? AND account_address = ?`
            )
            .bind(activeTokenId, TEST_SOLANA_ADDRESSES.wallet2)
            .all<{ id: string; unfrozen_at: string | null; reason: string | null }>();

          expect(storedRows.results).toHaveLength(1);
          expect(storedRows.results[0]?.id).toBe(frozenRecordId);
          expect(storedRows.results[0]?.unfrozen_at).toBeNull();
          expect(storedRows.results[0]?.reason).toBe("Frozen again");
        } finally {
          freezeSpy.mockRestore();
          thawSpy.mockRestore();
        }
      });
    });

    describe("POST /v1/issuance/tokens/:tokenId/unfreeze", () => {
      it("unfreezes an account", async () => {
        const activeTokenId = await seedFreezableToken();
        mockResolvedTokenAccount();

        // Freeze first
        await app.request(
          `/v1/issuance/tokens/${activeTokenId}/freeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ accountAddress: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        // Unfreeze
        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/unfreeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ accountAddress: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.frozenAccount.unfrozenAt).toBeDefined();
      });

      it("returns 400 for non-frozen account", async () => {
        const activeTokenId = await seedFreezableToken();
        mockResolvedTokenAccount();

        const res = await app.request(
          `/v1/issuance/tokens/${activeTokenId}/unfreeze`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({ accountAddress: TEST_SOLANA_ADDRESSES.wallet1 }),
          },
          env
        );

        expect(res.status).toBe(400);
        const body = await res.json();
        expect(body.error.code).toBe("ACCOUNT_NOT_FROZEN");
      });
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // Mint with Control List Tests
  // ═══════════════════════════════════════════════════════════════════════════

  describe("Mint with Control List Enforcement", () => {
    let allowlistTokenId: string;
    const blocklistTokenId = "tok_blocklist_token";

    const addBlocklistEntry = async (address: string) => {
      await app.request(
        `/v1/issuance/tokens/${blocklistTokenId}/allowlist`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ address }),
        },
        env
      );
    };

    beforeEach(async () => {
      const db = getDb(env);

      // Insert an active token that requires allowlist
      await db
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, total_supply_cached, is_mintable, freeze_authority_enabled, allowlist_enabled, status, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Allowlist Token', 'ALT', 9, '0', 1, 1, 1, 'active', ?)`
        )
        .bind(
          TEST_ALLOWLIST_TOKEN.id,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_ALLOWLIST_TOKEN.mintAddress,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();

      allowlistTokenId = TEST_ALLOWLIST_TOKEN.id;

      await db
        .prepare(
          `INSERT INTO issued_tokens (id, project_id, organization_id, mint_address, mint_authority, freeze_authority,
           name, symbol, decimals, template, total_supply_cached, is_mintable, freeze_authority_enabled, allowlist_enabled, status, created_by)
           VALUES (?, ?, ?, ?, ?, ?, 'Blocklist Token', 'BLT', 9, 'stablecoin', '0', 1, 1, 0, 'active', ?)`
        )
        .bind(
          blocklistTokenId,
          TEST_PROJECT.id,
          TEST_ORG.id,
          TEST_SOLANA_ADDRESSES.wallet3,
          TEST_ACTIVE_TOKEN.mintAuthority,
          TEST_ACTIVE_TOKEN.freezeAuthority,
          TEST_PROJECT_API_KEY.id
        )
        .run();
    });

    // Legacy fallback path for allowlist tokens with no ablListAddress: the handler
    // still asserts against the DB allowlist. The on-chain auto-add path is covered
    // by the "on-chain allowlist auto-add on mint" describe below.
    it("rejects mint to non-allowlisted address (legacy tokens with no ablListAddress)", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${allowlistTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet2, // Not on allowlist
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("NOT_ON_TOKEN_ALLOWLIST");
    });

    it("rejects execute mint to non-allowlisted address (legacy tokens with no ablListAddress)", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${allowlistTokenId}/mint`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("NOT_ON_TOKEN_ALLOWLIST");
    });

    // Skip in mock mode - Mosaic SDK requires RPC to fetch mint details
    it.skipIf(isMockMode)("allows mint to allowlisted address", async () => {
      // Add to allowlist first
      await app.request(
        `/v1/issuance/tokens/${allowlistTokenId}/allowlist`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({ address: TEST_SOLANA_ADDRESSES.wallet1 }),
        },
        env
      );

      // Now mint should work
      const res = await app.request(
        `/v1/issuance/tokens/${allowlistTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet1,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(200);
    });

    // The execute route may auto-add a destination to an on-chain ABL after
    // policy enforcement. The prepare route is deliberately read-only and only
    // succeeds when the destination is already on-chain.
    describe("on-chain allowlist auto-add on mint", () => {
      const ablList = TEST_SOLANA_ADDRESSES.wallet3;
      const signerAddress = TEST_SOLANA_ADDRESSES.wallet2;
      const freshDestination = TEST_SOLANA_ADDRESSES.wallet1;

      const mockPreparedMint = {
        serializedTx: "ZmFrZS1zZXJpYWxpemVkLXR4",
        blockhash: "11111111111111111111111111111111",
        lastValidBlockHeight: 0n,
        requiredSigners: [],
        tokenAccount: freshDestination,
      };

      const mockMintResult = {
        signature: "5testSigHOO469AutoAddOnMint",
        slot: 100n,
        tokenAccount: freshDestination,
      };

      const seedAblListAddress = async () => {
        await getDb(env)
          .prepare("UPDATE issued_tokens SET abl_list_address = ? WHERE id = ?")
          .bind(ablList, allowlistTokenId)
          .run();
      };

      it("rejects prepare mint without mutating an absent on-chain allowlist entry", async () => {
        await seedAblListAddress();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockResolvedValueOnce(undefined as never);
        const prepareMintToSpy = vi
          .spyOn(MosaicService.prototype, "prepareMintTo")
          .mockResolvedValueOnce(mockPreparedMint as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint/prepare`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(403);
          const body = (await res.json()) as { error: { code: string } };
          expect(body.error.code).toBe("NOT_ON_TOKEN_ALLOWLIST");
          expect(addToListSpy).not.toHaveBeenCalled();
          expect(prepareMintToSpy).not.toHaveBeenCalled();

          const entry = await getDb(env)
            .prepare(
              "SELECT id FROM token_allowlists WHERE token_id = ? AND address = ? AND status = 'active'"
            )
            .bind(allowlistTokenId, freshDestination)
            .first<{ id: string }>();
          expect(entry).toBeNull();
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          prepareMintToSpy.mockRestore();
        }
      });

      it("prepares for an existing on-chain entry without mutating the DB mirror", async () => {
        await seedAblListAddress();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockResolvedValueOnce(undefined as never);
        const prepareMintToSpy = vi
          .spyOn(MosaicService.prototype, "prepareMintTo")
          .mockResolvedValueOnce(mockPreparedMint as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint/prepare`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(addToListSpy).not.toHaveBeenCalled();
          expect(prepareMintToSpy).toHaveBeenCalledTimes(1);

          const entry = await getDb(env)
            .prepare(
              "SELECT id FROM token_allowlists WHERE token_id = ? AND address = ? AND status = 'active'"
            )
            .bind(allowlistTokenId, freshDestination)
            .first<{ id: string }>();
          expect(entry).toBeNull();

          const body = (await res.json()) as { data: { transaction: { id: string } } };
          const transactionId = body.data.transaction.id;
          const audit = await getDb(env)
            .prepare(
              `SELECT metadata FROM audit_logs
               WHERE action = 'mint' AND resource_type = 'token_transaction'
                 AND resource_id = ?
               LIMIT 1`
            )
            .bind(transactionId)
            .first<{ metadata: string }>();
          const meta = JSON.parse(audit?.metadata ?? "{}") as {
            mode: string;
            addedToAllowlist: boolean;
          };
          expect(meta.mode).toBe("prepare");
          expect(meta.addedToAllowlist).toBe(false);
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          prepareMintToSpy.mockRestore();
        }
      });

      it("re-asserts the DB row after a successful on-chain add when the original insert was not ours", async () => {
        await seedAblListAddress();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockResolvedValueOnce(undefined as never);
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockResolvedValueOnce(mockMintResult as never);

        // First call: simulate a parallel request having beaten us to the INSERT
        // — we don't own the row. Second call (the re-assert) succeeds, modeling
        // the race where the parallel owner hard-deleted its row between our
        // insert attempt and now.
        const addAllowlistEntryStrictSpy = vi
          .spyOn(TokenService.prototype, "addAllowlistEntryStrict")
          .mockRejectedValueOnce(new Error("ADDRESS_ALREADY_ALLOWLISTED"))
          .mockResolvedValueOnce({
            id: "tal_reasserted_race",
            tokenId: allowlistTokenId,
            address: freshDestination,
            label: null,
            status: "active",
            addedBy: "tester",
            createdAt: new Date().toISOString(),
            revokedAt: null,
          } as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(addToListSpy).toHaveBeenCalledTimes(1);
          expect(addAllowlistEntryStrictSpy).toHaveBeenCalledTimes(2);
          expect(mintToSpy).toHaveBeenCalledTimes(1);
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          mintToSpy.mockRestore();
          addAllowlistEntryStrictSpy.mockRestore();
        }
      });

      const storedSupply = (tokenId: string) =>
        getDb(env)
          .prepare("SELECT total_supply_cached FROM issued_tokens WHERE id = ?")
          .bind(tokenId)
          .first<{ total_supply_cached: string }>();

      const latestMintTransaction = (tokenId: string) =>
        getDb(env)
          .prepare(
            "SELECT status FROM issuance_transactions WHERE token_id = ? AND type = 'mint' ORDER BY created_at DESC LIMIT 1"
          )
          .bind(tokenId)
          .first<{ status: string }>();

      // The handler's own cap check reads a cached total, which two concurrent
      // mints — or a concurrent cap change — can both pass. The reservation is a
      // conditional UPDATE on the token row, so it holds even when the process
      // read a cap that is no longer there. Stubbing `getToken` to return a
      // generous cap is that stale read, made deterministic.
      it("enforces the cap in the database even when the request read a stale one", async () => {
        await seedAblListAddress();
        await getDb(env)
          .prepare(
            "UPDATE issued_tokens SET max_supply = '500000000000', total_supply_cached = '400000000000' WHERE id = ?"
          )
          .bind(allowlistTokenId)
          .run();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);
        // Stands in for the real submit path: run the caller's pre-submit gate, then
        // submit. The gate is where the cap is enforced, so `submitted` staying false
        // is the assertion that a refused cap costs no transaction.
        let submitted = false;
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockImplementation(async (_options, onBeforeSubmit) => {
            await onBeforeSubmit?.();
            submitted = true;
            return mockMintResult as never;
          });

        const originalGetToken = TokenService.prototype.getToken;
        const getTokenSpy = vi
          .spyOn(TokenService.prototype, "getToken")
          .mockImplementation(async function (this: TokenService, params) {
            const token = await originalGetToken.call(this, params);
            return token ? { ...token, maxSupply: "100000" } : token;
          });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "200" },
              }),
            },
            env
          );

          expect(res.status).toBe(400);
          const body = (await res.json()) as { error: { code: string } };
          expect(body.error.code).toBe("MAX_SUPPLY_EXCEEDED");
          // The gate refused before submission, so there is no settled mint to
          // reconcile and no reservation left behind.
          expect(submitted).toBe(false);
          expect((await storedSupply(allowlistTokenId))?.total_supply_cached).toBe("400000000000");
          expect((await latestMintTransaction(allowlistTokenId))?.status).toBe("failed");
        } finally {
          getTokenSpy.mockRestore();
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      it("keeps the reservation when a submitted mint fails", async () => {
        await seedAblListAddress();
        await getDb(env)
          .prepare(
            "UPDATE issued_tokens SET max_supply = '1000000000000', total_supply_cached = '100000000000' WHERE id = ?"
          )
          .bind(allowlistTokenId)
          .run();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);
        // Submitted, then lost during confirmation: the gate ran, so the transaction
        // is out there and may land whatever this request reports.
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockImplementation(async (_options, onBeforeSubmit) => {
            await onBeforeSubmit?.();
            throw new Error("transaction was not confirmed in time");
          });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "200" },
              }),
            },
            env
          );

          expect(res.status).toBeGreaterThanOrEqual(400);
          expect(mintToSpy).toHaveBeenCalledTimes(1);
          // Nothing past submission can prove the mint did not land. So the
          // reservation stands (100 + 200 recorded) and `POST /supply/refresh`
          // reconciles it once the transaction cannot land; handing the headroom back
          // here is what let two mints exceed the cap.
          expect((await storedSupply(allowlistTokenId))?.total_supply_cached).toBe("300000000000");
          // Submission is ambiguous after the point-of-no-return hook. Keep the
          // transaction pending and its durable audit intent unresolved until
          // supply reconciliation proves whether the mint landed.
          expect((await latestMintTransaction(allowlistTokenId))?.status).toBe("pending");
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      it("reserves nothing when the mint fails before it is submitted", async () => {
        await seedAblListAddress();
        await getDb(env)
          .prepare(
            "UPDATE issued_tokens SET max_supply = '1000000000000', total_supply_cached = '100000000000' WHERE id = ?"
          )
          .bind(allowlistTokenId)
          .run();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);
        // Building, resolving the token account and signing all happen before the
        // gate, so failing there means no transaction exists to account for.
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockRejectedValueOnce(new Error("failed to build mint transaction") as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "200" },
              }),
            },
            env
          );

          expect(res.status).toBeGreaterThanOrEqual(400);
          // Untouched: holding a reservation through a failure that never reached the
          // cluster would refuse later legitimate mints with MAX_SUPPLY_EXCEEDED until
          // someone refreshed the supply by hand.
          expect((await storedSupply(allowlistTokenId))?.total_supply_cached).toBe("100000000000");
          expect((await latestMintTransaction(allowlistTokenId))?.status).toBe("failed");
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      it("auto-adds destination to on-chain allowlist on execute mint", async () => {
        await seedAblListAddress();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockResolvedValueOnce(undefined as never);
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockResolvedValueOnce(mockMintResult as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(addToListSpy).toHaveBeenCalledTimes(1);
          expect(addToListSpy).toHaveBeenCalledWith({
            list: ablList,
            wallet: freshDestination,
          });
          expect(mintToSpy).toHaveBeenCalledTimes(1);

          const entry = await getDb(env)
            .prepare(
              "SELECT id FROM token_allowlists WHERE token_id = ? AND address = ? AND status = 'active'"
            )
            .bind(allowlistTokenId, freshDestination)
            .first<{ id: string }>();
          expect(entry?.id).toMatch(/^tal_/);

          const body = (await res.json()) as { data: { transaction: { id: string } } };
          const transactionId = body.data.transaction.id;
          const audit = await getDb(env)
            .prepare(
              `SELECT metadata FROM audit_logs
               WHERE action = 'mint' AND resource_type = 'token_transaction'
                 AND resource_id = ?
               LIMIT 1`
            )
            .bind(transactionId)
            .first<{ metadata: string }>();
          const meta = JSON.parse(audit?.metadata ?? "{}") as {
            mode: string;
            addedToAllowlist: boolean;
          };
          expect(meta.mode).toBe("execute");
          expect(meta.addedToAllowlist).toBe(true);
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      it("repairs settled mint bookkeeping from durable audit evidence on replay", async () => {
        await seedAblListAddress();

        const idempotencyKey = `idem_${crypto.randomUUID()}`;
        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValue(true);
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockImplementationOnce(async (_options, onBeforeSubmit) => {
            await onBeforeSubmit?.();
            return mockMintResult as never;
          });
        const updateTransactionSpy = vi
          .spyOn(TokenService.prototype, "updateTransaction")
          .mockRejectedValueOnce(new Error("transaction bookkeeping unavailable"));

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
                "Idempotency-Key": idempotencyKey,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(mintToSpy).toHaveBeenCalledTimes(1);
          const firstBody = (await res.json()) as {
            data: { transaction: { status: string; signature: string | null } };
          };
          expect(firstBody.data.transaction).toMatchObject({
            status: "confirmed",
            signature: mockMintResult.signature,
          });

          const db = getDb(env);
          const transaction = await db
            .prepare(
              "SELECT id, status FROM issuance_transactions WHERE idempotency_key = ? LIMIT 1"
            )
            .bind(idempotencyKey)
            .first<{ id: string; status: string }>();
          expect(transaction?.status).toBe("pending");

          const intent = await db
            .prepare(
              `SELECT resource_id FROM audit_logs
               WHERE action = 'maintenance' AND resource_type = 'audit_ledger'
                 AND metadata::jsonb #>> '{target,resourceId}' = ?
               ORDER BY ledger_sequence DESC LIMIT 1`
            )
            .bind(transaction?.id)
            .first<{ resource_id: string }>();
          expect(intent?.resource_id).toMatch(/^aint_/);

          const outcome = await db
            .prepare(
              `SELECT id, status FROM audit_logs
               WHERE metadata::jsonb ->> 'auditIntentId' = ?
               LIMIT 1`
            )
            .bind(intent?.resource_id)
            .first<{ id: string; status: string }>();
          expect(outcome).toMatchObject({ status: "success" });

          const replay = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
                "Idempotency-Key": idempotencyKey,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );
          expect(replay.status).toBe(200);
          const replayBody = (await replay.json()) as {
            data: { transaction: { status: string; signature: string | null } };
          };
          expect(replayBody.data.transaction).toMatchObject({
            status: "confirmed",
            signature: mockMintResult.signature,
          });
          expect(mintToSpy).toHaveBeenCalledTimes(1);

          const repaired = await db
            .prepare(
              "SELECT status, signature FROM issuance_transactions WHERE idempotency_key = ? LIMIT 1"
            )
            .bind(idempotencyKey)
            .first<{ status: string; signature: string | null }>();
          expect(repaired).toMatchObject({
            status: "confirmed",
            signature: mockMintResult.signature,
          });
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          mintToSpy.mockRestore();
          updateTransactionSpy.mockRestore();
        }
      });

      it("skips on-chain allowlist sync on prepare mint when destination already on list", async () => {
        await seedAblListAddress();

        // Pre-insert the destination directly into token_allowlists and mock
        // the on-chain ABL membership check to return true — the helper treats
        // the on-chain list as the source of truth and only skips when both
        // sides agree.
        const tokenService = new TokenService(getDb(env));
        await tokenService.addAllowlistEntry({
          tokenId: allowlistTokenId,
          address: freshDestination,
          addedBy: TEST_PROJECT_API_KEY.id,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockResolvedValueOnce(undefined as never);
        const prepareMintToSpy = vi
          .spyOn(MosaicService.prototype, "prepareMintTo")
          .mockResolvedValueOnce(mockPreparedMint as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint/prepare`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(addToListSpy).not.toHaveBeenCalled();
          expect(prepareMintToSpy).toHaveBeenCalledTimes(1);

          const body = (await res.json()) as { data: { transaction: { id: string } } };
          const transactionId = body.data.transaction.id;
          const audit = await getDb(env)
            .prepare(
              `SELECT metadata FROM audit_logs
               WHERE action = 'mint' AND resource_type = 'token_transaction'
                 AND resource_id = ?
               LIMIT 1`
            )
            .bind(transactionId)
            .first<{ metadata: string }>();
          const meta = JSON.parse(audit?.metadata ?? "{}") as {
            mode: string;
            addedToAllowlist: boolean;
          };
          expect(meta.mode).toBe("prepare");
          expect(meta.addedToAllowlist).toBe(false);
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          prepareMintToSpy.mockRestore();
        }
      });

      it("skips on-chain allowlist sync on execute mint when destination already on list", async () => {
        await seedAblListAddress();

        const tokenService = new TokenService(getDb(env));
        await tokenService.addAllowlistEntry({
          tokenId: allowlistTokenId,
          address: freshDestination,
          addedBy: TEST_PROJECT_API_KEY.id,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(true);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockResolvedValueOnce(undefined as never);
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockResolvedValueOnce(mockMintResult as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(addToListSpy).not.toHaveBeenCalled();
          expect(mintToSpy).toHaveBeenCalledTimes(1);

          const body = (await res.json()) as { data: { transaction: { id: string } } };
          const transactionId = body.data.transaction.id;
          const audit = await getDb(env)
            .prepare(
              `SELECT metadata FROM audit_logs
               WHERE action = 'mint' AND resource_type = 'token_transaction'
                 AND resource_id = ?
               LIMIT 1`
            )
            .bind(transactionId)
            .first<{ metadata: string }>();
          const meta = JSON.parse(audit?.metadata ?? "{}") as {
            mode: string;
            addedToAllowlist: boolean;
          };
          expect(meta.mode).toBe("execute");
          expect(meta.addedToAllowlist).toBe(false);
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      it("rejects prepare mint when destination is a revoked allowlist entry", async () => {
        await seedAblListAddress();

        // Operator previously allowlisted and then revoked this address.
        const tokenService = new TokenService(getDb(env));
        const { entry } = await tokenService.addAllowlistEntry({
          tokenId: allowlistTokenId,
          address: freshDestination,
          addedBy: TEST_PROJECT_API_KEY.id,
        });
        await tokenService.revokeAllowlistEntry(entry.id);

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi.spyOn(MosaicService.prototype, "isWalletOnList");
        const addToListSpy = vi.spyOn(MosaicService.prototype, "addToList");
        const prepareMintToSpy = vi.spyOn(MosaicService.prototype, "prepareMintTo");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint/prepare`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(403);
          const body = (await res.json()) as { error: { code: string } };
          expect(body.error.code).toBe("DESTINATION_REVOKED");

          // No on-chain or DB mutation happens — entry stays revoked, no
          // sync attempts to silently reactivate it.
          expect(isWalletOnListSpy).not.toHaveBeenCalled();
          expect(addToListSpy).not.toHaveBeenCalled();
          expect(prepareMintToSpy).not.toHaveBeenCalled();

          const row = await getDb(env)
            .prepare("SELECT status FROM token_allowlists WHERE id = ?")
            .bind(entry.id)
            .first<{ status: string }>();
          expect(row?.status).toBe("revoked");
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          prepareMintToSpy.mockRestore();
        }
      });

      it("rejects execute mint when destination is a revoked allowlist entry", async () => {
        await seedAblListAddress();

        const tokenService = new TokenService(getDb(env));
        const { entry } = await tokenService.addAllowlistEntry({
          tokenId: allowlistTokenId,
          address: freshDestination,
          addedBy: TEST_PROJECT_API_KEY.id,
        });
        await tokenService.revokeAllowlistEntry(entry.id);

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        const isWalletOnListSpy = vi.spyOn(MosaicService.prototype, "isWalletOnList");
        const addToListSpy = vi.spyOn(MosaicService.prototype, "addToList");
        const mintToSpy = vi.spyOn(MosaicService.prototype, "mintTo");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(403);
          const body = (await res.json()) as { error: { code: string } };
          expect(body.error.code).toBe("DESTINATION_REVOKED");

          expect(isWalletOnListSpy).not.toHaveBeenCalled();
          expect(addToListSpy).not.toHaveBeenCalled();
          expect(mintToSpy).not.toHaveBeenCalled();

          const row = await getDb(env)
            .prepare("SELECT status FROM token_allowlists WHERE id = ?")
            .bind(entry.id)
            .first<{ status: string }>();
          expect(row?.status).toBe("revoked");
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      it("rejects execute mint to revoked destination without poisoning the idempotency slot", async () => {
        await seedAblListAddress();

        const tokenService = new TokenService(getDb(env));
        const { entry } = await tokenService.addAllowlistEntry({
          tokenId: allowlistTokenId,
          address: freshDestination,
          addedBy: TEST_PROJECT_API_KEY.id,
        });
        await tokenService.revokeAllowlistEntry(entry.id);

        const idempotencyKey = `idem_${crypto.randomUUID()}`;

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: signerAddress } as never);
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockResolvedValue(mockMintResult as never);

        try {
          const firstRes = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
                "Idempotency-Key": idempotencyKey,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(firstRes.status).toBe(403);
          const firstBody = (await firstRes.json()) as { error: { code: string } };
          expect(firstBody.error.code).toBe("DESTINATION_REVOKED");

          // The revoke check must run BEFORE createTransaction, so no
          // token_transactions row should exist under this idempotency key.
          // Otherwise the next retry replays a stale failed row instead of
          // re-evaluating the (now possibly re-added) destination.
          const poisonedRow = await getDb(env)
            .prepare("SELECT id, status FROM issuance_transactions WHERE idempotency_key = ?")
            .bind(idempotencyKey)
            .first<{ id: string; status: string }>();
          expect(poisonedRow).toBeNull();

          // Operator re-adds the destination; a retry with the same idempotency
          // key should now succeed instead of replaying the prior failure.
          await tokenService.addAllowlistEntry({
            tokenId: allowlistTokenId,
            address: freshDestination,
            addedBy: TEST_PROJECT_API_KEY.id,
          });

          const isWalletOnListSpy = vi
            .spyOn(MosaicService.prototype, "isWalletOnList")
            .mockResolvedValueOnce(true);
          const addToListSpy = vi.spyOn(MosaicService.prototype, "addToList");

          try {
            const retryRes = await app.request(
              `/v1/issuance/tokens/${allowlistTokenId}/mint`,
              {
                method: "POST",
                headers: {
                  "Content-Type": "application/json",
                  Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
                  "Idempotency-Key": idempotencyKey,
                },
                body: JSON.stringify({
                  mint: { destination: freshDestination, amount: "1" },
                }),
              },
              env
            );

            expect(retryRes.status).toBe(200);
            expect(addToListSpy).not.toHaveBeenCalled();
            expect(mintToSpy).toHaveBeenCalledTimes(1);
          } finally {
            isWalletOnListSpy.mockRestore();
            addToListSpy.mockRestore();
          }
        } finally {
          createOrgSignerSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      it("rolls back the DB row when on-chain add fails and membership is not confirmed, leaving the address mintable on retry", async () => {
        await seedAblListAddress();

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: signerAddress } as never);
        // Initial check (no wallet on-chain) and recheck after the failure
        // (still not on-chain) → true rollback branch, not TOCTOU recovery.
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false)
          .mockResolvedValueOnce(false)
          // Retry: initial check on the second attempt also sees the wallet absent.
          .mockResolvedValueOnce(false);
        const addToListSpy = vi
          .spyOn(MosaicService.prototype, "addToList")
          .mockRejectedValueOnce(new Error("RPC confirmation timeout"))
          .mockResolvedValueOnce(undefined as never);
        const mintToSpy = vi
          .spyOn(MosaicService.prototype, "mintTo")
          .mockResolvedValueOnce(mockMintResult as never);

        try {
          const failedRes = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(failedRes.status).toBeGreaterThanOrEqual(500);

          // Rollback must hard-delete the row, not soft-revoke it — otherwise
          // the revoked-status guard blocks every subsequent mint to the same
          // address with DESTINATION_REVOKED even though no operator revoked.
          const rowAfterFailure = await getDb(env)
            .prepare("SELECT id, status FROM token_allowlists WHERE token_id = ? AND address = ?")
            .bind(allowlistTokenId, freshDestination)
            .first<{ id: string; status: string }>();
          expect(rowAfterFailure).toBeNull();

          // Retry on the same address with the on-chain add succeeding must
          // not be blocked by a stale "revoked" row from the prior rollback.
          const retryRes = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(retryRes.status).toBe(200);
          expect(addToListSpy).toHaveBeenCalledTimes(2);

          const rowAfterRetry = await getDb(env)
            .prepare("SELECT id, status FROM token_allowlists WHERE token_id = ? AND address = ?")
            .bind(allowlistTokenId, freshDestination)
            .first<{ id: string; status: string }>();
          expect(rowAfterRetry?.status).toBe("active");
        } finally {
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });

      // Race window: the top-level status check returns 'active' (stale read),
      // but the actual DB row is 'revoked' by the time the insert runs. Without
      // the strict insert variant, addAllowlistEntry would silently reactivate
      // the row, undoing the operator's KYC/compliance revocation.
      it("does not reactivate a concurrently-revoked entry when the top-level status read is stale", async () => {
        await seedAblListAddress();

        const tokenService = new TokenService(getDb(env));
        const { entry } = await tokenService.addAllowlistEntry({
          tokenId: allowlistTokenId,
          address: freshDestination,
          addedBy: TEST_PROJECT_API_KEY.id,
        });
        await tokenService.revokeAllowlistEntry(entry.id);

        // Simulate the race: top-level check sees stale 'active' status, but
        // by the time the insert path runs, the row is actually 'revoked'.
        const statusSpy = vi
          .spyOn(TokenService.prototype, "getAllowlistEntryStatusByAddress")
          .mockResolvedValueOnce("active");
        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: signerAddress } as never);
        // Force the not-on-chain branch so we exercise the strict insert path.
        const isWalletOnListSpy = vi
          .spyOn(MosaicService.prototype, "isWalletOnList")
          .mockResolvedValueOnce(false);
        const addToListSpy = vi.spyOn(MosaicService.prototype, "addToList");
        const mintToSpy = vi.spyOn(MosaicService.prototype, "mintTo");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${allowlistTokenId}/mint`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                mint: { destination: freshDestination, amount: "1" },
              }),
            },
            env
          );

          expect(res.status).toBe(403);
          const body = (await res.json()) as { error: { code: string } };
          expect(body.error.code).toBe("DESTINATION_REVOKED");

          // The DB row stays 'revoked' — not silently flipped to 'active' by
          // a reactivating insert. This is the regression guard.
          const row = await getDb(env)
            .prepare("SELECT status FROM token_allowlists WHERE id = ?")
            .bind(entry.id)
            .first<{ status: string }>();
          expect(row?.status).toBe("revoked");

          // The mint must not have proceeded any further on-chain.
          expect(addToListSpy).not.toHaveBeenCalled();
          expect(mintToSpy).not.toHaveBeenCalled();
        } finally {
          statusSpy.mockRestore();
          createOrgSignerSpy.mockRestore();
          isWalletOnListSpy.mockRestore();
          addToListSpy.mockRestore();
          mintToSpy.mockRestore();
        }
      });
    });

    it("rejects mint to denylisted address", async () => {
      await addBlocklistEntry(TEST_SOLANA_ADDRESSES.wallet2);

      const res = await app.request(
        `/v1/issuance/tokens/${blocklistTokenId}/mint/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("ON_TOKEN_BLOCKLIST");
    });

    it("rejects execute mint to denylisted address", async () => {
      await addBlocklistEntry(TEST_SOLANA_ADDRESSES.wallet2);

      const res = await app.request(
        `/v1/issuance/tokens/${blocklistTokenId}/mint`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            mint: {
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("ON_TOKEN_BLOCKLIST");
    });

    it("rejects prepare seize to denylisted destination", async () => {
      await addBlocklistEntry(TEST_SOLANA_ADDRESSES.wallet2);

      const res = await app.request(
        `/v1/issuance/tokens/${blocklistTokenId}/seize/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            seize: {
              source: TEST_SOLANA_ADDRESSES.wallet1,
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("ON_TOKEN_BLOCKLIST");
    });

    it("rejects execute seize to denylisted destination", async () => {
      await addBlocklistEntry(TEST_SOLANA_ADDRESSES.wallet2);

      const res = await app.request(
        `/v1/issuance/tokens/${blocklistTokenId}/seize`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            seize: {
              source: TEST_SOLANA_ADDRESSES.wallet1,
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("ON_TOKEN_BLOCKLIST");
    });

    it("rejects prepare seize to non-allowlisted destination", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${allowlistTokenId}/seize/prepare`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            seize: {
              source: TEST_SOLANA_ADDRESSES.wallet1,
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("NOT_ON_TOKEN_ALLOWLIST");
    });

    it("rejects execute seize to non-allowlisted destination", async () => {
      const res = await app.request(
        `/v1/issuance/tokens/${allowlistTokenId}/seize`,
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            seize: {
              source: TEST_SOLANA_ADDRESSES.wallet1,
              destination: TEST_SOLANA_ADDRESSES.wallet2,
              amount: "1",
            },
          }),
        },
        env
      );

      expect(res.status).toBe(403);
      const body = await res.json();
      expect(body.error.code).toBe("NOT_ON_TOKEN_ALLOWLIST");
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // Template Tests
  // ═══════════════════════════════════════════════════════════════════════════

  describe("Templates API", () => {
    describe("GET /v1/issuance/templates", () => {
      it("lists publicly exposed templates", async () => {
        const res = await app.request(
          "/v1/issuance/templates",
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.templates).toBeInstanceOf(Array);
        expect(body.data.templates.length).toBe(3);

        // Verify template structure
        const stablecoin = body.data.templates.find((t: { id: string }) => t.id === "stablecoin");
        expect(stablecoin).toBeDefined();
        expect(stablecoin.name).toBe("Stablecoin");
        expect(stablecoin.maxDecimals).toBe(18);
        const tokenized = body.data.templates.find(
          (t: { id: string }) => t.id === "tokenized-security"
        );
        expect(tokenized).toBeDefined();
        expect(tokenized.maxDecimals).toBe(18);
        const custom = body.data.templates.find((t: { id: string }) => t.id === "custom");
        expect(custom).toBeDefined();
        const arcade = body.data.templates.find((t: { id: string }) => t.id === "arcade");
        expect(arcade).toBeUndefined();
      });
    });

    describe("GET /v1/issuance/templates/:templateId", () => {
      it("returns stablecoin template", async () => {
        const res = await app.request(
          "/v1/issuance/templates/stablecoin",
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.template.id).toBe("stablecoin");
        expect(body.data.template.name).toBe("Stablecoin");
        expect(body.data.template.maxDecimals).toBe(18);
      });

      it("returns tokenized security template", async () => {
        const res = await app.request(
          "/v1/issuance/templates/tokenized-security",
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body.data.template.id).toBe("tokenized-security");
        expect(body.data.template.name).toBe("Tokenized Security");
        expect(body.data.template.maxDecimals).toBe(18);
      });

      it("does not return arcade template", async () => {
        const res = await app.request(
          "/v1/issuance/templates/arcade",
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );

        expect(res.status).toBe(404);
      });

      it("returns 404 for unknown template", async () => {
        const res = await app.request(
          "/v1/issuance/templates/nonexistent",
          {
            headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
          },
          env
        );

        expect(res.status).toBe(404);
      });
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // Template-Based Token Creation Tests
  // ═══════════════════════════════════════════════════════════════════════════

  describe("Template-based Token Creation", () => {
    it("creates token with arcade template", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Arcade Token",
            symbol: "ARCADE",
            template: "arcade",
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.decimals).toBe(0); // Arcade default
      expect(body.data.token.requiresAllowlist).toBe(false);
      expect(body.data.token.extensions?.defaultAccountState).toBe("initialized");
    });

    it("creates token with rwa template", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Real Estate Token",
            symbol: "RWA",
            template: "rwa",
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.decimals).toBe(8); // RWA default
      expect(body.data.token.requiresAllowlist).toBe(true);
      expect(body.data.token.extensions?.defaultAccountState).toBe("frozen");
    });

    it("creates token with decimal override", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Custom Decimals Arcade",
            symbol: "CDA",
            template: "arcade",
            decimals: 6, // Override arcade's 0 decimals
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.decimals).toBe(6);
    });

    it("creates stablecoin with mixed-case symbol and decimal override", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Custom Stablecoin Decimals",
            symbol: "Usd7",
            template: "stablecoin",
            decimals: 7,
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.template).toBe("stablecoin");
      expect(body.data.token.symbol).toBe("Usd7");
      expect(body.data.token.decimals).toBe(7);
    });

    it("creates tokenized security with decimal override", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Custom Security Decimals",
            symbol: "Sec12",
            template: "tokenized-security",
            decimals: 12,
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.template).toBe("tokenized-security");
      expect(body.data.token.decimals).toBe(12);
      expect(body.data.token.requiresAllowlist).toBe(true);
    });

    it("creates token with extension override", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Token with Fees",
            symbol: "FEE",
            template: "custom",
            overrides: {
              extensions: {
                transferFee: {
                  basisPoints: 50,
                  maxFee: "0.5",
                },
              },
            },
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.extensions?.transferFee).toBeDefined();
      expect(body.data.token.extensions?.transferFee?.basisPoints).toBe(50);
    });

    it("creates token with advanced extension overrides", async () => {
      const extensionAuthority = TEST_SOLANA_ADDRESSES.wallet1;

      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Advanced Extensions",
            symbol: "ADV",
            template: "custom",
            overrides: {
              extensions: {
                pausable: {
                  authority: extensionAuthority,
                },
                scaledUiAmount: {
                  multiplier: 2,
                  newMultiplier: 3,
                  newMultiplierEffectiveTimestamp: 1735689600,
                },
                transferHook: {
                  programId: extensionAuthority,
                  authority: extensionAuthority,
                },
              },
            },
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.extensions?.pausable?.authority).toBe(extensionAuthority);
      expect(body.data.token.extensions?.scaledUiAmount?.multiplier).toBe(2);
      expect(body.data.token.extensions?.transferHook?.programId).toBe(extensionAuthority);
    });

    it("creates token with allowlist override", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Allowlisted Arcade",
            symbol: "ALLARC",
            template: "arcade",
            overrides: {
              requiresAllowlist: true, // Arcade allows this override
            },
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.requiresAllowlist).toBe(true);
    });

    it("allows enabling allowlist for stablecoin", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Invalid Stablecoin",
            symbol: "INVSC",
            template: "stablecoin",
            overrides: {
              requiresAllowlist: true, // Stablecoin allows allowlist override
            },
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.requiresAllowlist).toBe(true);
      expect(body.data.token.extensions?.defaultAccountState).toBe("frozen");
    });

    it("allows tokenized-security to switch to denylist mode", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Security Denylist Token",
            symbol: "SDLT",
            template: "tokenized-security",
            overrides: {
              requiresAllowlist: false,
            },
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.requiresAllowlist).toBe(false);
      expect(body.data.token.extensions?.defaultAccountState).toBe("initialized");
    });

    it("rejects disabling required extension for template", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Invalid Arcade",
            symbol: "INVARC",
            template: "arcade",
            overrides: {
              extensions: {
                permanentDelegate: false,
              },
            },
          }),
        },
        env
      );

      expect(res.status).toBe(400);
      const body = await res.json();
      expect(body.error.details?.errors).toBeInstanceOf(Array);
      expect(
        body.error.details?.errors.some((e: { code: string }) => e.code === "EXTENSION_NOT_ALLOWED")
      ).toBe(true);
    });

    it("creates token with custom template overrides", async () => {
      const res = await app.request(
        "/v1/issuance/tokens",
        {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
          },
          body: JSON.stringify({
            name: "Legacy Token",
            symbol: "LEGACY",
            template: "custom",
            overrides: {
              extensions: {
                defaultAccountState: "frozen",
              },
            },
            requiresAllowlist: true,
          }),
        },
        env
      );

      expect(res.status).toBe(201);
      const body = await res.json();
      expect(body.data.token.decimals).toBe(9); // Custom template default
      expect(body.data.token.requiresAllowlist).toBe(true);
      expect(body.data.token.extensions?.defaultAccountState).toBe("frozen");
    });
  });

  // ═══════════════════════════════════════════════════════════════════════════
  // SDP-hosted Metadata (HOO-466)
  // ═══════════════════════════════════════════════════════════════════════════

  describe("SDP-hosted token metadata", () => {
    // app.request with a bare path builds requests against http://localhost, so
    // the request-derived origin the deploy handlers compute is deterministic.
    const expectedMetadataUrl = (tokenId: string) =>
      `http://localhost/v1/issuance/tokens/${tokenId}/metadata.json`;

    const mockDeployResult = {
      mint: TEST_SOLANA_ADDRESSES.mint,
      signature: "5testSigHOO466Deploy",
      slot: 100n,
      listAddress: undefined,
    };

    describe("POST /v1/issuance/tokens/:tokenId/deploy", () => {
      it("falls back to the SDP-hosted metadata URL when the token has no uri", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_uri_default",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockResolvedValueOnce(mockDeployResult as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(createTokenSpy).toHaveBeenCalledWith(
            expect.objectContaining({
              metadata: expect.objectContaining({ uri: expectedMetadataUrl(token.id) }),
            })
          );
        } finally {
          createOrgSignerSpy.mockRestore();
          createTokenSpy.mockRestore();
        }
      });

      it("passes through an issuer-supplied uri unchanged", async () => {
        const customUri = "https://issuer.example/custom-metadata.json";
        const token = await seedIssuedToken({
          id: "tok_deploy_uri_custom",
          mintAddress: null,
          status: "pending",
          uri: customUri,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockResolvedValueOnce(mockDeployResult as never);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(createTokenSpy).toHaveBeenCalledWith(
            expect.objectContaining({
              metadata: expect.objectContaining({ uri: customUri }),
            })
          );
        } finally {
          createOrgSignerSpy.mockRestore();
          createTokenSpy.mockRestore();
        }
      });

      it("rejects a wallet-paid deploy when the signing wallet cannot cover rent and fees", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_wallet_fee_broke",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const getAccountInfoSpy = vi
          .spyOn(SolanaRpc, "getAccountInfo")
          .mockResolvedValueOnce(null as never);
        const createTokenSpy = vi.spyOn(MosaicService.prototype, "createToken");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({ feePayment: "wallet" }),
            },
            env
          );

          expect(res.status).toBe(400);
          const payload = (await res.json()) as { error: { message: string } };
          expect(payload.error.message).toMatch(/pay deployment rent and fees/);
          expect(createTokenSpy).not.toHaveBeenCalled();
        } finally {
          createOrgSignerSpy.mockRestore();
          getAccountInfoSpy.mockRestore();
          createTokenSpy.mockRestore();
        }
      });

      it("deploys with wallet-paid fees when the signing wallet holds enough SOL, without touching Kora", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_wallet_fee_funded",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const getAccountInfoSpy = vi
          .spyOn(SolanaRpc, "getAccountInfo")
          .mockResolvedValueOnce({ lamports: 20_000_000n } as never);
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockResolvedValueOnce(mockDeployResult as never);
        const feePaymentAdapterSpy = vi.spyOn(FeePaymentAdapters, "createFeePaymentAdapter");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({ feePayment: "wallet" }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(getAccountInfoSpy).toHaveBeenCalled();
          expect(createTokenSpy).toHaveBeenCalled();
          expect(feePaymentAdapterSpy).not.toHaveBeenCalled();
        } finally {
          createOrgSignerSpy.mockRestore();
          getAccountInfoSpy.mockRestore();
          createTokenSpy.mockRestore();
          feePaymentAdapterSpy.mockRestore();
        }
      });

      it("routes sponsored deploys through the Kora fee-payment adapter", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_sponsored_fee",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockResolvedValueOnce(mockDeployResult as never);
        const feePaymentAdapterSpy = vi.spyOn(FeePaymentAdapters, "createFeePaymentAdapter");

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({ feePayment: "sponsored" }),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(feePaymentAdapterSpy).toHaveBeenCalled();
        } finally {
          createOrgSignerSpy.mockRestore();
          createTokenSpy.mockRestore();
          feePaymentAdapterSpy.mockRestore();
        }
      });

      it("still surfaces the mint address when recording it fails after a metadata-URI overflow", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_recovery_db_fail",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        // Mint is live on-chain but the follow-up metadata-URI update failed.
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockRejectedValueOnce(
            new Mosaic.MintMetadataUpdateError({
              mint: TEST_SOLANA_ADDRESSES.mint,
              signature: "5recoverySig",
              slot: 100n,
              listAddress: undefined,
            } as never)
          );
        // Recording the live mint then fails too (e.g. a D1 timeout). The handler
        // must still report the mint so the caller knows not to redeploy, rather
        // than letting this second exception escape and bury it.
        const setTokenDeployedSpy = vi
          .spyOn(TokenService.prototype, "setTokenDeployed")
          .mockRejectedValueOnce(new Error("D1_ERROR: timeout"));
        const consoleErrorSpy = vi.spyOn(rootLogger, "error").mockImplementation(() => {});

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          // The original metadata-URI failure is surfaced (not the swallowed D1
          // error), carrying the live mint address in its details.
          expect(res.status).toBe(400);
          const payload = (await res.json()) as {
            error: { code: string; message: string; details?: { mintAddress?: string } };
          };
          expect(payload.error.code).toBe("TRANSACTION_FAILED");
          expect(payload.error.message).toMatch(/do not redeploy/);
          expect(payload.error.details?.mintAddress).toBe(TEST_SOLANA_ADDRESSES.mint);
          // The DB failure was logged rather than escaping the recovery block.
          expect(consoleErrorSpy).toHaveBeenCalled();
        } finally {
          createOrgSignerSpy.mockRestore();
          createTokenSpy.mockRestore();
          setTokenDeployedSpy.mockRestore();
          consoleErrorSpy.mockRestore();
        }
      });

      it("stamps the permanent delegate in the recovery path after a metadata-URI overflow", async () => {
        // A permanent-delegate token whose mint lands on-chain but whose metadata
        // URI follow-up fails must still get its initial permanentDelegate stamped
        // into the DB — otherwise later seize/force-transfer ops target the wrong
        // authority. This mirrors the success path.
        // The arcade template requires the permanentDelegate extension, so the
        // initial delegate resolves to the custody (signing-wallet) address.
        const token = await seedIssuedToken({
          id: "tok_deploy_recovery_perm_delegate",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
          template: "arcade",
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockRejectedValueOnce(
            new Mosaic.MintMetadataUpdateError({
              mint: TEST_SOLANA_ADDRESSES.mint,
              signature: "5recoverySig",
              slot: 100n,
              listAddress: undefined,
            } as never)
          );
        // Recording the live mint succeeds, so the recovery path proceeds to stamp
        // the permanent delegate.
        const updateTokenAuthoritiesSpy = vi.spyOn(
          TokenService.prototype,
          "updateTokenAuthorities"
        );

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          // Recovery always re-throws so the caller knows not to redeploy.
          expect(res.status).toBe(400);
          const payload = (await res.json()) as { error: { code: string } };
          expect(payload.error.code).toBe("TRANSACTION_FAILED");
          // The permanent delegate was persisted despite the metadata-URI failure.
          expect(updateTokenAuthoritiesSpy).toHaveBeenCalledWith(token.id, {
            permanentDelegate: TEST_SOLANA_ADDRESSES.wallet2,
          });
        } finally {
          createOrgSignerSpy.mockRestore();
          createTokenSpy.mockRestore();
          updateTokenAuthoritiesSpy.mockRestore();
        }
      });

      it("returns TRANSACTION_FAILED with the on-chain reason when the create tx fails on-chain", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_onchain_fail",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const onChainDetail = 'Transaction failed: {"InstructionError":[0,{"Custom":6001}]}';
        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockRejectedValueOnce(new AppError("TRANSACTION_FAILED", onChainDetail));

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          expect(res.status).toBe(400);
          const payload = (await res.json()) as { error: { code: string; message: string } };
          expect(payload.error.code).toBe("TRANSACTION_FAILED");
          expect(payload.error.message).toBe(onChainDetail);
        } finally {
          createOrgSignerSpy.mockRestore();
          createTokenSpy.mockRestore();
        }
      });

      it("returns SOLANA_RPC_ERROR when the create tx confirmation times out", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_timeout",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const timeoutDetail = "Transaction 5timeoutSig confirmation timed out after 60000ms";
        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const createTokenSpy = vi
          .spyOn(MosaicService.prototype, "createToken")
          .mockRejectedValueOnce(new AppError("SOLANA_RPC_ERROR", timeoutDetail));

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          expect(res.status).toBe(502);
          const payload = (await res.json()) as { error: { code: string; message: string } };
          expect(payload.error.code).toBe("SOLANA_RPC_ERROR");
          expect(payload.error.message).toBe(timeoutDetail);
        } finally {
          createOrgSignerSpy.mockRestore();
          createTokenSpy.mockRestore();
        }
      });
    });

    describe("POST /v1/issuance/tokens/:tokenId/deploy/prepare", () => {
      it("falls back to the SDP-hosted metadata URL when the token has no uri", async () => {
        if (!(env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL) {
          (env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL = "https://rpc.invalid.test";
        }

        const token = await seedIssuedToken({
          id: "tok_prepare_uri_default",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const prepareCreateTokenSpy = vi
          .spyOn(MosaicService.prototype, "prepareCreateToken")
          .mockResolvedValueOnce({
            serializedTx: "ZmFrZS1zZXJpYWxpemVkLXR4",
            blockhash: "11111111111111111111111111111111",
            lastValidBlockHeight: 0n,
            mint: TEST_SOLANA_ADDRESSES.mint,
            listAddress: undefined,
          } as never);
        const simulateTransactionSpy = vi
          .spyOn(SolanaRpc, "simulateTransaction")
          .mockResolvedValueOnce({
            success: true,
            logs: [],
            unitsConsumed: 0n,
            error: null,
          });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/prepare`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          expect(res.status).toBe(200);
          expect(prepareCreateTokenSpy).toHaveBeenCalledWith(
            expect.objectContaining({
              metadata: expect.objectContaining({ uri: expectedMetadataUrl(token.id) }),
            })
          );
        } finally {
          createOrgSignerSpy.mockRestore();
          prepareCreateTokenSpy.mockRestore();
          simulateTransactionSpy.mockRestore();
        }
      });

      it("re-prepares with an empty uri and signals a follow-up when the create tx overflows", async () => {
        if (!(env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL) {
          (env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL = "https://rpc.invalid.test";
        }

        const token = await seedIssuedToken({
          id: "tok_prepare_uri_overflow",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        // base64 of 1644 chars decodes to 1233 raw bytes — one over the limit.
        const oversizedTx = "A".repeat(1644);
        const slimTx = "ZmFrZS1zZXJpYWxpemVkLXR4";

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const prepareCreateTokenSpy = vi
          .spyOn(MosaicService.prototype, "prepareCreateToken")
          .mockResolvedValueOnce({
            serializedTx: oversizedTx,
            blockhash: "11111111111111111111111111111111",
            lastValidBlockHeight: 0n,
            mint: TEST_SOLANA_ADDRESSES.mint,
            listAddress: undefined,
          } as never)
          .mockResolvedValueOnce({
            serializedTx: slimTx,
            blockhash: "11111111111111111111111111111111",
            lastValidBlockHeight: 0n,
            mint: TEST_SOLANA_ADDRESSES.mint,
            listAddress: undefined,
          } as never);
        const simulateTransactionSpy = vi
          .spyOn(SolanaRpc, "simulateTransaction")
          .mockResolvedValueOnce({ success: true, logs: [], unitsConsumed: 0n, error: null });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/prepare`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          expect(res.status).toBe(200);
          const payload = (await res.json()) as {
            data: {
              transaction: { serialized: string };
              metadataUriFollowUp?: { required: boolean; uri: string };
            };
          };

          // First attempt carries the hosted uri; the overflow retry uses "".
          expect(prepareCreateTokenSpy).toHaveBeenNthCalledWith(
            1,
            expect.objectContaining({
              metadata: expect.objectContaining({ uri: expectedMetadataUrl(token.id) }),
            })
          );
          expect(prepareCreateTokenSpy).toHaveBeenNthCalledWith(
            2,
            expect.objectContaining({ metadata: expect.objectContaining({ uri: "" }) })
          );

          // Response returns the slim create tx + a follow-up descriptor.
          expect(payload.data.transaction.serialized).toBe(slimTx);
          expect(payload.data.metadataUriFollowUp).toEqual({
            required: true,
            uri: expectedMetadataUrl(token.id),
          });
        } finally {
          createOrgSignerSpy.mockRestore();
          prepareCreateTokenSpy.mockRestore();
          simulateTransactionSpy.mockRestore();
        }
      });
    });

    describe("POST /v1/issuance/tokens/:tokenId/deploy/prepare-metadata", () => {
      it("prepares the metadata-uri follow-up tx for a deployed token", async () => {
        if (!(env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL) {
          (env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL = "https://rpc.invalid.test";
        }

        const token = await seedIssuedToken({
          id: "tok_prepare_metadata_followup",
          mintAddress: TEST_SOLANA_ADDRESSES.mint,
          status: "active",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const prepareUpdateMetadataSpy = vi
          .spyOn(MosaicService.prototype, "prepareUpdateMetadata")
          .mockResolvedValueOnce({
            serializedTx: "ZmFrZS1tZXRhZGF0YS10eA",
            blockhash: "11111111111111111111111111111111",
            lastValidBlockHeight: 0n,
            requiredSigners: [],
          } as never);
        const simulateTransactionSpy = vi
          .spyOn(SolanaRpc, "simulateTransaction")
          .mockResolvedValueOnce({ success: true, logs: [], unitsConsumed: 0n, error: null });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/prepare-metadata`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({}),
            },
            env
          );

          expect(res.status).toBe(200);
          const payload = (await res.json()) as {
            data: { transaction: { serialized: string } | null; uri: string };
          };

          expect(prepareUpdateMetadataSpy).toHaveBeenCalledWith(
            expect.objectContaining({
              mint: TEST_SOLANA_ADDRESSES.mint,
              uri: expectedMetadataUrl(token.id),
            })
          );
          expect(payload.data.transaction?.serialized).toBe("ZmFrZS1tZXRhZGF0YS10eA");
          expect(payload.data.uri).toBe(expectedMetadataUrl(token.id));
        } finally {
          createOrgSignerSpy.mockRestore();
          prepareUpdateMetadataSpy.mockRestore();
          simulateTransactionSpy.mockRestore();
        }
      });

      it("ignores a request-body signingWalletId, using the wallet pinned at deploy/prepare", async () => {
        if (!(env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL) {
          (env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL = "https://rpc.invalid.test";
        }

        const token = await seedIssuedToken({
          id: "tok_prepare_metadata_wallet_pin",
          mintAddress: TEST_SOLANA_ADDRESSES.mint,
          status: "active",
          uri: null,
          signingWalletId: "wallet_pinned",
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValueOnce({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const prepareUpdateMetadataSpy = vi
          .spyOn(MosaicService.prototype, "prepareUpdateMetadata")
          .mockResolvedValueOnce({
            serializedTx: "ZmFrZS1tZXRhZGF0YS10eA",
            blockhash: "11111111111111111111111111111111",
            lastValidBlockHeight: 0n,
            requiredSigners: [],
          } as never);
        const simulateTransactionSpy = vi
          .spyOn(SolanaRpc, "simulateTransaction")
          .mockResolvedValueOnce({ success: true, logs: [], unitsConsumed: 0n, error: null });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/prepare-metadata`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({ signingWalletId: "wallet_body_ignored" }),
            },
            env
          );

          expect(res.status).toBe(200);
          // The update-authority signer comes from the pinned wallet, not the body —
          // otherwise the follow-up tx would be signed by the wrong authority.
          expect(createOrgSignerSpy).toHaveBeenCalledWith(
            expect.anything(),
            expect.anything(),
            expect.anything(),
            "wallet_pinned"
          );
        } finally {
          createOrgSignerSpy.mockRestore();
          prepareUpdateMetadataSpy.mockRestore();
          simulateTransactionSpy.mockRestore();
        }
      });

      it("returns 400 for a token that has not been deployed", async () => {
        const token = await seedIssuedToken({
          id: "tok_prepare_metadata_undeployed",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const res = await app.request(
          `/v1/issuance/tokens/${token.id}/deploy/prepare-metadata`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({}),
          },
          env
        );

        expect(res.status).toBe(400);
      });
    });

    describe("POST /v1/issuance/tokens/:tokenId/deploy/confirm", () => {
      const ensureRpcUrl = () => {
        if (!(env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL) {
          (env as { SOLANA_RPC_URL?: string }).SOLANA_RPC_URL = "https://rpc.invalid.test";
        }
      };

      it("records the mint, marks the token active, and unblocks prepare-metadata", async () => {
        ensureRpcUrl();

        const token = await seedIssuedToken({
          id: "tok_deploy_confirm",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([
            { slot: 100n, confirmations: 10n, confirmationStatus: "confirmed", err: null },
          ]);
        const accountExistsSpy = vi.spyOn(SolanaRpc, "accountExists").mockResolvedValueOnce(true);
        const getTransactionSpy = vi.spyOn(SolanaRpc, "getTransaction").mockResolvedValueOnce({
          slot: 100n,
          err: null,
          instructions: [
            {
              programId: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
              parsedType: "initializeMint2",
              info: {
                mint: TEST_SOLANA_ADDRESSES.mint,
                mintAuthority: TEST_SOLANA_ADDRESSES.wallet2,
                freezeAuthority: TEST_SOLANA_ADDRESSES.wallet2,
              },
            },
          ],
        });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5testSigHOO466Confirm",
                mint: TEST_SOLANA_ADDRESSES.mint,
              }),
            },
            env
          );

          expect(res.status).toBe(200);
          const payload = (await res.json()) as {
            data: { token: { mintAddress: string | null; status: string } };
          };
          expect(payload.data.token.mintAddress).toBe(TEST_SOLANA_ADDRESSES.mint);
          expect(payload.data.token.status).toBe("active");

          // The recorded mint unblocks the metadata follow-up, which previously
          // 400'd for every non-custodial caller (mintAddress was never set).
          const prepareUpdateMetadataSpy = vi
            .spyOn(MosaicService.prototype, "prepareUpdateMetadata")
            .mockResolvedValueOnce({
              serializedTx: "ZmFrZS1tZXRhZGF0YS10eA",
              blockhash: "11111111111111111111111111111111",
              lastValidBlockHeight: 0n,
              requiredSigners: [],
            } as never);
          const simulateTransactionSpy = vi
            .spyOn(SolanaRpc, "simulateTransaction")
            .mockResolvedValueOnce({ success: true, logs: [], unitsConsumed: 0n, error: null });

          try {
            const followUp = await app.request(
              `/v1/issuance/tokens/${token.id}/deploy/prepare-metadata`,
              {
                method: "POST",
                headers: {
                  "Content-Type": "application/json",
                  Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
                },
                body: JSON.stringify({}),
              },
              env
            );

            expect(followUp.status).toBe(200);
          } finally {
            prepareUpdateMetadataSpy.mockRestore();
            simulateTransactionSpy.mockRestore();
          }
        } finally {
          createOrgSignerSpy.mockRestore();
          getSignatureStatusesSpy.mockRestore();
          accountExistsSpy.mockRestore();
          getTransactionSpy.mockRestore();
        }
      });

      it("still returns 200 with the token active when post-deploy bookkeeping fails", async () => {
        ensureRpcUrl();

        // The mint is live on-chain and setTokenDeployed has flipped the token to
        // active; a failure writing the audit/transaction row afterward must not
        // 500, or a retry would hit the `status !== "pending"` guard and 400
        // permanently, stranding the token with no recovery.
        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_bookkeeping_fail",
          mintAddress: null,
          status: "pending",
          uri: null,
          isFreezable: false,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([
            { slot: 100n, confirmations: 10n, confirmationStatus: "confirmed", err: null },
          ]);
        const accountExistsSpy = vi.spyOn(SolanaRpc, "accountExists").mockResolvedValueOnce(true);
        const getTransactionSpy = vi.spyOn(SolanaRpc, "getTransaction").mockResolvedValueOnce({
          slot: 100n,
          err: null,
          instructions: [
            {
              programId: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
              parsedType: "initializeMint2",
              info: {
                mint: TEST_SOLANA_ADDRESSES.mint,
                mintAuthority: TEST_SOLANA_ADDRESSES.wallet2,
              },
            },
          ],
        });
        // The transaction-row write fails after the token is already deployed.
        const createTransactionSpy = vi
          .spyOn(TokenService.prototype, "createTransaction")
          .mockRejectedValueOnce(new Error("D1_ERROR: timeout"));
        const consoleErrorSpy = vi.spyOn(rootLogger, "error").mockImplementation(() => {});

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5testSigHOO466ConfirmBookkeeping",
                mint: TEST_SOLANA_ADDRESSES.mint,
              }),
            },
            env
          );

          // The deploy is recorded and surfaced as success despite the bookkeeping
          // failure (which is logged, not thrown).
          expect(res.status).toBe(200);
          const payload = (await res.json()) as {
            data: { token: { mintAddress: string | null; status: string } };
          };
          expect(payload.data.token.mintAddress).toBe(TEST_SOLANA_ADDRESSES.mint);
          expect(payload.data.token.status).toBe("active");
          expect(consoleErrorSpy).toHaveBeenCalled();
        } finally {
          createOrgSignerSpy.mockRestore();
          getSignatureStatusesSpy.mockRestore();
          accountExistsSpy.mockRestore();
          getTransactionSpy.mockRestore();
          createTransactionSpy.mockRestore();
          consoleErrorSpy.mockRestore();
        }
      });

      it("returns 400 when the confirmed tx did not create the supplied mint", async () => {
        ensureRpcUrl();

        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_unrelated_tx",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        // Confirmed signature + an existing mint account, but the tx is unrelated
        // (no initializeMint for this mint) — the spoofing case the guard closes.
        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([
            { slot: 100n, confirmations: 10n, confirmationStatus: "confirmed", err: null },
          ]);
        const accountExistsSpy = vi.spyOn(SolanaRpc, "accountExists").mockResolvedValueOnce(true);
        const getTransactionSpy = vi.spyOn(SolanaRpc, "getTransaction").mockResolvedValueOnce({
          slot: 100n,
          err: null,
          instructions: [
            {
              programId: "11111111111111111111111111111111",
              parsedType: "transfer",
              info: { destination: TEST_SOLANA_ADDRESSES.wallet2 },
            },
          ],
        });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5unrelatedConfirmedSig",
                mint: TEST_SOLANA_ADDRESSES.mint,
              }),
            },
            env
          );

          expect(res.status).toBe(400);

          // The token stays pending — nothing recorded from a spoofed signature.
          const stillPending = await app.request(
            `/v1/issuance/tokens/${token.id}`,
            {
              method: "GET",
              headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
            },
            env
          );
          const payload = (await stillPending.json()) as {
            data: { token: { mintAddress: string | null; status: string } };
          };
          expect(payload.data.token.mintAddress).toBeNull();
          expect(payload.data.token.status).toBe("pending");
        } finally {
          getSignatureStatusesSpy.mockRestore();
          accountExistsSpy.mockRestore();
          getTransactionSpy.mockRestore();
        }
      });

      it("returns 400 when the mint authority differs from the server-derived custody address", async () => {
        ensureRpcUrl();

        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_wrong_authority",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([
            { slot: 100n, confirmations: 10n, confirmationStatus: "confirmed", err: null },
          ]);
        const accountExistsSpy = vi.spyOn(SolanaRpc, "accountExists").mockResolvedValueOnce(true);
        const getTransactionSpy = vi.spyOn(SolanaRpc, "getTransaction").mockResolvedValueOnce({
          slot: 100n,
          err: null,
          instructions: [
            {
              programId: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
              parsedType: "initializeMint2",
              info: {
                mint: TEST_SOLANA_ADDRESSES.mint,
                mintAuthority: TEST_SOLANA_ADDRESSES.wallet1,
                freezeAuthority: null,
              },
            },
          ],
        });

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5wrongAuthorityConfirmedSig",
                mint: TEST_SOLANA_ADDRESSES.mint,
              }),
            },
            env
          );

          expect(res.status).toBe(400);
          const stillPending = await new TokenService(getDb(env)).getToken({
            tokenId: token.id,
            organizationId: TEST_PROJECT.organizationId,
            projectId: TEST_PROJECT.id,
          });
          expect(stillPending?.mintAddress).toBeNull();
          expect(stillPending?.status).toBe("pending");
        } finally {
          createOrgSignerSpy.mockRestore();
          getSignatureStatusesSpy.mockRestore();
          accountExistsSpy.mockRestore();
          getTransactionSpy.mockRestore();
        }
      });

      it("returns a retryable error (not the wrong-tx 400) when the tx is not yet indexed", async () => {
        ensureRpcUrl();

        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_not_indexed",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        // Confirmed via getSignatureStatuses and the mint exists, but
        // getTransaction hasn't indexed the tx yet (the two RPC methods index
        // independently). This is a transient race, not a bad deploy — the
        // client must get a retryable signal, not the "wrong tx" 400.
        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([
            { slot: 100n, confirmations: 10n, confirmationStatus: "confirmed", err: null },
          ]);
        const accountExistsSpy = vi.spyOn(SolanaRpc, "accountExists").mockResolvedValueOnce(true);
        const getTransactionSpy = vi.spyOn(SolanaRpc, "getTransaction").mockResolvedValueOnce(null);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5notYetIndexedSig",
                mint: TEST_SOLANA_ADDRESSES.mint,
              }),
            },
            env
          );

          // 5xx (retryable), distinct from the 400 the spoofed/wrong-tx case returns.
          expect(res.status).toBe(502);
          const payload = (await res.json()) as { error: { message: string } };
          expect(payload.error.message).not.toMatch(/did not create this mint/);

          // Token stays pending so a retry can still record it.
          const stillPending = await app.request(
            `/v1/issuance/tokens/${token.id}`,
            {
              method: "GET",
              headers: { Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}` },
            },
            env
          );
          const tokenPayload = (await stillPending.json()) as {
            data: { token: { mintAddress: string | null; status: string } };
          };
          expect(tokenPayload.data.token.mintAddress).toBeNull();
          expect(tokenPayload.data.token.status).toBe("pending");
        } finally {
          getSignatureStatusesSpy.mockRestore();
          accountExistsSpy.mockRestore();
          getTransactionSpy.mockRestore();
        }
      });

      it("records the server-derived ABL list address, ignoring the client-supplied one", async () => {
        ensureRpcUrl();

        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_abl",
          mintAddress: null,
          status: "pending",
          uri: null,
          isFreezable: true,
          requiresAllowlist: true,
          ablListAddress: null,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([
            { slot: 100n, confirmations: 10n, confirmationStatus: "confirmed", err: null },
          ]);
        const accountExistsSpy = vi.spyOn(SolanaRpc, "accountExists").mockResolvedValueOnce(true);
        const getTransactionSpy = vi.spyOn(SolanaRpc, "getTransaction").mockResolvedValueOnce({
          slot: 100n,
          err: null,
          instructions: [
            {
              programId: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
              parsedType: "initializeMint2",
              info: {
                mint: TEST_SOLANA_ADDRESSES.mint,
                mintAuthority: TEST_SOLANA_ADDRESSES.wallet2,
                freezeAuthority: TEST_SOLANA_ADDRESSES.wallet2,
              },
            },
          ],
        });
        // The list-config PDA is derived server-side from (custody authority,
        // mint). wallet3 is the legitimate derived value; the client tries to
        // inject wallet1, which must be ignored.
        const deriveAblListAddressSpy = vi
          .spyOn(Mosaic, "deriveAblListAddress")
          .mockResolvedValue(TEST_SOLANA_ADDRESSES.wallet3 as Address);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5ablConfirmSig",
                mint: TEST_SOLANA_ADDRESSES.mint,
                listAddress: TEST_SOLANA_ADDRESSES.wallet1, // bogus — must be ignored
              }),
            },
            env
          );

          expect(res.status).toBe(200);

          // Derived from the server-resolved custody authority + mint, never the body.
          expect(deriveAblListAddressSpy).toHaveBeenCalledWith(
            TEST_SOLANA_ADDRESSES.wallet2,
            TEST_SOLANA_ADDRESSES.mint
          );

          const stored = await new TokenService(getDb(env)).getToken({
            tokenId: token.id,
            organizationId: TEST_PROJECT.organizationId,
            projectId: TEST_PROJECT.id,
          });
          expect(stored?.ablListAddress).toBe(TEST_SOLANA_ADDRESSES.wallet3);
          expect(stored?.ablListAddress).not.toBe(TEST_SOLANA_ADDRESSES.wallet1);
        } finally {
          createOrgSignerSpy.mockRestore();
          getSignatureStatusesSpy.mockRestore();
          accountExistsSpy.mockRestore();
          getTransactionSpy.mockRestore();
          deriveAblListAddressSpy.mockRestore();
        }
      });

      it("pins the signing wallet from prepareDeploy so confirmDeploy can't diverge", async () => {
        ensureRpcUrl();

        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_wallet_pin",
          mintAddress: null,
          status: "pending",
          uri: null,
          signingWalletId: null,
          requiresAllowlist: false,
        });

        const createOrgSignerSpy = vi
          .spyOn(SolanaServices, "createOrgSigner")
          .mockResolvedValue({ address: TEST_SOLANA_ADDRESSES.wallet2 } as never);
        const prepareCreateTokenSpy = vi
          .spyOn(MosaicService.prototype, "prepareCreateToken")
          .mockResolvedValueOnce({
            serializedTx: "ZmFrZS1zZXJpYWxpemVkLXR4",
            blockhash: "11111111111111111111111111111111",
            lastValidBlockHeight: 0n,
            mint: TEST_SOLANA_ADDRESSES.mint,
            listAddress: undefined,
          } as never);
        const simulateTransactionSpy = vi
          .spyOn(SolanaRpc, "simulateTransaction")
          .mockResolvedValueOnce({ success: true, logs: [], unitsConsumed: 0n, error: null });
        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([
            { slot: 100n, confirmations: 10n, confirmationStatus: "confirmed", err: null },
          ]);
        const accountExistsSpy = vi.spyOn(SolanaRpc, "accountExists").mockResolvedValueOnce(true);
        const getTransactionSpy = vi.spyOn(SolanaRpc, "getTransaction").mockResolvedValueOnce({
          slot: 100n,
          err: null,
          instructions: [
            {
              programId: "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
              parsedType: "initializeMint2",
              info: {
                mint: TEST_SOLANA_ADDRESSES.mint,
                mintAuthority: TEST_SOLANA_ADDRESSES.wallet2,
                freezeAuthority: TEST_SOLANA_ADDRESSES.wallet2,
              },
            },
          ],
        });

        try {
          // 1. prepareDeploy with a custom signing wallet — it must be persisted.
          const prepareRes = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/prepare`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({ signingWalletId: "wallet_custom_pin" }),
            },
            env
          );
          expect(prepareRes.status).toBe(200);

          const afterPrepare = await new TokenService(getDb(env)).getToken({
            tokenId: token.id,
            organizationId: TEST_PROJECT.organizationId,
            projectId: TEST_PROJECT.id,
          });
          expect(afterPrepare?.signingWalletId).toBe("wallet_custom_pin");

          // 2. confirmDeploy with a DIVERGENT signingWalletId in the body — it
          // must be ignored in favor of the wallet prepareDeploy pinned, or the
          // custody address (and recorded authorities) would silently differ.
          createOrgSignerSpy.mockClear();
          const confirmRes = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5walletPinSig",
                mint: TEST_SOLANA_ADDRESSES.mint,
                signingWalletId: "wallet_body_divergent_ignored",
              }),
            },
            env
          );
          expect(confirmRes.status).toBe(200);
          expect(createOrgSignerSpy).toHaveBeenCalledWith(
            expect.anything(),
            expect.anything(),
            expect.anything(),
            "wallet_custom_pin"
          );
        } finally {
          createOrgSignerSpy.mockRestore();
          prepareCreateTokenSpy.mockRestore();
          simulateTransactionSpy.mockRestore();
          getSignatureStatusesSpy.mockRestore();
          accountExistsSpy.mockRestore();
          getTransactionSpy.mockRestore();
        }
      });

      it("returns 400 when the create tx is not confirmed on-chain", async () => {
        ensureRpcUrl();

        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_unconfirmed",
          mintAddress: null,
          status: "pending",
          uri: null,
          requiresAllowlist: false,
        });

        const getSignatureStatusesSpy = vi
          .spyOn(SolanaRpc, "getSignatureStatuses")
          .mockResolvedValueOnce([null]);

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/deploy/confirm`,
            {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
                Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
              },
              body: JSON.stringify({
                signature: "5unconfirmedSig",
                mint: TEST_SOLANA_ADDRESSES.mint,
              }),
            },
            env
          );

          expect(res.status).toBe(400);
        } finally {
          getSignatureStatusesSpy.mockRestore();
        }
      });

      it("returns 400 when the token already has a mint address", async () => {
        const token = await seedIssuedToken({
          id: "tok_deploy_confirm_already",
          mintAddress: TEST_SOLANA_ADDRESSES.mint,
          status: "active",
          uri: null,
          requiresAllowlist: false,
        });

        const res = await app.request(
          `/v1/issuance/tokens/${token.id}/deploy/confirm`,
          {
            method: "POST",
            headers: {
              "Content-Type": "application/json",
              Authorization: `Bearer ${TEST_PROJECT_API_KEY.raw}`,
            },
            body: JSON.stringify({
              signature: "5testSig",
              mint: TEST_SOLANA_ADDRESSES.mint,
            }),
          },
          env
        );

        expect(res.status).toBe(400);
      });
    });

    describe("GET /v1/issuance/tokens/:tokenId/metadata.json", () => {
      it("serves public metadata JSON without authentication", async () => {
        const token = await seedIssuedToken({
          id: "tok_metadata_public",
          name: "Public Metadata Token",
          symbol: "PMT",
          description: "Served by SDP",
          imageUrl: "https://issuer.example/logo.png",
        });

        const res = await app.request(
          `/v1/issuance/tokens/${token.id}/metadata.json`,
          { method: "GET" },
          env
        );

        expect(res.status).toBe(200);
        expect(res.headers.get("Access-Control-Allow-Origin")).toBe("*");
        expect(res.headers.get("Cache-Control")).toBe("public, max-age=300");

        const body = await res.json();
        expect(body).toEqual({
          name: "Public Metadata Token",
          symbol: "PMT",
          description: "Served by SDP",
          image: "https://issuer.example/logo.png",
        });
      });

      it("omits description and image when absent", async () => {
        const token = await seedIssuedToken({
          id: "tok_metadata_minimal",
          name: "Minimal Token",
          symbol: "MIN",
          description: null,
          imageUrl: null,
        });

        const res = await app.request(
          `/v1/issuance/tokens/${token.id}/metadata.json`,
          { method: "GET" },
          env
        );

        expect(res.status).toBe(200);
        const body = await res.json();
        expect(body).toEqual({ name: "Minimal Token", symbol: "MIN" });
      });

      it("returns 404 with a short negative-cache for an unknown token id", async () => {
        const res = await app.request(
          "/v1/issuance/tokens/tok_does_not_exist/metadata.json",
          { method: "GET" },
          env
        );

        expect(res.status).toBe(404);
        expect(res.headers.get("Access-Control-Allow-Origin")).toBe("*");
        // Unknown ids never resolve — negative-cache to blunt enumeration probes.
        expect(res.headers.get("Cache-Control")).toBe("public, max-age=60");
      });

      it("returns an uncacheable 404 for a known but not-yet-deployed token", async () => {
        // A pending token can flip to 200 within seconds of deploy, so its 404
        // must not be cached — otherwise the CDN/browser serves a stale 404.
        const token = await seedIssuedToken({
          id: "tok_metadata_pending",
          name: "Pending Token",
          symbol: "PEND",
          mintAddress: null,
          status: "pending",
        });

        const res = await app.request(
          `/v1/issuance/tokens/${token.id}/metadata.json`,
          { method: "GET" },
          env
        );

        expect(res.status).toBe(404);
        expect(res.headers.get("Access-Control-Allow-Origin")).toBe("*");
        expect(res.headers.get("Cache-Control")).toBe("no-store");
      });

      it("keeps the CORS header on the error response when the DB read throws", async () => {
        // The CORS header is set up-front, so even a 500 from a failed DB read
        // stays fetchable from any origin — browsers see the real error rather
        // than an opaque CORS failure.
        const token = await seedIssuedToken({
          id: "tok_metadata_db_error",
          name: "Errored Token",
          symbol: "ERR",
        });
        const spy = vi
          .spyOn(TokenService.prototype, "getPublicTokenMetadata")
          .mockRejectedValueOnce(new Error("db down"));

        try {
          const res = await app.request(
            `/v1/issuance/tokens/${token.id}/metadata.json`,
            { method: "GET" },
            env
          );

          expect(res.status).toBe(500);
          expect(res.headers.get("Access-Control-Allow-Origin")).toBe("*");
        } finally {
          spy.mockRestore();
        }
      });
    });
  });
});
