{"version":3,"file":"errors-CGcNP0rV.cjs","sources":["../src/tbv/core/contracts/errors.ts"],"sourcesContent":["/**\n * Contract Error Handling Utilities\n *\n * Provides utilities for extracting and handling contract revert errors.\n * Maps known error selectors to user-friendly messages.\n *\n * @module contracts/errors\n */\n\n/**\n * Known contract error signatures mapped to user-friendly messages.\n *\n * Error selectors are the first 4 bytes of keccak256(error signature).\n * Example: keccak256(\"VaultAlreadyExists()\") = 0x04aabf33...\n */\nexport const CONTRACT_ERRORS: Record<string, string> = {\n  // VaultAlreadyExists()\n  \"0x04aabf33\":\n    \"Vault already exists: This Bitcoin transaction has already been registered. \" +\n    \"Please select different UTXOs or use a different amount to create a unique transaction.\",\n  // ScriptPubKeyMismatch() - taproot output doesn't match expected script\n  \"0x4fec082d\":\n    \"Script mismatch: The Bitcoin transaction's taproot output does not match the expected vault script. \" +\n    \"This may be caused by incorrect vault participants or key configuration.\",\n  // InvalidBTCProofOfPossession()\n  \"0x6cc363a5\":\n    \"Invalid BTC proof of possession: The signature could not be verified. \" +\n    \"Please ensure you're signing with the correct Bitcoin wallet.\",\n  // InvalidBTCPublicKey()\n  \"0x6c3f2bf6\":\n    \"Invalid BTC public key: The Bitcoin public key format is invalid.\",\n  // InvalidAmount()\n  \"0x2c5211c6\":\n    \"Invalid amount: The deposit amount is invalid or below the minimum required.\",\n  // ApplicationNotRegistered()\n  \"0x0405f772\":\n    \"Application not registered: The application controller is not registered in the system.\",\n  // InvalidProviderStatus()\n  \"0x24e165cc\":\n    \"Invalid provider status: The vault provider is not in a valid state to accept deposits.\",\n  // ZeroAddress()\n  \"0xd92e233d\":\n    \"Zero address: One of the required addresses is the zero address.\",\n  // BtcKeyMismatch()\n  \"0x65aa7007\":\n    \"BTC key mismatch: The Bitcoin public key does not match the expected key.\",\n  // Unauthorized()\n  \"0x82b42900\":\n    \"Unauthorized: You must be the depositor or vault provider to submit this transaction.\",\n  // InvalidSignature() - common signature verification error\n  \"0x8baa579f\":\n    \"Invalid signature: The BTC proof of possession signature could not be verified.\",\n  // InvalidBtcTransaction()\n  \"0x2f9d01e9\":\n    \"Invalid BTC transaction: The Bitcoin transaction format is invalid.\",\n  // VaultProviderNotRegistered()\n  \"0x5a3c6b3e\":\n    \"Vault provider not registered: The selected vault provider is not registered.\",\n  // InvalidPeginFee(uint256,uint256)\n  \"0x979f4518\":\n    \"Invalid pegin fee: The ETH fee sent does not match the required amount. \" +\n    \"This may indicate a fee rate change during the transaction.\",\n  // PrePeginOutputAlreadyUsed()\n  \"0x5fad9694\":\n    \"This pre-pegin output has already been used to activate another vault.\",\n  // PeginTransactionAlreadyUsed()\n  \"0x7ed061c9\":\n    \"This pegin transaction has already been used to activate another vault.\",\n  // DuplicateHashlock() — keccak256(abi.encodePacked(hashlock, msg.sender))\n  // collision in BTCVaultRegistry.hashlockToVaultId. Hashlocks are derived\n  // deterministically from the depositor's BTC wallet + selected UTXOs, so\n  // reusing the same UTXOs from the same wallet (even after a previous\n  // vault expires) produces the same hashlock and reverts here.\n  \"0x70f7d5e2\":\n    \"Duplicate deposit: a BTC Vault with this hashlock is already registered to your wallet. Hashlocks are derived from your BTC wallet and selected UTXOs — use different UTXOs to create a unique deposit.\",\n};\n\n/**\n * Extract error data from various error formats.\n *\n * Viem and wallet providers wrap errors in multiple levels. This function\n * searches through the error chain to find the revert data.\n *\n * @param error - The error object to extract data from\n * @returns The error data (e.g., \"0x04aabf33\") or undefined\n */\nexport function extractErrorData(error: unknown): string | undefined {\n  return walkForErrorData(error, 0);\n}\n\n/**\n * Walk an error chain looking for revert data in any of viem 2.x's known\n * shapes. Covers:\n *  - `.data: \"0x...\"` — raw revert hex (most common with `estimateGas`)\n *  - `.revertData: \"0x...\"` — alternate viem shape\n *  - `.signature: \"0x...\"` — 4-byte selector from a *decoded*\n *    ContractFunctionRevertedError (set when the ABI included the error def)\n *  - `.error.data: \"0x...\"` — RPC-level error shape from some providers\n *  - `.walk(fn)` — viem's chainable error walker (BaseError.walk)\n *  - `.cause` chain — viem wraps errors many layers deep\n *\n * Depth-limited (10) and walk-result-deduplicated so a cycle can't loop.\n */\nfunction walkForErrorData(\n  error: unknown,\n  depth: number,\n): string | undefined {\n  if (depth > 10 || !error || typeof error !== \"object\") return undefined;\n\n  const err = error as Record<string, unknown>;\n\n  if (typeof err.data === \"string\" && err.data.startsWith(\"0x\")) {\n    return err.data;\n  }\n  if (typeof err.revertData === \"string\" && err.revertData.startsWith(\"0x\")) {\n    return err.revertData;\n  }\n  if (typeof err.signature === \"string\" && err.signature.startsWith(\"0x\")) {\n    return err.signature;\n  }\n  if (typeof err.details === \"string\" && err.details.startsWith(\"0x\")) {\n    return err.details;\n  }\n\n  // RPC-level error shape (`{ error: { data: \"0x...\" } }`)\n  if (err.error && typeof err.error === \"object\") {\n    const inner = (err.error as Record<string, unknown>).data;\n    if (typeof inner === \"string\" && inner.startsWith(\"0x\")) {\n      return inner;\n    }\n  }\n\n  // Recurse through `.cause`\n  if (err.cause) {\n    const fromCause = walkForErrorData(err.cause, depth + 1);\n    if (fromCause) return fromCause;\n  }\n\n  // Use viem's `.walk()` if available\n  if (typeof err.walk === \"function\") {\n    try {\n      let found: string | undefined;\n      (err.walk as (fn: (e: unknown) => boolean) => unknown)((e) => {\n        if (e === error) return false; // avoid self-cycle\n        const data = walkForErrorData(e, depth + 1);\n        if (data) {\n          found = data;\n          return true;\n        }\n        return false;\n      });\n      if (found) return found;\n    } catch {\n      // walk failed; ignore\n    }\n  }\n\n  // Last resort: regex an embedded hex selector out of the message\n  if (depth === 0) {\n    const message = typeof err.message === \"string\" ? err.message : \"\";\n    const hexMatch = message.match(/\\b(0x[a-fA-F0-9]{8})\\b/);\n    if (hexMatch) return hexMatch[1];\n  }\n\n  return undefined;\n}\n\n/**\n * Get a user-friendly error message for a contract error.\n *\n * @param error - The error object from a contract call\n * @returns A user-friendly error message, or undefined if error is not recognized\n */\nexport function getContractErrorMessage(error: unknown): string | undefined {\n  const errorData = extractErrorData(error);\n  if (errorData) {\n    // Check exact match first, then match by 4-byte selector prefix.\n    // Parametric errors (e.g. InvalidPeginFee(uint256,uint256)) return\n    // the selector + ABI-encoded args, so the full string won't match.\n    const selector = errorData.substring(0, 10); // \"0x\" + 4 bytes\n    return CONTRACT_ERRORS[errorData] ?? CONTRACT_ERRORS[selector];\n  }\n  return undefined;\n}\n\n/**\n * Check if an error is a known contract error.\n *\n * @param error - The error object to check\n * @returns True if the error is a known contract error\n */\nexport function isKnownContractError(error: unknown): boolean {\n  const errorData = extractErrorData(error);\n  if (errorData === undefined) return false;\n  const selector = errorData.substring(0, 10);\n  return errorData in CONTRACT_ERRORS || selector in CONTRACT_ERRORS;\n}\n\n/**\n * Handle a contract error by throwing a user-friendly error.\n *\n * This function extracts error data, maps it to a user-friendly message,\n * and throws an appropriate error. Use this in catch blocks after contract calls.\n *\n * @param error - The error from a contract call\n * @throws Always throws an error with a descriptive message\n */\nexport function handleContractError(error: unknown): never {\n  // Log full error for debugging\n  console.error(\"[Contract Error] Raw error:\", error);\n\n  // Extract error data from the error chain\n  const errorData = extractErrorData(error);\n  console.error(\"[Contract Error] Extracted error data:\", errorData);\n\n  // Check for known contract error signatures (exact match or 4-byte selector prefix)\n  if (errorData) {\n    const selector = errorData.substring(0, 10);\n    const knownError = CONTRACT_ERRORS[errorData] ?? CONTRACT_ERRORS[selector];\n    if (knownError) {\n      console.error(\"[Contract Error] Known error:\", knownError);\n      throw new Error(knownError);\n    }\n  }\n\n  // Check for gas estimation errors or internal JSON-RPC errors\n  const errorMsg = (error as Error)?.message || \"\";\n  if (\n    errorMsg.includes(\"gas limit too high\") ||\n    errorMsg.includes(\"21000000\") ||\n    errorMsg.includes(\"Internal JSON-RPC error\")\n  ) {\n    // If we found error data but it's not in our known list, include it\n    const errorHint = errorData ? ` (error code: ${errorData})` : \"\";\n    console.error(\n      \"[Contract Error] Transaction rejected. Error code:\",\n      errorData,\n      \"Message:\",\n      errorMsg,\n    );\n    throw new Error(\n      `Transaction failed: The contract rejected this transaction${errorHint}. ` +\n        \"Possible causes: (1) Vault already exists for this transaction, \" +\n        \"(2) Invalid signature, (3) Unauthorized caller. \" +\n        \"Please check your transaction parameters and try again.\",\n    );\n  }\n\n  // Default: re-throw original error with better context\n  if (error instanceof Error) {\n    console.error(\"[Contract Error] Unhandled error:\", error.message);\n    throw error;\n  }\n  throw new Error(`Contract call failed: ${String(error)}`);\n}\n"],"names":["CONTRACT_ERRORS","extractErrorData","error","walkForErrorData","depth","err","inner","fromCause","found","e","data","hexMatch","getContractErrorMessage","errorData","selector","isKnownContractError","handleContractError","knownError","errorMsg","errorHint"],"mappings":"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"}