{"version":3,"file":"waitForTransactionReceiptSmartAware-AgZ-3WV_.cjs","sources":["../src/tbv/core/utils/fee/peginFeeMath.ts","../src/tbv/core/utils/utxo/selectUtxos.ts","../src/tbv/core/utils/transaction/btcTxHash.ts","../src/tbv/core/utils/btc/scriptType.ts","../src/tbv/core/utils/btc/psbtInputFields.ts","../src/tbv/core/utils/eth/waitForTransactionReceiptSmartAware.ts"],"sourcesContent":["/**\n * Pre-PegIn fee math primitives used by both UTXO selection and\n * transaction funding so they make bit-identical decisions about base\n * fee, change-output fee, and whether to emit change at all.\n *\n * Dust handling matches the wallet-side check in\n * `babylon-vault crates/btc-wallet-remote/src/client.rs` (dust-change\n * rejection): a change output is emitted only when the post-fee residual\n * exceeds DUST_THRESHOLD (546 sats). Broader fee-estimation behaviors\n * (output sizing, safety margins) are NOT cross-stack guarantees — see\n * JS-vs-Rust parity fixtures in `__tests__/peginFeeMath.test.ts` for the\n * invariants we pin.\n */\n\nimport {\n  DUST_THRESHOLD,\n  MAX_NON_LEGACY_OUTPUT_SIZE,\n  P2TR_INPUT_SIZE,\n  rateBasedTxBufferFee,\n  TX_BUFFER_SIZE_OVERHEAD,\n} from \"./constants\";\n\nexport interface ComputeBaseFeeParams {\n  numInputs: number;\n  /**\n   * Number of outputs in the unfunded transaction (HTLC vault outputs +\n   * CPFP anchor + optional auth-anchor OP_RETURN). Excludes the change\n   * output — `applyChangeOutputPolicy` adds the change-output fee\n   * separately.\n   */\n  numOutputs: number;\n  feeRate: number;\n}\n\n/**\n * Compute the base fee (sats) for a Pre-PegIn transaction with no change\n * output, including the low-fee-rate buffer.\n *\n * Used as the starting point by `applyChangeOutputPolicy`, which then\n * decides whether to add the incremental change-output fee.\n */\nexport function computePeginBaseFeeSats(\n  params: ComputeBaseFeeParams,\n): bigint {\n  const { numInputs, numOutputs, feeRate } = params;\n  if (!Number.isInteger(numInputs) || numInputs < 0) {\n    throw new Error(\n      `computePeginBaseFeeSats: numInputs must be a non-negative integer, got ${numInputs}`,\n    );\n  }\n  if (!Number.isInteger(numOutputs) || numOutputs < 1) {\n    throw new Error(\n      `computePeginBaseFeeSats: numOutputs must be a positive integer, got ${numOutputs}`,\n    );\n  }\n  const txVsize =\n    numInputs * P2TR_INPUT_SIZE +\n    numOutputs * MAX_NON_LEGACY_OUTPUT_SIZE +\n    TX_BUFFER_SIZE_OVERHEAD;\n  return (\n    BigInt(Math.ceil(txVsize * feeRate)) +\n    BigInt(rateBasedTxBufferFee(feeRate))\n  );\n}\n\n/**\n * Incremental fee (sats) for adding one P2TR-sized change output at the\n * given fee rate. Does NOT include the low-fee-rate buffer — that is part\n * of the base fee, paid once per transaction.\n */\nexport function computeChangeOutputFeeSats(feeRate: number): bigint {\n  return BigInt(Math.ceil(MAX_NON_LEGACY_OUTPUT_SIZE * feeRate));\n}\n\nexport interface ApplyChangeOutputPolicyParams {\n  totalInputValue: bigint;\n  peginAmount: bigint;\n  baseFee: bigint;\n  changeOutputFee: bigint;\n}\n\nexport interface ChangeOutputPolicyResult {\n  /** Final transaction fee (sats). */\n  fee: bigint;\n  /**\n   * Final change amount (sats). 0n when no change output is emitted.\n   * When `emitChangeOutput` is false, the would-be change is paid to\n   * miners as part of `fee` — i.e. it is dust by policy.\n   */\n  changeAmount: bigint;\n  /** Whether the funded transaction must include a change output. */\n  emitChangeOutput: boolean;\n}\n\n/**\n * Apply the change-output dust policy: emit a change output iff the\n * post-change-output-fee residual strictly exceeds DUST_THRESHOLD.\n *\n * Returns `{ fee, changeAmount, emitChangeOutput }` so the selector and\n * funder both end up with the same fee and same change decision for the\n * same inputs.\n *\n * Inputs:\n * - `totalInputValue`: sum of selected UTXO values\n * - `peginAmount`: amount being pegged in\n * - `baseFee`: fee assuming no change output (from `computePeginBaseFeeSats`)\n * - `changeOutputFee`: incremental fee for adding one change output\n *   (from `computeChangeOutputFeeSats`)\n *\n * @throws If `totalInputValue < peginAmount + baseFee` (insufficient funds\n *   even before considering change). Callers that need to surface\n *   \"insufficient funds\" with their own error wording should check the\n *   precondition themselves before invoking this.\n */\nexport function applyChangeOutputPolicy(\n  params: ApplyChangeOutputPolicyParams,\n): ChangeOutputPolicyResult {\n  const { totalInputValue, peginAmount, baseFee, changeOutputFee } = params;\n\n  const residualBeforeChange = totalInputValue - peginAmount - baseFee;\n  if (residualBeforeChange < 0n) {\n    throw new Error(\n      `applyChangeOutputPolicy: insufficient funds (need ${peginAmount + baseFee} sats, have ${totalInputValue})`,\n    );\n  }\n\n  const residualWithChangeOutput = residualBeforeChange - changeOutputFee;\n  if (residualWithChangeOutput > DUST_THRESHOLD) {\n    return {\n      fee: baseFee + changeOutputFee,\n      changeAmount: residualWithChangeOutput,\n      emitChangeOutput: true,\n    };\n  }\n\n  // Dust-revert: the would-be change is below (or equal to) the dust\n  // threshold once the change-output fee is paid, so we omit the change\n  // output and let the residual go to miners. The reported `fee` is the\n  // ACTUAL on-wire fee — `baseFee + residualBeforeChange` — not just\n  // `baseFee`, otherwise fee displays would under-report by up to\n  // (changeOutputFee + DUST_THRESHOLD) sats whenever dust gets absorbed.\n  return {\n    fee: baseFee + residualBeforeChange,\n    changeAmount: 0n,\n    emitChangeOutput: false,\n  };\n}\n\nexport interface ComputeMaxDepositParams {\n  numInputs: number;\n  /**\n   * Number of outputs in the unfunded transaction. Use the worst-case\n   * count for the use case being budgeted (e.g. max-batch with\n   * auth-anchor) — `computeMaxDeposit` is intentionally an UPPER BOUND\n   * and assumes no change output.\n   */\n  numOutputs: number;\n  totalBalance: bigint;\n  feeRate: number;\n}\n\n/**\n * Compute the maximum depositable amount (sats) given a fixed-cost\n * sweep: every UTXO is spent, no change output is emitted, fee is the\n * base fee for the requested input/output count.\n *\n * Returns null when `totalBalance <= 0n`. Returns 0n if the base fee\n * alone exceeds the balance.\n */\nexport function computeMaxDeposit(\n  params: ComputeMaxDepositParams,\n): bigint | null {\n  const { numInputs, numOutputs, totalBalance, feeRate } = params;\n  if (totalBalance <= 0n) return null;\n  const fee = computePeginBaseFeeSats({ numInputs, numOutputs, feeRate });\n  const max = totalBalance - fee;\n  return max > 0n ? max : 0n;\n}\n","/**\n * UTXO selection utilities for peg-in transactions.\n * Follows btc-staking-ts methodology with iterative fee calculation.\n */\n\nimport { script as bitcoinScript } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport { BTC_DUST_SAT, DUST_THRESHOLD } from \"../fee/constants\";\nimport {\n  applyChangeOutputPolicy,\n  computeChangeOutputFeeSats,\n  computePeginBaseFeeSats,\n} from \"../fee/peginFeeMath\";\n\n/**\n * Unspent Transaction Output (UTXO) for funding peg-in transactions.\n */\nexport interface UTXO {\n  /**\n   * Transaction ID of the UTXO (64-char hex without 0x prefix).\n   */\n  txid: string;\n\n  /**\n   * Output index within the transaction.\n   */\n  vout: number;\n\n  /**\n   * Value in satoshis.\n   */\n  value: number;\n\n  /**\n   * Script public key hex.\n   */\n  scriptPubKey: string;\n}\n\nexport interface UTXOSelectionResult {\n  selectedUTXOs: UTXO[];\n  totalValue: bigint;\n  fee: bigint;\n  changeAmount: bigint;\n}\n\n/**\n * Assert that no two UTXOs share the same txid:vout outpoint.\n * Duplicates from a buggy or compromised UTXO source would produce\n * an invalid Bitcoin transaction that double-spends the same outpoint.\n */\nfunction assertNoDuplicateUtxos(utxos: UTXO[]): void {\n  const seen = new Set<string>();\n  for (const utxo of utxos) {\n    const key = `${utxo.txid.toLowerCase()}:${utxo.vout}`;\n    if (seen.has(key)) {\n      throw new Error(\n        `Duplicate UTXO detected: ${utxo.txid}:${utxo.vout}. ` +\n          `This indicates a data integrity issue with the UTXO source.`,\n      );\n    }\n    seen.add(key);\n  }\n}\n\n/**\n * Selects UTXOs to fund a peg-in transaction with iterative fee calculation.\n *\n * This function implements the btc-staking-ts approach:\n * 1. Filter UTXOs for script validity (no minimum value filter)\n * 2. Sort by value (largest first) to minimize number of inputs\n * 3. Iteratively add UTXOs and recalculate fee until we have enough\n *\n * The fee recalculation is critical because:\n * - Each UTXO added increases transaction size → increases fee\n * - More fee needed might require another UTXO\n * - Change output detection affects fee (adds output size if needed)\n *\n * @param availableUTXOs - All available UTXOs from wallet\n * @param peginAmount - Amount to peg in (satoshis)\n * @param feeRate - Fee rate (sat/vbyte)\n * @param numOutputs - Number of outputs in the unfunded transaction (HTLC + CPFP anchor, before change)\n * @returns Selected UTXOs, total value, calculated fee, and change amount\n * @throws Error if insufficient funds or no valid UTXOs\n */\nexport function selectUtxosForPegin(\n  availableUTXOs: UTXO[],\n  peginAmount: bigint,\n  feeRate: number,\n  numOutputs: number,\n): UTXOSelectionResult {\n  if (!Number.isInteger(numOutputs) || numOutputs < 1) {\n    throw new Error(\n      `Invalid numOutputs: expected a positive integer, got ${numOutputs}`,\n    );\n  }\n\n  if (availableUTXOs.length === 0) {\n    throw new Error(\"Insufficient funds: no UTXOs available\");\n  }\n\n  assertNoDuplicateUtxos(availableUTXOs);\n\n  // Filter for script validity ONLY (matching btc-staking-ts approach)\n  // No minimum value filter - we accept any UTXO with valid script\n  const validUTXOs = availableUTXOs.filter((utxo) => {\n    const script = Buffer.from(utxo.scriptPubKey, \"hex\");\n    const decompiledScript = bitcoinScript.decompile(script);\n    return !!decompiledScript;\n  });\n\n  if (validUTXOs.length === 0) {\n    throw new Error(\n      \"Insufficient funds: no valid UTXOs available (all have invalid scripts)\",\n    );\n  }\n\n  // Sort by value: HIGHEST to LOWEST (use big UTXOs first)\n  // Use spread to avoid mutating the original array\n  const sortedUTXOs = [...validUTXOs].sort((a, b) => b.value - a.value);\n\n  const selectedUTXOs: UTXO[] = [];\n  let accumulatedValue = 0n;\n  let estimatedFee = 0n;\n\n  // Iteratively select UTXOs, recalculating the fee through the shared\n  // `applyChangeOutputPolicy` helper so the selector and the funder\n  // agree on (fee, change output emission, change amount) for the same\n  // inputs. Without that, the funder can omit a change output the\n  // selector charged for — silent depositor overpayment at the dust\n  // boundary.\n  for (const utxo of sortedUTXOs) {\n    selectedUTXOs.push(utxo);\n    accumulatedValue += BigInt(utxo.value);\n\n    const baseFee = computePeginBaseFeeSats({\n      numInputs: selectedUTXOs.length,\n      numOutputs,\n      feeRate,\n    });\n    const changeOutputFee = computeChangeOutputFeeSats(feeRate);\n\n    if (accumulatedValue < peginAmount + baseFee) {\n      estimatedFee = baseFee;\n      continue;\n    }\n\n    const policy = applyChangeOutputPolicy({\n      totalInputValue: accumulatedValue,\n      peginAmount,\n      baseFee,\n      changeOutputFee,\n    });\n\n    return {\n      selectedUTXOs,\n      totalValue: accumulatedValue,\n      fee: policy.fee,\n      changeAmount: policy.changeAmount,\n    };\n  }\n\n  // If we get here, we don't have enough funds\n  throw new Error(\n    `Insufficient funds: need ${peginAmount + estimatedFee} sats (${peginAmount} pegin + ${estimatedFee} fee), have ${accumulatedValue} sats`,\n  );\n}\n\n/**\n * Checks if change amount is above dust threshold.\n *\n * @param changeAmount - Change amount in satoshis\n * @returns true if change should be added as output, false if it should go to miners\n */\nexport function shouldAddChangeOutput(changeAmount: bigint): boolean {\n  return changeAmount > DUST_THRESHOLD;\n}\n\n/**\n * Gets the dust threshold value.\n *\n * @returns Dust threshold in satoshis\n */\nexport function getDustThreshold(): number {\n  return BTC_DUST_SAT;\n}\n","/**\n * Bitcoin Transaction Hash Utilities\n *\n * Provides utilities for calculating Bitcoin transaction hashes in a way that matches\n * the contract's BtcUtils.hashBtcTx() implementation.\n */\n\nimport { Transaction } from \"bitcoinjs-lib\";\nimport type { Hex } from \"viem\";\n\n/**\n * Calculate Bitcoin transaction hash\n *\n * This matches the contract's BtcUtils.hashBtcTx() implementation:\n * 1. Double SHA256 the transaction bytes\n * 2. Reverse the byte order (Bitcoin convention)\n *\n * The resulting hash is used as the unique vault identifier in the BTCVaultRegistry contract.\n *\n * @param txHex - Transaction hex (with or without 0x prefix)\n * @returns The transaction hash as Hex (with 0x prefix)\n */\nexport function calculateBtcTxHash(txHex: string): Hex {\n  // Remove 0x prefix if present\n  const cleanHex = txHex.startsWith(\"0x\") ? txHex.slice(2) : txHex;\n\n  // Use bitcoinjs-lib to calculate transaction ID (already does double SHA256 + reverse)\n  const tx = Transaction.fromHex(cleanHex);\n  const txid = tx.getId();\n\n  // Return with 0x prefix to match Ethereum hex format\n  return `0x${txid}` as Hex;\n}\n","/**\n * Bitcoin Script Type Detection\n *\n * Utilities to detect Bitcoin script types for proper PSBT input construction.\n *\n * @module utils/btc/scriptType\n */\n\n/**\n * Bitcoin script types.\n */\nexport enum BitcoinScriptType {\n  P2PKH = \"P2PKH\",\n  P2SH = \"P2SH\",\n  P2WPKH = \"P2WPKH\",\n  P2WSH = \"P2WSH\",\n  P2TR = \"P2TR\",\n  UNKNOWN = \"UNKNOWN\",\n}\n\n/**\n * Detect the type of a Bitcoin script.\n *\n * @param scriptPubKey - The script public key buffer\n * @returns The detected script type\n *\n * @example\n * ```typescript\n * const scriptType = getScriptType(Buffer.from(scriptPubKeyHex, 'hex'));\n * if (scriptType === BitcoinScriptType.P2TR) {\n *   // Handle Taproot input\n * }\n * ```\n */\nexport function getScriptType(scriptPubKey: Buffer): BitcoinScriptType {\n  const length = scriptPubKey.length;\n\n  // P2PKH: OP_DUP OP_HASH160 <20 bytes> OP_EQUALVERIFY OP_CHECKSIG (25 bytes)\n  if (\n    length === 25 &&\n    scriptPubKey[0] === 0x76 && // OP_DUP\n    scriptPubKey[1] === 0xa9 && // OP_HASH160\n    scriptPubKey[2] === 0x14 && // Push 20 bytes\n    scriptPubKey[23] === 0x88 && // OP_EQUALVERIFY\n    scriptPubKey[24] === 0xac // OP_CHECKSIG\n  ) {\n    return BitcoinScriptType.P2PKH;\n  }\n\n  // P2SH: OP_HASH160 <20 bytes> OP_EQUAL (23 bytes)\n  if (\n    length === 23 &&\n    scriptPubKey[0] === 0xa9 && // OP_HASH160\n    scriptPubKey[1] === 0x14 && // Push 20 bytes\n    scriptPubKey[22] === 0x87 // OP_EQUAL\n  ) {\n    return BitcoinScriptType.P2SH;\n  }\n\n  // P2WPKH: OP_0 <20 bytes> (22 bytes)\n  if (\n    length === 22 &&\n    scriptPubKey[0] === 0x00 && // OP_0\n    scriptPubKey[1] === 0x14 // Push 20 bytes\n  ) {\n    return BitcoinScriptType.P2WPKH;\n  }\n\n  // P2WSH: OP_0 <32 bytes> (34 bytes)\n  if (\n    length === 34 &&\n    scriptPubKey[0] === 0x00 && // OP_0\n    scriptPubKey[1] === 0x20 // Push 32 bytes\n  ) {\n    return BitcoinScriptType.P2WSH;\n  }\n\n  // P2TR (Taproot): OP_1 <32 bytes> (34 bytes)\n  if (\n    length === 34 &&\n    scriptPubKey[0] === 0x51 && // OP_1\n    scriptPubKey[1] === 0x20 // Push 32 bytes\n  ) {\n    return BitcoinScriptType.P2TR;\n  }\n\n  return BitcoinScriptType.UNKNOWN;\n}\n\n","/**\n * PSBT Input Field Construction\n *\n * Constructs the correct PSBT input fields for a given UTXO based on its script type.\n *\n * @module utils/btc/psbtInputFields\n */\n\nimport { Buffer } from \"buffer\";\n\nimport { BitcoinScriptType, getScriptType } from \"./scriptType\";\n\n/**\n * PSBT input fields for supported script types (P2TR, P2WPKH, P2WSH).\n */\nexport interface PsbtInputFields {\n  witnessUtxo?: {\n    script: Buffer;\n    value: number;\n  };\n  witnessScript?: Buffer;\n  tapInternalKey?: Buffer;\n}\n\n/**\n * UTXO information for PSBT construction.\n *\n * Only supports Taproot (P2TR) and native SegWit (P2WPKH, P2WSH) script types.\n */\nexport interface UtxoForPsbt {\n  /** Transaction ID of the UTXO */\n  txid: string;\n  /** Output index (vout) of the UTXO */\n  vout: number;\n  /** Value of the UTXO in satoshis */\n  value: number;\n  /** ScriptPubKey of the UTXO (hex string) */\n  scriptPubKey: string;\n  /** Witness script (required for P2WSH) */\n  witnessScript?: string;\n}\n\n/**\n * Get PSBT input fields for a given UTXO based on its script type.\n *\n * Only supports Taproot (P2TR) and native SegWit (P2WPKH, P2WSH) script types.\n *\n * @param utxo - The unspent transaction output to process\n * @param publicKeyNoCoord - The x-only public key (32 bytes) for Taproot signing\n * @returns PSBT input fields object containing the necessary data\n * @throws Error if required input data is missing or unsupported script type\n */\nexport function getPsbtInputFields(\n  utxo: UtxoForPsbt,\n  publicKeyNoCoord?: Buffer,\n): PsbtInputFields {\n  const scriptPubKey = Buffer.from(utxo.scriptPubKey, \"hex\");\n  const type = getScriptType(scriptPubKey);\n\n  switch (type) {\n    case BitcoinScriptType.P2WPKH: {\n      return {\n        witnessUtxo: {\n          script: scriptPubKey,\n          value: utxo.value,\n        },\n      };\n    }\n\n    case BitcoinScriptType.P2WSH: {\n      if (!utxo.witnessScript) {\n        throw new Error(\"Missing witnessScript for P2WSH input\");\n      }\n      return {\n        witnessUtxo: {\n          script: scriptPubKey,\n          value: utxo.value,\n        },\n        witnessScript: Buffer.from(utxo.witnessScript, \"hex\"),\n      };\n    }\n\n    case BitcoinScriptType.P2TR: {\n      if (publicKeyNoCoord && publicKeyNoCoord.length !== 32) {\n        throw new Error(\n          `Invalid tapInternalKey length: expected 32 bytes, got ${publicKeyNoCoord.length}`,\n        );\n      }\n      return {\n        witnessUtxo: {\n          script: scriptPubKey,\n          value: utxo.value,\n        },\n        // tapInternalKey is needed for Taproot signing\n        ...(publicKeyNoCoord && { tapInternalKey: publicKeyNoCoord }),\n      };\n    }\n\n    default:\n      throw new Error(`Unsupported script type: ${type}`);\n  }\n}\n\n","/**\n * Smart-account-aware wrapper around viem's `waitForTransactionReceipt`.\n *\n * Externally Owned Accounts (EOAs) — wallets controlled by a single private\n * key, e.g. MetaMask or a hardware wallet. `eth_sendTransaction` returns a real\n * Ethereum tx hash, which viem can poll directly. This wrapper detects an EOA\n * via `eth_getCode` returning empty bytecode and delegates unchanged.\n *\n * Smart-contract accounts (e.g. Safe multisigs) — the wallet address is a\n * deployed contract that decides whether to accept a transaction. WalletConnect's\n * `eth_sendTransaction` returns a `safeTxHash` (an EIP-712 hash of the\n * *proposal*) rather than a real tx hash, and the proposal is held in Safe's\n * off-chain Transaction Service until quorum signs and executes it. We poll\n * that service for the proposal until execution, then wait for receipt on the\n * real Ethereum tx hash exposed in the service's response.\n *\n * @module utils/eth\n */\n\nimport type {\n  Address,\n  Hash,\n  PublicClient,\n  TransactionReceipt,\n} from \"viem\";\n\n/**\n * Chains where the Safe Transaction Service is supported by this utility.\n * Extend the map as more Safe-enabled chains are needed.\n */\nconst SAFE_TX_SERVICE_BASE_URLS: Record<number, string> = {\n  1: \"https://safe-transaction-mainnet.safe.global\",\n  11155111: \"https://safe-transaction-sepolia.safe.global\",\n};\n\nconst DEFAULT_SAFE_POLL_INTERVAL_MS = 5_000;\nconst DEFAULT_SAFE_POLL_TIMEOUT_MS = 4 * 60 * 60 * 1_000;\nconst SAFE_TX_SERVICE_FETCH_TIMEOUT_MS = 10_000;\n\nexport interface WaitForTransactionReceiptSmartAwareParams {\n  publicClient: PublicClient;\n  walletAddress: Address;\n  hash: Hash;\n  /**\n   * Forwarded to viem verbatim.\n   *\n   * MUST NOT be used as a finality/reorg gate. viem fetches the receipt once\n   * and then only compares block numbers against that cached copy — it never\n   * re-checks that the receipt's block is still canonical, so it resolves\n   * happily for a transaction that has been reorged out. Setting this buys a\n   * delay, not a guarantee. For peg-in registration finality use\n   * `waitForPeginRegistrationDepth`, which re-reads live contract state on\n   * every poll.\n   */\n  confirmations?: number;\n  /**\n   * Forwarded to viem on the EOA (externally owned account) path.\n   * Ignored on the smart-account path — see safePollTimeoutMs.\n   */\n  timeout?: number;\n  /** Total budget for waiting on Safe quorum + execution. Default 4h. */\n  safePollTimeoutMs?: number;\n  /** Poll cadence against the Safe Transaction Service. Default 5s. */\n  safePollIntervalMs?: number;\n}\n\nexport async function waitForTransactionReceiptSmartAware(\n  params: WaitForTransactionReceiptSmartAwareParams,\n): Promise<TransactionReceipt> {\n  const {\n    publicClient,\n    walletAddress,\n    hash,\n    confirmations,\n    timeout,\n    safePollTimeoutMs = DEFAULT_SAFE_POLL_TIMEOUT_MS,\n    safePollIntervalMs = DEFAULT_SAFE_POLL_INTERVAL_MS,\n  } = params;\n\n  const code = await publicClient.getCode({ address: walletAddress });\n  const isSmartAccount = code !== undefined && code !== \"0x\";\n\n  if (!isSmartAccount) {\n    return publicClient.waitForTransactionReceipt({\n      hash,\n      confirmations,\n      timeout,\n    });\n  }\n\n  const chainId = await publicClient.getChainId();\n  const realTxHash = await pollSafeTransactionServiceUntilExecuted({\n    chainId,\n    safeTxHash: hash,\n    pollIntervalMs: safePollIntervalMs,\n    timeoutMs: safePollTimeoutMs,\n  });\n\n  return publicClient.waitForTransactionReceipt({\n    hash: realTxHash,\n    confirmations,\n  });\n}\n\ninterface SafeMultisigTransaction {\n  isExecuted: boolean;\n  isSuccessful: boolean | null;\n  transactionHash: Hash | null;\n}\n\nasync function pollSafeTransactionServiceUntilExecuted({\n  chainId,\n  safeTxHash,\n  pollIntervalMs,\n  timeoutMs,\n}: {\n  chainId: number;\n  safeTxHash: Hash;\n  pollIntervalMs: number;\n  timeoutMs: number;\n}): Promise<Hash> {\n  const baseUrl = SAFE_TX_SERVICE_BASE_URLS[chainId];\n  if (!baseUrl) {\n    throw new Error(\n      `Safe Transaction Service not configured for chainId ${chainId}. ` +\n        `Connected wallet appears to be a smart-contract account, but this ` +\n        `chain is not in the supported list. Either connect an EOA or extend ` +\n        `SAFE_TX_SERVICE_BASE_URLS in waitForTransactionReceiptSmartAware.ts.`,\n    );\n  }\n\n  const url = `${baseUrl}/api/v1/multisig-transactions/${safeTxHash}/`;\n  const deadline = Date.now() + timeoutMs;\n\n  while (Date.now() < deadline) {\n    const controller = new AbortController();\n    const fetchTimeoutId = setTimeout(\n      () => controller.abort(),\n      SAFE_TX_SERVICE_FETCH_TIMEOUT_MS,\n    );\n\n    let response: Response;\n    try {\n      response = await fetch(url, { signal: controller.signal });\n    } catch (err) {\n      // Transient failure (AbortError on per-request timeout, DNS hiccup,\n      // connection reset, etc.). Log and continue to the next poll iteration\n      // instead of consuming the entire safePollTimeoutMs budget on one blip.\n      // The outer `while (Date.now() < deadline)` is what enforces the overall\n      // budget; this catch deliberately preserves it.\n      console.warn(\n        `Safe Transaction Service request failed (will retry in ${pollIntervalMs}ms): ` +\n          (err instanceof Error ? err.message : String(err)),\n      );\n      await sleep(pollIntervalMs);\n      continue;\n    } finally {\n      clearTimeout(fetchTimeoutId);\n    }\n\n    if (response.ok) {\n      const data = (await response.json()) as SafeMultisigTransaction;\n      if (data.isExecuted) {\n        if (data.isSuccessful === false) {\n          throw new Error(\n            `Safe transaction ${safeTxHash} was executed on chain but reverted. ` +\n              `Check the Safe queue UI for details.`,\n          );\n        }\n        if (data.transactionHash) {\n          return data.transactionHash;\n        }\n      }\n    } else if (response.status === 404) {\n      // Proposal not yet indexed — keep polling silently.\n    } else if (response.status >= 500) {\n      // Transient server error — same treatment as a hung connection: log and retry.\n      console.warn(\n        `Safe Transaction Service returned ${response.status} for ${safeTxHash}; retrying in ${pollIntervalMs}ms.`,\n      );\n    } else {\n      // Other 4xx (403, 410, etc.) is likely permanent — surface immediately.\n      throw new Error(\n        `Safe Transaction Service returned ${response.status} for ${safeTxHash}.`,\n      );\n    }\n\n    await sleep(pollIntervalMs);\n  }\n\n  throw new Error(\n    `Timed out after ${timeoutMs}ms waiting for Safe transaction ${safeTxHash} ` +\n      `to reach quorum and execute. The proposal is still pending in the Safe ` +\n      `queue — co-signers must sign and execute it before the dApp can proceed.`,\n  );\n}\n\nfunction sleep(ms: number): Promise<void> {\n  return new Promise((resolve) => {\n    setTimeout(resolve, ms);\n  });\n}\n"],"names":["computePeginBaseFeeSats","params","numInputs","numOutputs","feeRate","txVsize","P2TR_INPUT_SIZE","MAX_NON_LEGACY_OUTPUT_SIZE","TX_BUFFER_SIZE_OVERHEAD","rateBasedTxBufferFee","computeChangeOutputFeeSats","applyChangeOutputPolicy","totalInputValue","peginAmount","baseFee","changeOutputFee","residualBeforeChange","residualWithChangeOutput","DUST_THRESHOLD","computeMaxDeposit","totalBalance","fee","max","assertNoDuplicateUtxos","utxos","seen","utxo","key","selectUtxosForPegin","availableUTXOs","validUTXOs","script","Buffer","bitcoinScript","sortedUTXOs","a","b","selectedUTXOs","accumulatedValue","estimatedFee","policy","shouldAddChangeOutput","changeAmount","getDustThreshold","BTC_DUST_SAT","calculateBtcTxHash","txHex","cleanHex","Transaction","BitcoinScriptType","getScriptType","scriptPubKey","length","getPsbtInputFields","publicKeyNoCoord","type","SAFE_TX_SERVICE_BASE_URLS","DEFAULT_SAFE_POLL_INTERVAL_MS","DEFAULT_SAFE_POLL_TIMEOUT_MS","SAFE_TX_SERVICE_FETCH_TIMEOUT_MS","waitForTransactionReceiptSmartAware","publicClient","walletAddress","hash","confirmations","timeout","safePollTimeoutMs","safePollIntervalMs","code","chainId","realTxHash","pollSafeTransactionServiceUntilExecuted","safeTxHash","pollIntervalMs","timeoutMs","baseUrl","url","deadline","controller","fetchTimeoutId","response","err","sleep","data","ms","resolve"],"mappings":"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"}