{"version":3,"file":"reservation-CDbInVw0.cjs","sources":["../src/tbv/core/utils/utxo/availability.ts","../src/tbv/core/utils/utxo/reservation.ts"],"sourcesContent":["/**\n * UTXO Availability Validation\n *\n * Validates that UTXOs referenced in a pre-pegin transaction are still unspent\n * BEFORE asking the user to sign. This prevents wasted signing effort when\n * UTXOs have already been spent by unrelated transactions.\n *\n * These functions are pure — they accept pre-fetched UTXOs and perform no I/O.\n * The vault service wrapper is responsible for fetching UTXOs from the mempool.\n */\n\nimport { Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\n/**\n * Reference to a Bitcoin UTXO by its outpoint (txid + vout).\n *\n * Used by the availability check to compare a Pre-PegIn transaction's\n * declared inputs against the wallet's current spendable set. Txids are\n * compared case-insensitively; callers should treat the txid as opaque\n * lowercase hex.\n */\nexport interface UtxoRef {\n  txid: string;\n  vout: number;\n}\n\n/**\n * Information about a missing/spent UTXO.\n */\nexport interface MissingUtxoInfo {\n  /** Transaction ID of the missing UTXO */\n  txid: string;\n  /** Output index of the missing UTXO */\n  vout: number;\n}\n\n/**\n * Result of UTXO validation.\n */\nexport interface UtxoValidationResult {\n  /** Whether all UTXOs are still available */\n  allAvailable: boolean;\n  /** List of missing UTXOs (if any) */\n  missingUtxos: MissingUtxoInfo[];\n  /** Total number of inputs checked */\n  totalInputs: number;\n}\n\n/**\n * Error thrown when UTXOs are not available.\n */\nexport class UtxoNotAvailableError extends Error {\n  public readonly missingUtxos: MissingUtxoInfo[];\n\n  constructor(missingUtxos: MissingUtxoInfo[]) {\n    const count = missingUtxos.length;\n    const message =\n      count === 1\n        ? \"The UTXO for this peg-in is no longer available. It may have been spent in another transaction. Please create a new peg-in request with a different UTXO.\"\n        : `${count} UTXOs for this peg-in are no longer available. They may have been spent. Please create a new peg-in request with different UTXOs.`;\n\n    super(message);\n    this.name = \"UtxoNotAvailableError\";\n    this.missingUtxos = missingUtxos;\n  }\n}\n\n/**\n * Extract input references (txid:vout) from an unsigned transaction.\n *\n * @param unsignedTxHex - Unsigned transaction hex\n * @returns Array of input references\n */\nexport function extractInputsFromTransaction(\n  unsignedTxHex: string,\n): Array<{ txid: string; vout: number }> {\n  const cleanHex = unsignedTxHex.startsWith(\"0x\")\n    ? unsignedTxHex.slice(2)\n    : unsignedTxHex;\n\n  let tx: Transaction;\n  try {\n    tx = Transaction.fromHex(cleanHex);\n  } catch (error) {\n    throw new Error(\n      `Failed to parse BTC transaction: ${error instanceof Error ? error.message : String(error)}`,\n    );\n  }\n\n  return tx.ins.map((input) => ({\n    // Bitcoin stores txid in reverse byte order\n    txid: Buffer.from(input.hash).reverse().toString(\"hex\"),\n    vout: input.index,\n  }));\n}\n\n/**\n * Validate that all UTXOs in a transaction are still available.\n *\n * Pure function — accepts pre-fetched UTXOs instead of making network calls.\n * This should be called BEFORE signing to avoid wasting user effort\n * signing a transaction that will fail to broadcast.\n *\n * @param unsignedTxHex - Unsigned transaction hex\n * @param availableUtxos - Pre-fetched list of available UTXOs for the depositor\n * @returns Validation result with missing UTXO details\n */\nexport function validateUtxosAvailable(\n  unsignedTxHex: string,\n  availableUtxos: UtxoRef[],\n): UtxoValidationResult {\n  const inputs = extractInputsFromTransaction(unsignedTxHex);\n\n  if (inputs.length === 0) {\n    throw new Error(\"Transaction has no inputs\");\n  }\n\n  // Detect duplicate inputs (same txid:vout referenced more than once).\n  // This would produce an invalid Bitcoin transaction.\n  const inputKeys = new Set<string>();\n  for (const input of inputs) {\n    const key = `${input.txid.toLowerCase()}:${input.vout}`;\n    if (inputKeys.has(key)) {\n      throw new Error(\n        `Transaction contains duplicate input ${input.txid}:${input.vout}. ` +\n          `This would produce an invalid Bitcoin transaction.`,\n      );\n    }\n    inputKeys.add(key);\n  }\n\n  // Set of available outpoints for O(1) lookup. Lowercased so the comparison\n  // is case-insensitive against whatever case the wallet returned.\n  const availableSet = new Set(\n    availableUtxos.map((utxo) => `${utxo.txid.toLowerCase()}:${utxo.vout}`),\n  );\n\n  // Check which inputs are missing\n  const missingUtxos: MissingUtxoInfo[] = [];\n  for (const input of inputs) {\n    const key = `${input.txid.toLowerCase()}:${input.vout}`;\n    if (!availableSet.has(key)) {\n      missingUtxos.push({\n        txid: input.txid,\n        vout: input.vout,\n      });\n    }\n  }\n\n  return {\n    allAvailable: missingUtxos.length === 0,\n    missingUtxos,\n    totalInputs: inputs.length,\n  };\n}\n\n/**\n * Validate UTXOs and throw if any are not available.\n *\n * Pure convenience function that combines validation and error throwing.\n *\n * @param unsignedTxHex - Unsigned transaction hex\n * @param availableUtxos - Pre-fetched list of available UTXOs for the depositor\n * @throws UtxoNotAvailableError if any UTXOs are not available\n * @throws Error if validation fails\n */\nexport function assertUtxosAvailable(\n  unsignedTxHex: string,\n  availableUtxos: UtxoRef[],\n): void {\n  const result = validateUtxosAvailable(unsignedTxHex, availableUtxos);\n\n  if (!result.allAvailable) {\n    throw new UtxoNotAvailableError(result.missingUtxos);\n  }\n}\n","/**\n * Pending-vault outpoint overlap detection.\n *\n * Given the depositor's pending vaults (indexer + local cache) and the\n * outpoints a new deposit's coin selector picked, return the set of\n * pending vault ids whose Pre-PegIn BTC tx shares an input. Advisory\n * only — used to warn the user before signing.\n *\n * Only `PENDING` vaults contribute: VERIFIED+ have their Pre-PegIn\n * already confirmed on-chain, so those inputs cannot still appear in\n * the wallet's spendable set.\n */\nimport { Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport { stripHexPrefix } from \"../../primitives/utils/bitcoin\";\nimport { ContractStatus } from \"../../services/deposit/peginState\";\n\nimport { type UtxoRef } from \"./availability\";\n\n/** Locally-known pending pegin. `id` is the bytes32 vault id. */\nexport interface PendingPeginLike {\n  id?: string;\n  unsignedTxHex?: string;\n}\n\n/** On-chain vault row from the indexer. */\nexport interface VaultLike {\n  id?: string;\n  status: number;\n  unsignedPrePeginTx: string;\n}\n\nexport interface FindOverlappingPendingVaultsParams {\n  selectedOutpoints: ReadonlyArray<UtxoRef>;\n  vaults?: ReadonlyArray<VaultLike>;\n  pendingPegins?: ReadonlyArray<PendingPeginLike>;\n}\n\nfunction extractInputUtxoRefs(txHex: string): UtxoRef[] {\n  try {\n    const tx = Transaction.fromHex(stripHexPrefix(txHex));\n    return tx.ins.map((input) => ({\n      txid: Buffer.from(input.hash).reverse().toString(\"hex\"),\n      vout: input.index,\n    }));\n  } catch {\n    return [];\n  }\n}\n\nfunction outpointKey(o: UtxoRef): string {\n  return `${o.txid.toLowerCase()}:${o.vout}`;\n}\n\n/**\n * Return the ids of pending vaults whose committed Pre-PegIn inputs\n * overlap any of the just-selected outpoints. On-chain `PENDING` vaults\n * take precedence over a same-id local pegin entry.\n */\nexport function findOverlappingPendingVaults(\n  params: FindOverlappingPendingVaultsParams,\n): string[] {\n  const { selectedOutpoints, vaults = [], pendingPegins = [] } = params;\n\n  const selectedSet = new Set(selectedOutpoints.map(outpointKey));\n  if (selectedSet.size === 0) return [];\n\n  const seenIds = new Set<string>();\n  const impacted = new Set<string>();\n\n  const consider = (id: string | undefined, txHex: string): void => {\n    if (!id) return;\n    const idLower = id.toLowerCase();\n    if (seenIds.has(idLower)) return;\n    seenIds.add(idLower);\n    const inputs = extractInputUtxoRefs(txHex);\n    for (const input of inputs) {\n      if (selectedSet.has(outpointKey(input))) {\n        impacted.add(id);\n        return;\n      }\n    }\n  };\n\n  // On-chain wins on id collision.\n  for (const v of vaults) {\n    if (v.status !== ContractStatus.PENDING) continue;\n    consider(v.id, v.unsignedPrePeginTx);\n  }\n  for (const p of pendingPegins) {\n    if (!p.unsignedTxHex) continue;\n    consider(p.id, p.unsignedTxHex);\n  }\n\n  return Array.from(impacted);\n}\n"],"names":["UtxoNotAvailableError","missingUtxos","count","message","__publicField","extractInputsFromTransaction","unsignedTxHex","cleanHex","tx","Transaction","error","input","Buffer","validateUtxosAvailable","availableUtxos","inputs","inputKeys","key","availableSet","utxo","assertUtxosAvailable","result","extractInputUtxoRefs","txHex","stripHexPrefix","outpointKey","o","findOverlappingPendingVaults","params","selectedOutpoints","vaults","pendingPegins","selectedSet","seenIds","impacted","consider","id","idLower","v","ContractStatus","p"],"mappings":"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"}