@babylonlabs-io/ts-sdk 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{PayoutManager-BkOfdb2_.js → PayoutManager-BK1jKgL5.js} +405 -364
- package/dist/PayoutManager-BK1jKgL5.js.map +1 -0
- package/dist/PayoutManager-CzKMN6xT.cjs +2 -0
- package/dist/PayoutManager-CzKMN6xT.cjs.map +1 -0
- package/dist/challengeAssert-DOa5L0kv.cjs +2 -0
- package/dist/challengeAssert-DOa5L0kv.cjs.map +1 -0
- package/dist/challengeAssert-Dvcg38_y.js +606 -0
- package/dist/challengeAssert-Dvcg38_y.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +62 -58
- package/dist/tbv/core/contracts/abis/BTCVaultsManager.abi.d.ts +50 -4
- package/dist/tbv/core/contracts/abis/BTCVaultsManager.abi.d.ts.map +1 -1
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.js +62 -58
- package/dist/tbv/core/managers/PeginManager.d.ts +89 -48
- package/dist/tbv/core/managers/PeginManager.d.ts.map +1 -1
- package/dist/tbv/core/managers/__tests__/PeginManager.test.d.ts +1 -1
- package/dist/tbv/core/managers/index.d.ts +4 -4
- package/dist/tbv/core/managers/index.d.ts.map +1 -1
- package/dist/tbv/core/primitives/index.cjs +1 -1
- package/dist/tbv/core/primitives/index.d.ts +5 -3
- package/dist/tbv/core/primitives/index.d.ts.map +1 -1
- package/dist/tbv/core/primitives/index.js +22 -18
- package/dist/tbv/core/primitives/psbt/__tests__/pegin.test.d.ts +1 -1
- package/dist/tbv/core/primitives/psbt/index.d.ts +8 -3
- package/dist/tbv/core/primitives/psbt/index.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/pegin.d.ts +76 -59
- package/dist/tbv/core/primitives/psbt/pegin.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/peginInput.d.ts +69 -0
- package/dist/tbv/core/primitives/psbt/peginInput.d.ts.map +1 -0
- package/dist/tbv/core/primitives/utils/bitcoin.d.ts +11 -0
- package/dist/tbv/core/primitives/utils/bitcoin.d.ts.map +1 -1
- package/dist/tbv/core/primitives/utils/index.d.ts +1 -1
- package/dist/tbv/core/primitives/utils/index.d.ts.map +1 -1
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +62 -58
- package/dist/tbv/integrations/aave/clients/abis/AaveIntegrationController.abi.json.d.ts +16 -1
- package/dist/tbv/integrations/aave/index.cjs +1 -1
- package/dist/tbv/integrations/aave/index.cjs.map +1 -1
- package/dist/tbv/integrations/aave/index.js +3 -3
- package/package.json +3 -3
- package/dist/PayoutManager-BkOfdb2_.js.map +0 -1
- package/dist/PayoutManager-DZ7EIcAJ.cjs +0 -2
- package/dist/PayoutManager-DZ7EIcAJ.cjs.map +0 -1
- package/dist/challengeAssert-34HqeVFH.cjs +0 -2
- package/dist/challengeAssert-34HqeVFH.cjs.map +0 -1
- package/dist/challengeAssert-DVErOd8l.js +0 -423
- package/dist/challengeAssert-DVErOd8l.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PayoutManager-CzKMN6xT.cjs","sources":["../src/tbv/core/utils/utxo/selectUtxos.ts","../src/tbv/core/utils/transaction/btcTxHash.ts","../src/tbv/core/utils/transaction/createSplitTransaction.ts","../src/tbv/core/utils/btc/scriptType.ts","../src/tbv/core/utils/btc/psbtInputFields.ts","../src/tbv/core/clients/mempool/mempoolApi.ts","../src/tbv/core/contracts/abis/BTCVaultsManager.abi.ts","../src/tbv/core/contracts/errors.ts","../src/tbv/core/managers/PeginManager.ts","../src/tbv/core/managers/PayoutManager.ts"],"sourcesContent":["/**\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 {\n BTC_DUST_SAT,\n DUST_THRESHOLD,\n MAX_NON_LEGACY_OUTPUT_SIZE,\n P2TR_INPUT_SIZE,\n rateBasedTxBufferFee,\n TX_BUFFER_SIZE_OVERHEAD,\n} from \"../fee/constants\";\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 * 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 * @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): UTXOSelectionResult {\n if (availableUTXOs.length === 0) {\n throw new Error(\"Insufficient funds: no UTXOs available\");\n }\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 and recalculate fee\n for (const utxo of sortedUTXOs) {\n selectedUTXOs.push(utxo);\n accumulatedValue += BigInt(utxo.value);\n\n // Recalculate fee based on CURRENT number of inputs\n const inputSize = selectedUTXOs.length * P2TR_INPUT_SIZE;\n const outputSize = 2 * MAX_NON_LEGACY_OUTPUT_SIZE; // vault + depositor claim outputs\n const baseTxSize = inputSize + outputSize + TX_BUFFER_SIZE_OVERHEAD;\n\n // Calculate base fee with buffer\n estimatedFee =\n BigInt(Math.ceil(baseTxSize * feeRate)) +\n BigInt(rateBasedTxBufferFee(feeRate));\n\n // Check if there will be change left after pegin amount and fee\n const changeAmount = accumulatedValue - peginAmount - estimatedFee;\n\n // If change is above dust, add fee for change output\n if (changeAmount > DUST_THRESHOLD) {\n const changeOutputFee = BigInt(\n Math.ceil(MAX_NON_LEGACY_OUTPUT_SIZE * feeRate),\n );\n estimatedFee += changeOutputFee;\n }\n\n // Check if we have enough to cover pegin amount + fees\n if (accumulatedValue >= peginAmount + estimatedFee) {\n // Success! We have enough funds\n const finalChangeAmount = accumulatedValue - peginAmount - estimatedFee;\n\n return {\n selectedUTXOs,\n totalValue: accumulatedValue,\n fee: estimatedFee,\n changeAmount: finalChangeAmount,\n };\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 BTCVaultsManager 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 * UTXO Split Transaction Builder\n *\n * Creates Bitcoin transactions that split input UTXOs into multiple outputs.\n * Used for multi-vault peg-in flow when user doesn't have enough separate UTXOs.\n *\n * Transaction Flow:\n * 1. createSplitTransaction() → unsigned transaction with deterministic txid\n * 2. createSplitTransactionPsbt() → PSBT ready for wallet signing\n * 3. Wallet signs PSBT → signed transaction\n * 4. Broadcast to Bitcoin network → outputs become available for pegin transactions\n *\n * @module utils/transaction/createSplitTransaction\n */\n\nimport { address as bitcoinAddress, Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport type { Network } from \"../../primitives\";\nimport type { UTXO } from \"../utxo/selectUtxos\";\n\nimport { getNetwork } from \"./fundPeginTransaction\";\n\n/**\n * Output specification for split transaction.\n */\nexport interface SplitOutput {\n /** Amount in satoshis */\n amount: bigint;\n /** Bitcoin address to send to */\n address: string;\n}\n\n/**\n * Result of creating a split transaction.\n */\nexport interface SplitTransactionResult {\n /** Unsigned transaction hex */\n txHex: string;\n /** Transaction ID (deterministic, calculated before signing) */\n txid: string;\n /** Output UTXOs that will be created when transaction is broadcast */\n outputs: Array<{\n /** Transaction ID of this output */\n txid: string;\n /** Output index */\n vout: number;\n /** Amount in satoshis */\n value: number;\n /** Script pubkey hex */\n scriptPubKey: string;\n }>;\n}\n\n/**\n * Create a UTXO split transaction.\n *\n * This function creates a Bitcoin transaction that takes input UTXOs\n * and splits them into multiple outputs with specified amounts.\n *\n * The transaction is returned unsigned. The caller must:\n * 1. Sign the transaction using a Bitcoin wallet\n * 2. Broadcast it to the Bitcoin network\n * 3. Use the output UTXOs for subsequent peg-in transactions\n *\n * @param inputs - Input UTXOs to split\n * @param outputs - Desired output amounts and addresses\n * @param network - Bitcoin network (mainnet, testnet, signet, regtest)\n * @returns Unsigned transaction hex, txid, and output UTXO references\n * @throws Error if inputs or outputs are empty\n * @throws Error if address decoding fails (invalid address for network)\n *\n * @example\n * ```typescript\n * const result = createSplitTransaction(\n * [{ txid: \"abc...\", vout: 0, value: 100000, scriptPubKey: \"...\" }],\n * [\n * { amount: 50000n, address: \"tb1p...\" },\n * { amount: 45000n, address: \"tb1p...\" }\n * ],\n * \"testnet\"\n * );\n * // result.txHex → unsigned transaction\n * // result.txid → deterministic transaction ID\n * // result.outputs → UTXO references for pegin creation\n * ```\n */\nexport function createSplitTransaction(\n inputs: UTXO[],\n outputs: SplitOutput[],\n network: Network,\n): SplitTransactionResult {\n // Validate inputs\n if (inputs.length === 0) {\n throw new Error(\"No input UTXOs provided for split transaction\");\n }\n\n if (outputs.length === 0) {\n throw new Error(\"No outputs specified for split transaction\");\n }\n\n // Validate all output amounts are positive\n for (const output of outputs) {\n if (output.amount <= 0n) {\n throw new Error(\n `Invalid output amount for ${output.address}: ${output.amount} satoshis. ` +\n `Amount must be greater than zero.`,\n );\n }\n }\n\n // Get bitcoinjs-lib network\n const btcNetwork = getNetwork(network);\n\n // Create transaction with BIP 68/112/113 compatibility\n const tx = new Transaction();\n tx.version = 2;\n\n // Add inputs\n for (const input of inputs) {\n // Bitcoin uses reversed byte order for txid\n const txidBuffer = Buffer.from(input.txid, \"hex\").reverse();\n tx.addInput(txidBuffer, input.vout);\n }\n\n // Add outputs\n const outputUtxos: SplitTransactionResult[\"outputs\"] = [];\n\n for (let i = 0; i < outputs.length; i++) {\n const output = outputs[i];\n\n // Decode address to get script pubkey\n let outputScript: Buffer;\n try {\n const decoded = bitcoinAddress.toOutputScript(output.address, btcNetwork);\n outputScript = decoded;\n } catch (error) {\n throw new Error(\n `Failed to decode address \"${output.address}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n\n tx.addOutput(outputScript, Number(output.amount));\n\n // Store output UTXO reference (will be created when tx is broadcast)\n outputUtxos.push({\n txid: \"\", // Will be set after txid calculation\n vout: i,\n value: Number(output.amount),\n scriptPubKey: outputScript.toString(\"hex\"),\n });\n }\n\n // Get unsigned transaction hex\n const txHex = tx.toHex();\n\n // Calculate txid (this is deterministic for unsigned transactions)\n const txid = tx.getId();\n\n // Update output UTXO txids\n for (const output of outputUtxos) {\n output.txid = txid;\n }\n\n return {\n txHex,\n txid,\n outputs: outputUtxos,\n };\n}\n\n/**\n * Create a PSBT for signing a split transaction with Taproot inputs.\n *\n * IMPORTANT: This function assumes ALL inputs are P2TR (Taproot) addresses.\n * It unconditionally adds tapInternalKey for Taproot signing. Using non-P2TR\n * inputs will cause wallet signing failures.\n *\n * This function takes an unsigned split transaction and creates a PSBT\n * that is intended to be signed by a Bitcoin wallet; this function does not\n * perform any signing itself.\n *\n * The PSBT includes:\n * - witnessUtxo: Script and value for each input (required for segwit)\n * - tapInternalKey: Depositor's x-only pubkey (required for P2TR signing)\n *\n * Technical Note:\n * For P2TR (Taproot) inputs, we need the witnessUtxo and tapInternalKey.\n * This is different from legacy inputs which would need the full previous transaction.\n *\n * @param unsignedTxHex - Unsigned transaction hex from createSplitTransaction\n * @param inputs - Input UTXOs with full data for PSBT\n * @param publicKeyNoCoord - Depositor's public key (x-only, 32 bytes) for P2TR signing\n * @returns PSBT hex ready for wallet signing\n * @throws Error if publicKeyNoCoord is not a 32-byte Buffer\n * @throws Error if UTXO count doesn't match transaction inputs\n * @throws Error if any input is not P2TR format\n *\n * @example\n * ```typescript\n * const psbtHex = createSplitTransactionPsbt(\n * result.txHex,\n * inputUtxos,\n * Buffer.from(depositorPubkeyXOnly, \"hex\")\n * );\n * // Sign via wallet\n * const signedPsbtHex = await wallet.signPsbt(psbtHex);\n * ```\n */\nexport function createSplitTransactionPsbt(\n unsignedTxHex: string,\n inputs: UTXO[],\n publicKeyNoCoord: Buffer,\n): string {\n const tx = Transaction.fromHex(unsignedTxHex);\n const psbt = new Psbt();\n\n psbt.setVersion(tx.version);\n psbt.setLocktime(tx.locktime);\n\n // Validate tapInternalKey is a 32-byte x-only public key\n if (!Buffer.isBuffer(publicKeyNoCoord) || publicKeyNoCoord.length !== 32) {\n throw new Error(\n `Invalid publicKeyNoCoord: expected 32-byte Buffer (x-only pubkey), got ${\n Buffer.isBuffer(publicKeyNoCoord)\n ? `${publicKeyNoCoord.length}-byte Buffer`\n : typeof publicKeyNoCoord\n }`,\n );\n }\n\n // Validate UTXO array length matches transaction inputs\n if (inputs.length !== tx.ins.length) {\n throw new Error(\n `UTXO count mismatch: transaction has ${tx.ins.length} input${tx.ins.length !== 1 ? \"s\" : \"\"}, ` +\n `but ${inputs.length} UTXO${inputs.length !== 1 ? \"s were\" : \" was\"} provided`,\n );\n }\n\n // Add inputs with UTXO data for P2TR signing\n for (let i = 0; i < tx.ins.length; i++) {\n const input = tx.ins[i];\n const utxo = inputs[i];\n\n if (!utxo) {\n throw new Error(`Missing UTXO data for input ${i}`);\n }\n\n // Validate UTXO outpoint matches transaction input\n const expectedTxid = Buffer.from(input.hash).reverse().toString(\"hex\");\n const expectedVout = input.index;\n\n if (utxo.txid !== expectedTxid || utxo.vout !== expectedVout) {\n throw new Error(\n `Input ${i} outpoint mismatch: ` +\n `transaction expects ${expectedTxid}:${expectedVout}, ` +\n `but UTXO ${utxo.txid}:${utxo.vout} was provided. ` +\n `Ensure inputs array matches the order used in createSplitTransaction().`,\n );\n }\n\n // Validate input is P2TR (required for tapInternalKey)\n const inputScript = Buffer.from(utxo.scriptPubKey, \"hex\");\n const isP2TR =\n inputScript.length === 34 &&\n inputScript[0] === 0x51 && // OP_1 (witness version 1)\n inputScript[1] === 0x20; // push 32 bytes\n\n if (!isP2TR) {\n throw new Error(\n `Input ${i} must be P2TR (Taproot). ` +\n `createSplitTransactionPsbt() requires P2TR inputs because it uses ` +\n `tapInternalKey for Taproot signing. ` +\n `ScriptPubKey: ${utxo.scriptPubKey.substring(0, 20)}...`,\n );\n }\n\n // IMPORTANT: Assumes P2TR inputs. tapInternalKey is only valid for Taproot.\n // Using this function with non-P2TR inputs will cause wallet signing to fail.\n const witnessUtxo = {\n script: Buffer.from(utxo.scriptPubKey, \"hex\"),\n value: utxo.value,\n };\n\n psbt.addInput({\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo,\n tapInternalKey: publicKeyNoCoord,\n });\n }\n\n // Add outputs\n for (const output of tx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\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 * Mempool API Client\n *\n * Client for interacting with mempool.space API for Bitcoin network operations.\n * Used for broadcasting transactions and fetching UTXO data.\n *\n * @module clients/mempool/mempoolApi\n */\n\nimport type { MempoolUTXO, NetworkFees, TxInfo, UtxoInfo } from \"./types\";\n\n/**\n * Default mempool API URLs by network.\n */\nexport const MEMPOOL_API_URLS = {\n mainnet: \"https://mempool.space/api\",\n testnet: \"https://mempool.space/testnet/api\",\n signet: \"https://mempool.space/signet/api\",\n} as const;\n\n/**\n * Fetch wrapper with error handling.\n */\nasync function fetchApi<T>(\n url: string,\n options?: RequestInit,\n): Promise<T> {\n try {\n const response = await fetch(url, options);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Mempool API error (${response.status}): ${errorText || response.statusText}`,\n );\n }\n\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n return (await response.json()) as T;\n } else {\n return (await response.text()) as T;\n }\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to fetch from mempool API: ${error.message}`);\n }\n throw new Error(\"Failed to fetch from mempool API: Unknown error\");\n }\n}\n\n/**\n * Push a signed transaction to the Bitcoin network.\n *\n * @param txHex - The signed transaction hex string\n * @param apiUrl - Mempool API base URL\n * @returns The transaction ID\n * @throws Error if broadcasting fails\n */\nexport async function pushTx(txHex: string, apiUrl: string): Promise<string> {\n try {\n const response = await fetch(`${apiUrl}/tx`, {\n method: \"POST\",\n body: txHex,\n headers: {\n \"Content-Type\": \"text/plain\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n // Try to extract error message from response using robust JSON parsing\n let message: string | undefined;\n try {\n const errorJson = JSON.parse(errorText);\n message = errorJson.message;\n } catch {\n // Not JSON, use raw text\n message = errorText;\n }\n throw new Error(\n message || `Failed to broadcast transaction: ${response.statusText}`,\n );\n }\n\n // Response is the transaction ID (plain text)\n const txId = await response.text();\n return txId;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to broadcast BTC transaction: ${error.message}`);\n }\n throw new Error(\"Failed to broadcast BTC transaction: Unknown error\");\n }\n}\n\n/**\n * Get transaction information from mempool.\n *\n * @param txid - The transaction ID\n * @param apiUrl - Mempool API base URL\n * @returns Transaction information\n */\nexport async function getTxInfo(txid: string, apiUrl: string): Promise<TxInfo> {\n return fetchApi<TxInfo>(`${apiUrl}/tx/${txid}`);\n}\n\n/**\n * Get the hex representation of a transaction.\n *\n * @param txid - The transaction ID\n * @param apiUrl - Mempool API base URL\n * @returns The transaction hex string\n * @throws Error if the request fails or transaction is not found\n */\nexport async function getTxHex(txid: string, apiUrl: string): Promise<string> {\n try {\n const response = await fetch(`${apiUrl}/tx/${txid}/hex`);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Mempool API error (${response.status}): ${errorText || response.statusText}`,\n );\n }\n\n return await response.text();\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to get transaction hex for ${txid}: ${error.message}`);\n }\n throw new Error(`Failed to get transaction hex for ${txid}: Unknown error`);\n }\n}\n\n/**\n * Get UTXO information for a specific transaction output.\n *\n * This is used for constructing PSBTs where we need the witnessUtxo data.\n * Only supports Taproot (P2TR) and native SegWit (P2WPKH, P2WSH) script types.\n *\n * @param txid - The transaction ID containing the UTXO\n * @param vout - The output index\n * @param apiUrl - Mempool API base URL\n * @returns UTXO information with value and scriptPubKey\n */\nexport async function getUtxoInfo(\n txid: string,\n vout: number,\n apiUrl: string,\n): Promise<UtxoInfo> {\n const txInfo = await getTxInfo(txid, apiUrl);\n\n if (vout >= txInfo.vout.length) {\n throw new Error(\n `Invalid vout ${vout} for transaction ${txid} (has ${txInfo.vout.length} outputs)`,\n );\n }\n\n const output = txInfo.vout[vout];\n\n return {\n txid,\n vout,\n value: output.value,\n scriptPubKey: output.scriptpubkey,\n };\n}\n\n/**\n * Get all UTXOs for a Bitcoin address.\n *\n * @param address - The Bitcoin address\n * @param apiUrl - Mempool API base URL\n * @returns Array of UTXOs sorted by value (largest first)\n */\nexport async function getAddressUtxos(\n address: string,\n apiUrl: string,\n): Promise<MempoolUTXO[]> {\n try {\n // Fetch UTXOs for the address\n const utxos = await fetchApi<\n {\n txid: string;\n vout: number;\n value: number;\n status: {\n confirmed: boolean;\n };\n }[]\n >(`${apiUrl}/address/${address}/utxo`);\n\n // Fetch scriptPubKey for the address\n const addressInfo = await fetchApi<{\n isvalid: boolean;\n scriptPubKey: string;\n }>(`${apiUrl}/v1/validate-address/${address}`);\n\n if (!addressInfo.isvalid) {\n throw new Error(\n `Invalid Bitcoin address: ${address}. Mempool API validation failed.`,\n );\n }\n\n // Sort by value (largest first) and map to our UTXO format\n const sortedUTXOs = utxos.sort((a, b) => b.value - a.value);\n\n return sortedUTXOs.map((utxo) => ({\n txid: utxo.txid,\n vout: utxo.vout,\n value: utxo.value,\n scriptPubKey: addressInfo.scriptPubKey,\n confirmed: utxo.status.confirmed,\n }));\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(\n `Failed to get UTXOs for address ${address}: ${error.message}`,\n );\n }\n throw new Error(\n `Failed to get UTXOs for address ${address}: Unknown error`,\n );\n }\n}\n\n/**\n * Get the mempool API URL for a given network.\n *\n * @param network - Bitcoin network (mainnet, testnet, signet)\n * @returns The mempool API URL\n */\nexport function getMempoolApiUrl(\n network: \"mainnet\" | \"testnet\" | \"signet\",\n): string {\n return MEMPOOL_API_URLS[network];\n}\n\n/**\n * Transaction summary from address transactions endpoint.\n */\nexport interface AddressTx {\n txid: string;\n status: {\n confirmed: boolean;\n block_height?: number;\n };\n}\n\n/**\n * Get recent transactions for a Bitcoin address.\n *\n * Returns the last 25 confirmed transactions plus any unconfirmed (mempool) transactions.\n * This is useful for checking if a specific transaction has been broadcast.\n *\n * @param address - The Bitcoin address\n * @param apiUrl - Mempool API base URL\n * @returns Array of recent transactions\n */\nexport async function getAddressTxs(\n address: string,\n apiUrl: string,\n): Promise<AddressTx[]> {\n return fetchApi<AddressTx[]>(`${apiUrl}/address/${address}/txs`);\n}\n\n/**\n * Fetches Bitcoin network fee recommendations from mempool.space API.\n *\n * @param apiUrl - Mempool API base URL\n * @returns Fee rates in sat/vbyte for different confirmation times\n * @throws Error if request fails or returns invalid data\n *\n * @see https://mempool.space/docs/api/rest#get-recommended-fees\n */\nexport async function getNetworkFees(apiUrl: string): Promise<NetworkFees> {\n const response = await fetch(`${apiUrl}/v1/fees/recommended`);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch network fees: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n\n if (\n typeof data.fastestFee !== \"number\" ||\n typeof data.halfHourFee !== \"number\" ||\n typeof data.hourFee !== \"number\" ||\n typeof data.economyFee !== \"number\" ||\n typeof data.minimumFee !== \"number\"\n ) {\n throw new Error(\n \"Invalid fee data structure from mempool API. Expected all fee fields to be numbers.\",\n );\n }\n\n return data as NetworkFees;\n}\n\n","/**\n * BTCVaultsManager Contract ABI\n *\n * Minimal ABI containing only the functions needed by the SDK.\n * Full ABI is available in the vault service package.\n *\n * @module contracts/abis/BTCVaultsManager\n */\n\n/**\n * Minimal ABI for BTCVaultsManager contract.\n * Contains submitPeginRequest, activateVaultWithSecret, getPegInFee, and getBTCVault.\n */\nexport const BTCVaultsManagerABI = [\n {\n type: \"function\",\n name: \"submitPeginRequest\",\n inputs: [\n {\n name: \"depositor\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"depositorBtcPubKey\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"btcPopSignature\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"unsignedPrePeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorSignedPeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"vaultProvider\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"hashlock\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"depositorPayoutBtcAddress\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorLamportPkHash\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n stateMutability: \"payable\",\n },\n {\n type: \"function\",\n name: \"submitPeginRequest\",\n inputs: [\n {\n name: \"depositor\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"depositorBtcPubKey\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"btcPopSignature\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"unsignedPrePeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorSignedPeginTx\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"vaultProvider\",\n type: \"address\",\n internalType: \"address\",\n },\n {\n name: \"hashlock\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"referralCode\",\n type: \"uint32\",\n internalType: \"uint32\",\n },\n {\n name: \"depositorPayoutBtcAddress\",\n type: \"bytes\",\n internalType: \"bytes\",\n },\n {\n name: \"depositorLamportPkHash\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n stateMutability: \"payable\",\n },\n {\n type: \"function\",\n name: \"activateVaultWithSecret\",\n inputs: [\n {\n name: \"vaultId\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n {\n name: \"s\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [],\n stateMutability: \"nonpayable\",\n },\n {\n type: \"function\",\n name: \"getPegInFee\",\n inputs: [\n {\n name: \"vaultProvider\",\n type: \"address\",\n internalType: \"address\",\n },\n ],\n outputs: [\n {\n name: \"totalFee\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"function\",\n name: \"getBTCVault\",\n inputs: [\n {\n name: \"vaultId\",\n type: \"bytes32\",\n internalType: \"bytes32\",\n },\n ],\n outputs: [\n {\n name: \"vault\",\n type: \"tuple\",\n internalType: \"struct IBTCVaultsManager.BTCVault\",\n components: [\n { name: \"depositor\", type: \"address\", internalType: \"address\" },\n { name: \"depositorBtcPubKey\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"depositorSignedPeginTx\", type: \"bytes\", internalType: \"bytes\" },\n { name: \"amount\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"vaultProvider\", type: \"address\", internalType: \"address\" },\n { name: \"status\", type: \"uint8\", internalType: \"enum IBTCVaultsManager.BTCVaultStatus\" },\n { name: \"applicationController\", type: \"address\", internalType: \"address\" },\n { name: \"universalChallengersVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"appVaultKeepersVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"offchainParamsVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"vkVersion\", type: \"uint16\", internalType: \"uint16\" },\n { name: \"createdAt\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"verifiedAt\", type: \"uint256\", internalType: \"uint256\" },\n { name: \"depositorLamportPkHash\", type: \"bytes32\", internalType: \"bytes32\" },\n { name: \"hashlock\", type: \"bytes32\", internalType: \"bytes32\" },\n ],\n },\n ],\n stateMutability: \"view\",\n },\n {\n type: \"error\",\n name: \"InvalidPeginFee\",\n inputs: [\n {\n name: \"provided\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n {\n name: \"required\",\n type: \"uint256\",\n internalType: \"uint256\",\n },\n ],\n },\n {\n type: \"error\",\n name: \"InvalidSecret\",\n inputs: [],\n },\n {\n type: \"error\",\n name: \"ActivationDeadlineExpired\",\n inputs: [],\n },\n] as const;\n","/**\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};\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 if (!error || typeof error !== \"object\") return undefined;\n\n const err = error as Record<string, unknown>;\n\n // Check direct properties first\n if (typeof err.data === \"string\" && err.data.startsWith(\"0x\")) {\n return err.data;\n }\n if (typeof err.details === \"string\" && err.details.startsWith(\"0x\")) {\n return err.details;\n }\n\n // Walk the cause chain (viem wraps errors multiple levels deep)\n let current: unknown = err.cause;\n let depth = 0;\n const maxDepth = 5;\n\n while (current && typeof current === \"object\" && depth < maxDepth) {\n const cause = current as Record<string, unknown>;\n if (typeof cause.data === \"string\" && cause.data.startsWith(\"0x\")) {\n return cause.data;\n }\n current = cause.cause;\n depth++;\n }\n\n // Check error message for embedded hex error selector\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) {\n 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","/**\n * Peg-in Manager - Wallet Orchestration for Peg-in Operations\n *\n * This module provides the PeginManager class that orchestrates the complete\n * atomic swap peg-in flow using SDK primitives, utilities, and wallet interfaces.\n *\n * @remarks\n * PeginManager handles the atomic swap peg-in flow:\n * 1. **prepareAtomicPegin()** - Build Pre-PegIn HTLC, fund it, sign PegIn input\n * 2. **registerPeginOnChain()** - Submit to Ethereum contract with PoP\n * 3. *(Use {@link PayoutManager} for payout authorization signing)*\n * 4. **signAndBroadcast()** - Sign and broadcast Pre-PegIn tx to Bitcoin network\n *\n * @see {@link PayoutManager} - For Step 3: sign payout transactions\n * @see {@link buildPrePeginPsbt} - Lower-level primitive used internally\n *\n * @module managers/PeginManager\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\nimport {\n createPublicClient,\n encodeFunctionData,\n http,\n zeroAddress,\n type Address,\n type Chain,\n type Hex,\n type WalletClient,\n} from \"viem\";\n\nimport type { BitcoinWallet } from \"../../../shared/wallets/interfaces/BitcoinWallet\";\nimport type { Hash } from \"../../../shared/wallets/interfaces/EthereumWallet\";\nimport { getUtxoInfo, pushTx } from \"../clients/mempool\";\nimport { BTCVaultsManagerABI, handleContractError } from \"../contracts\";\nimport {\n buildPrePeginPsbt,\n buildPeginTxFromFundedPrePegin,\n buildPeginInputPsbt,\n extractPeginInputSignature,\n type PrePeginParams,\n type Network,\n} from \"../primitives\";\nimport {\n ensureHexPrefix,\n isAddressFromPublicKey,\n stripHexPrefix,\n} from \"../primitives/utils/bitcoin\";\nimport {\n calculateBtcTxHash,\n fundPeginTransaction,\n getNetwork,\n getPsbtInputFields,\n selectUtxosForPegin,\n type UTXO,\n} from \"../utils\";\n\n/**\n * Configuration for the PeginManager.\n */\nexport interface PeginManagerConfig {\n /**\n * Bitcoin network to use for transactions.\n */\n btcNetwork: Network;\n\n /**\n * Bitcoin wallet for signing peg-in transactions.\n */\n btcWallet: BitcoinWallet;\n\n /**\n * Ethereum wallet for registering peg-in on-chain.\n * Uses viem's WalletClient directly for proper gas estimation.\n */\n ethWallet: WalletClient;\n\n /**\n * Ethereum chain configuration.\n * Required for proper gas estimation in contract calls.\n */\n ethChain: Chain;\n\n /**\n * Vault contract addresses.\n */\n vaultContracts: {\n /**\n * BTCVaultsManager contract address on Ethereum.\n */\n btcVaultsManager: Address;\n };\n\n /**\n * Mempool API URL for fetching UTXO data and broadcasting transactions.\n * Use MEMPOOL_API_URLS constant for standard mempool.space URLs, or provide\n * a custom URL if running your own mempool instance.\n */\n mempoolApiUrl: string;\n}\n\n/**\n * Parameters for the atomic swap pegin flow (pre-pegin + pegin transactions).\n */\nexport interface CreateAtomicPeginParams {\n /**\n * Amount to peg in (in satoshis).\n */\n amount: bigint;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n */\n vaultKeeperBtcPubkeys: readonly string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix (will be stripped automatically).\n */\n universalChallengerBtcPubkeys: readonly string[];\n\n /**\n * CSV timelock in blocks for the PegIn vault output.\n */\n timelockPegin: number;\n\n /**\n * CSV timelock in blocks for the Pre-PegIn HTLC refund path.\n */\n timelockRefund: number;\n\n /**\n * SHA256 hash commitment for the HTLC (64 hex chars = 32 bytes).\n * Generated by the depositor as H = SHA256(secret).\n */\n hashH: string;\n\n /**\n * Fee rate in satoshis per vbyte for the Pre-PegIn transaction.\n */\n feeRate: number;\n\n /**\n * Number of local challengers (from contract params).\n */\n numLocalChallengers: number;\n\n /**\n * M in M-of-N council multisig (from contract params).\n */\n councilQuorum: number;\n\n /**\n * N in M-of-N council multisig (from contract params).\n */\n councilSize: number;\n\n /**\n * Available UTXOs from the depositor's wallet for funding the Pre-PegIn transaction.\n */\n availableUTXOs: readonly UTXO[];\n\n /**\n * Bitcoin address for receiving change from the Pre-PegIn transaction.\n */\n changeAddress: string;\n}\n\n/**\n * Result of preparing an atomic swap pegin.\n */\nexport interface AtomicPeginResult {\n /**\n * Funded but unsigned Pre-PegIn transaction hex.\n * Sign and broadcast this AFTER registering on Ethereum.\n */\n fundedPrePeginTxHex: string;\n\n /**\n * Pre-PegIn HTLC value in satoshis (amount the UTXOs cover).\n */\n htlcValue: bigint;\n\n /**\n * PegIn transaction hex with depositor's HTLC leaf 0 signature embedded in the PSBT.\n * Submit the extracted signature to the vault provider.\n */\n signedPeginInputPsbtHex: string;\n\n /**\n * Depositor's Schnorr signature over PegIn input 0 (HTLC leaf 0), 128 hex chars.\n * This is submitted to the contract via the VP's signPeginInput batch.\n */\n peginInputSignature: string;\n\n /**\n * Vault script pubkey hex — used in the ETH registration call.\n */\n vaultScriptPubKey: string;\n\n /**\n * Funded Pre-PegIn transaction ID.\n */\n prePeginTxid: string;\n\n /**\n * PegIn transaction hex. Pass to registerPeginOnChain as `depositorSignedPeginTx`\n * so the contract computes the correct vault ID from the pegin txid.\n */\n peginTxHex: string;\n\n /**\n * PegIn transaction ID (stable — signing does not change it).\n */\n peginTxid: string;\n\n /**\n * UTXOs selected to fund the Pre-PegIn transaction.\n */\n selectedUTXOs: UTXO[];\n\n /**\n * Transaction fee in satoshis.\n */\n fee: bigint;\n\n /**\n * Change amount in satoshis (if any).\n */\n changeAmount: bigint;\n}\n\n\n/**\n * Parameters for signing and broadcasting a transaction.\n */\nexport interface SignAndBroadcastParams {\n /**\n * Funded Pre-PegIn transaction hex from prepareAtomicPegin().\n */\n fundedPrePeginTxHex: string;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix.\n * Required for Taproot signing.\n */\n depositorBtcPubkey: string;\n}\n\n/**\n * Parameters for registering a peg-in on Ethereum.\n */\nexport interface RegisterPeginParams {\n /**\n * Depositor's BTC public key (x-only, 64-char hex).\n * Can be provided with or without \"0x\" prefix.\n */\n depositorBtcPubkey: string;\n\n /**\n * Unsigned Pre-PegIn transaction hex (submitted to contract for data availability).\n */\n unsignedPrePeginTx: string;\n\n /**\n * Depositor-signed PegIn transaction hex (submitted to contract; vault ID derived from this).\n */\n depositorSignedPeginTx: string;\n\n /**\n * Vault provider's Ethereum address.\n */\n vaultProvider: Address;\n\n /**\n * SHA256 hashlock for atomic swap activation (bytes32 hex with 0x prefix).\n */\n hashlock: Hex;\n\n /**\n * Optional callback invoked after PoP signing completes but before ETH transaction.\n */\n onPopSigned?: () => void | Promise<void>;\n\n /**\n * Depositor's BTC payout address (e.g. bc1p..., bc1q...).\n * Converted to scriptPubKey internally via bitcoinjs-lib.\n *\n * If omitted, defaults to the connected BTC wallet's address\n * via `btcWallet.getAddress()`.\n */\n depositorPayoutBtcAddress?: string;\n\n /** Keccak256 hash of the depositor's Lamport public key (bytes32) */\n depositorLamportPkHash: Hex;\n\n /**\n * Pre-signed BTC PoP signature (hex with 0x prefix).\n * When provided, the BTC wallet signing step is skipped and this signature is used directly.\n * Useful for multi-vault deposits where PoP only needs to be signed once.\n */\n preSignedBtcPopSignature?: Hex;\n\n /**\n * SHA-256 hash of the depositor's secret (bytes32).\n * Required for the new peg-in flow deposits.\n * TODO: Wire into submitPeginRequest contract call when contract ABI is updated to support the new peg-in flow.\n */\n depositorSecretHash?: Hex;\n}\n\n/**\n * Result of registering a peg-in on Ethereum.\n */\nexport interface RegisterPeginResult {\n /**\n * Ethereum transaction hash for the peg-in registration.\n */\n ethTxHash: Hash;\n\n /**\n * Vault identifier used in the BTCVaultsManager contract.\n * This is the Bitcoin transaction hash with 0x prefix for Ethereum compatibility.\n * Corresponds to btcTxHash from PeginResult, but formatted as Hex with '0x' prefix.\n */\n vaultId: Hex;\n\n /**\n * The BTC PoP signature used for this registration (hex with 0x prefix).\n * Returned so callers can reuse it for subsequent pegins without re-signing.\n */\n btcPopSignature: Hex;\n}\n\n/**\n * Manager for orchestrating peg-in operations.\n *\n * This manager provides a high-level API for creating peg-in transactions\n * by coordinating between SDK primitives, utilities, and wallet interfaces.\n *\n * @remarks\n * The complete atomic swap peg-in flow consists of 4 steps:\n *\n * | Step | Method | Description |\n * |------|--------|-------------|\n * | 1 | {@link prepareAtomicPegin} | Build Pre-PegIn HTLC, fund it, sign PegIn input |\n * | 2 | {@link registerPeginOnChain} | Submit to Ethereum contract with PoP |\n * | 3 | {@link PayoutManager} | Sign BOTH payout authorizations |\n * | 4 | {@link signAndBroadcast} | Sign and broadcast Pre-PegIn tx to Bitcoin network |\n *\n * **Important:** Step 3 uses {@link PayoutManager}, not this class. After step 2,\n * the vault provider prepares 3 transactions per claimer:\n * - `claim_tx` - Claim transaction\n * - `assert_tx` - Assert transaction\n * - `payout_tx` - Payout transaction\n *\n * You must sign the Payout transaction for each claimer:\n * - {@link PayoutManager.signPayoutTransaction} - uses assert_tx as input reference\n *\n * Submit all signatures to the vault provider before proceeding to step 4.\n *\n * @see {@link PayoutManager} - Required for Step 3 (payout authorization)\n * @see {@link buildPrePeginPsbt} - Lower-level primitive for custom implementations\n * @see {@link https://github.com/babylonlabs-io/babylon-toolkit/blob/main/packages/babylon-ts-sdk/docs/quickstart/managers.md | Managers Quickstart}\n */\nexport class PeginManager {\n private readonly config: PeginManagerConfig;\n\n /**\n * Creates a new PeginManager instance.\n *\n * @param config - Manager configuration including wallets and contract addresses\n */\n constructor(config: PeginManagerConfig) {\n this.config = config;\n }\n\n /**\n * Prepares an atomic swap peg-in by building the Pre-PegIn HTLC transaction,\n * funding it, constructing the PegIn transaction, and signing the PegIn input.\n *\n * This method orchestrates the following steps:\n * 1. Get depositor BTC public key from wallet\n * 2. Build unfunded Pre-PegIn transaction (HTLC output) using primitives\n * 3. Select UTXOs to cover the HTLC value\n * 4. Fund the Pre-PegIn transaction\n * 5. Derive the PegIn transaction from the funded Pre-PegIn txid\n * 6. Build PSBT for signing the PegIn input (HTLC leaf 0)\n * 7. Sign via BTC wallet and extract depositor signature\n *\n * The returned `fundedPrePeginTxHex` is funded but unsigned (inputs unsigned).\n * Use `signAndBroadcast()` AFTER registering on Ethereum to broadcast it.\n *\n * @param params - Atomic pegin parameters including amount, HTLC params, UTXOs\n * @returns Atomic pegin result with funded Pre-PegIn tx, signed PegIn input, and signatures\n * @throws Error if wallet operations fail or insufficient funds\n */\n async prepareAtomicPegin(\n params: CreateAtomicPeginParams,\n ): Promise<AtomicPeginResult> {\n // Step 1: Get depositor BTC public key from wallet\n const depositorBtcPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n // Convert 33-byte compressed (66 chars) to 32-byte x-only (64 chars) if needed\n const depositorBtcPubkey =\n depositorBtcPubkeyRaw.length === 66\n ? depositorBtcPubkeyRaw.slice(2)\n : depositorBtcPubkeyRaw;\n\n const vaultProviderBtcPubkey = stripHexPrefix(params.vaultProviderBtcPubkey);\n const vaultKeeperBtcPubkeys = params.vaultKeeperBtcPubkeys.map(stripHexPrefix);\n const universalChallengerBtcPubkeys =\n params.universalChallengerBtcPubkeys.map(stripHexPrefix);\n\n const prePeginParams: PrePeginParams = {\n depositorPubkey: depositorBtcPubkey,\n vaultProviderPubkey: vaultProviderBtcPubkey,\n vaultKeeperPubkeys: vaultKeeperBtcPubkeys,\n universalChallengerPubkeys: universalChallengerBtcPubkeys,\n hashH: params.hashH,\n timelockRefund: params.timelockRefund,\n pegInAmount: params.amount,\n feeRate: BigInt(params.feeRate),\n numLocalChallengers: params.numLocalChallengers,\n councilQuorum: params.councilQuorum,\n councilSize: params.councilSize,\n network: this.config.btcNetwork,\n };\n\n // Step 2: Build unfunded Pre-PegIn transaction (HTLC output, no inputs)\n const prePeginResult = await buildPrePeginPsbt(prePeginParams);\n\n // Step 3: Select UTXOs to cover ALL unfunded tx outputs (HTLC + CPFP anchor)\n // fundPeginTransaction copies all WASM outputs, so UTXO selection must\n // account for their total value, not just the HTLC output.\n const utxoSelection = selectUtxosForPegin(\n [...params.availableUTXOs],\n prePeginResult.totalOutputValue,\n params.feeRate,\n );\n\n // Step 4: Fund the Pre-PegIn transaction with selected UTXOs\n const network = getNetwork(this.config.btcNetwork);\n const fundedPrePeginTxHex = fundPeginTransaction({\n unfundedTxHex: prePeginResult.psbtHex,\n selectedUTXOs: utxoSelection.selectedUTXOs,\n changeAddress: params.changeAddress,\n changeAmount: utxoSelection.changeAmount,\n network,\n });\n\n // Compute the funded Pre-PegIn txid — this is the stable txid used to derive the PegIn tx\n const prePeginTxid = stripHexPrefix(calculateBtcTxHash(fundedPrePeginTxHex));\n\n // Step 5: Derive the PegIn transaction from the funded Pre-PegIn txid\n const peginTxResult = await buildPeginTxFromFundedPrePegin({\n prePeginParams,\n timelockPegin: params.timelockPegin,\n fundedPrePeginTxid: prePeginTxid,\n });\n\n // Step 6: Build PSBT for depositor to sign PegIn input 0 (HTLC hashlock leaf)\n const peginInputPsbtResult = await buildPeginInputPsbt({\n peginTxHex: peginTxResult.txHex,\n fundedPrePeginTxHex,\n depositorPubkey: depositorBtcPubkey,\n vaultProviderPubkey: vaultProviderBtcPubkey,\n vaultKeeperPubkeys: vaultKeeperBtcPubkeys,\n universalChallengerPubkeys: universalChallengerBtcPubkeys,\n hashH: params.hashH,\n timelockRefund: params.timelockRefund,\n network: this.config.btcNetwork,\n });\n\n // Step 7: Sign the PegIn input PSBT via BTC wallet\n // The PegIn input is a Taproot script-path spend (HTLC hashlock leaf), so:\n // - autoFinalized: false to keep tapScriptSig accessible for signature extraction\n // - disableTweakSigner: true because script-path uses the untweaked internal key\n const signedPeginInputPsbtHex = await this.config.btcWallet.signPsbt(\n peginInputPsbtResult.psbtHex,\n {\n autoFinalized: false,\n signInputs: [\n {\n index: 0,\n publicKey: depositorBtcPubkeyRaw,\n disableTweakSigner: true,\n },\n ],\n },\n );\n\n // Extract the depositor's Schnorr signature from the signed PSBT\n const peginInputSignature = extractPeginInputSignature(\n signedPeginInputPsbtHex,\n depositorBtcPubkey,\n );\n\n return {\n fundedPrePeginTxHex,\n htlcValue: prePeginResult.htlcValue,\n signedPeginInputPsbtHex,\n peginInputSignature,\n vaultScriptPubKey: peginTxResult.vaultScriptPubKey,\n peginTxHex: peginTxResult.txHex,\n prePeginTxid,\n peginTxid: peginTxResult.txid,\n selectedUTXOs: utxoSelection.selectedUTXOs,\n fee: utxoSelection.fee,\n changeAmount: utxoSelection.changeAmount,\n };\n }\n\n /**\n * Signs and broadcasts a funded peg-in transaction to the Bitcoin network.\n *\n * This method:\n * 1. Parses the funded transaction hex\n * 2. Fetches UTXO data from mempool for each input\n * 3. Creates a PSBT with proper witnessUtxo/tapInternalKey\n * 4. Signs via btcWallet.signPsbt()\n * 5. Finalizes and extracts the transaction\n * 6. Broadcasts via mempool API\n *\n * @param params - Transaction hex and depositor public key\n * @returns The broadcasted Bitcoin transaction ID\n * @throws Error if signing or broadcasting fails\n */\n async signAndBroadcast(params: SignAndBroadcastParams): Promise<string> {\n const { fundedPrePeginTxHex, depositorBtcPubkey } = params;\n\n // Step 1: Parse the funded transaction\n const cleanHex = fundedPrePeginTxHex.startsWith(\"0x\")\n ? fundedPrePeginTxHex.slice(2)\n : fundedPrePeginTxHex;\n const tx = Transaction.fromHex(cleanHex);\n\n if (tx.ins.length === 0) {\n throw new Error(\"Transaction has no inputs\");\n }\n\n // Step 2: Create PSBT and add inputs with UTXO data from mempool\n const psbt = new Psbt();\n psbt.setVersion(tx.version);\n psbt.setLocktime(tx.locktime);\n\n // Strip 0x prefix if present before converting to Buffer\n const cleanPubkey = depositorBtcPubkey.startsWith(\"0x\")\n ? depositorBtcPubkey.slice(2)\n : depositorBtcPubkey;\n // Validate x-only pubkey length and format (32 bytes = 64 hex chars)\n if (cleanPubkey.length !== 64 || !/^[0-9a-fA-F]+$/.test(cleanPubkey)) {\n throw new Error(\n \"Invalid depositorBtcPubkey: expected 64 hex characters (x-only pubkey)\",\n );\n }\n const publicKeyNoCoord = Buffer.from(cleanPubkey, \"hex\");\n if (publicKeyNoCoord.length !== 32) {\n throw new Error(\n `Invalid depositorBtcPubkey length: expected 32 bytes, got ${publicKeyNoCoord.length}`,\n );\n }\n const apiUrl = this.config.mempoolApiUrl;\n\n // Fetch all UTXO data in parallel for better performance\n const utxoDataPromises = tx.ins.map((input) => {\n const txid = Buffer.from(input.hash).reverse().toString(\"hex\");\n const vout = input.index;\n return getUtxoInfo(txid, vout, apiUrl).then((utxoData) => ({\n input,\n utxoData,\n txid,\n vout,\n }));\n });\n\n const inputsWithUtxoData = await Promise.all(utxoDataPromises);\n\n // Add inputs with proper PSBT fields based on script type\n for (const { input, utxoData, txid, vout } of inputsWithUtxoData) {\n const psbtInputFields = getPsbtInputFields(\n {\n txid,\n vout,\n value: utxoData.value,\n scriptPubKey: utxoData.scriptPubKey,\n },\n publicKeyNoCoord,\n );\n\n psbt.addInput({\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n ...psbtInputFields,\n });\n }\n\n // Step 3: Add outputs\n for (const output of tx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n // Step 4: Sign PSBT via wallet\n const signedPsbtHex = await this.config.btcWallet.signPsbt(psbt.toHex());\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n\n // Step 5: Finalize and extract transaction\n try {\n signedPsbt.finalizeAllInputs();\n } catch (e) {\n // Some wallets (e.g. UniSat, OKX) auto-finalize PSBTs before returning them.\n // Attempting to finalize again throws, which is expected and safe to skip —\n // but verify the wallet actually finalized all inputs.\n const allFinalized = signedPsbt.data.inputs.every(\n (inp) => inp.finalScriptWitness || inp.finalScriptSig,\n );\n if (!allFinalized) {\n throw new Error(\n `PSBT finalization failed and wallet did not auto-finalize: ${e}`,\n );\n }\n }\n\n const signedTxHex = signedPsbt.extractTransaction().toHex();\n\n // Step 6: Broadcast to Bitcoin network\n const btcTxid = await pushTx(signedTxHex, apiUrl);\n\n return btcTxid;\n }\n\n /**\n * Registers a peg-in on Ethereum by calling the BTCVaultsManager contract.\n *\n * This method:\n * 1. Gets depositor ETH address from wallet\n * 2. Creates proof of possession (BTC signature of ETH address)\n * 3. Checks if vault already exists (pre-flight check)\n * 4. Encodes the contract call using viem\n * 5. Estimates gas (catches contract errors early with proper revert reasons)\n * 6. Sends transaction with pre-estimated gas via ethWallet.sendTransaction()\n *\n * @param params - Registration parameters including BTC pubkey and unsigned tx\n * @returns Result containing Ethereum transaction hash and vault ID\n * @throws Error if signing or transaction fails\n * @throws Error if vault already exists\n * @throws Error if contract simulation fails (e.g., invalid signature, unauthorized)\n */\n async registerPeginOnChain(\n params: RegisterPeginParams,\n ): Promise<RegisterPeginResult> {\n const {\n depositorBtcPubkey,\n unsignedPrePeginTx,\n depositorSignedPeginTx,\n vaultProvider,\n hashlock,\n onPopSigned,\n depositorPayoutBtcAddress,\n depositorLamportPkHash,\n preSignedBtcPopSignature,\n } = params;\n\n // Step 1: Get depositor ETH address (from wallet account)\n if (!this.config.ethWallet.account) {\n throw new Error(\"Ethereum wallet account not found\");\n }\n const depositorEthAddress = this.config.ethWallet.account.address;\n\n // Step 2: Create proof of possession (or reuse pre-signed one)\n const btcPopSignature = await this.resolvePopSignature(\n depositorEthAddress,\n preSignedBtcPopSignature,\n );\n\n if (onPopSigned) {\n await onPopSigned();\n }\n\n // Step 3: Format parameters for contract call\n const depositorBtcPubkeyHex = ensureHexPrefix(depositorBtcPubkey);\n const unsignedPrePeginTxHex = ensureHexPrefix(unsignedPrePeginTx);\n const depositorSignedPeginTxHex = ensureHexPrefix(depositorSignedPeginTx);\n\n const payoutScriptPubKey = await this.resolvePayoutScriptPubKey(\n depositorPayoutBtcAddress,\n );\n\n // Step 4: Calculate vault ID from depositorSignedPeginTx and check if it already exists\n const vaultId = calculateBtcTxHash(depositorSignedPeginTxHex);\n const exists = await this.checkVaultExists(vaultId);\n\n if (exists) {\n throw new Error(\n `Vault already exists for this transaction (ID: ${vaultId}). ` +\n `Vault IDs are deterministically derived from the unsigned Bitcoin transaction, so using the same UTXOs and amount will always produce the same vault. ` +\n `To create a new vault, please use different UTXOs or a different amount to generate a unique transaction.`,\n );\n }\n\n // Step 5: Query required pegin fee from the contract\n const publicClient = createPublicClient({\n chain: this.config.ethChain,\n transport: http(),\n });\n\n let peginFee: bigint;\n try {\n peginFee = (await publicClient.readContract({\n address: this.config.vaultContracts.btcVaultsManager,\n abi: BTCVaultsManagerABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n } catch {\n throw new Error(\n \"Failed to query pegin fee from the contract. \" +\n \"Please check your network connection and that the contract address is correct.\",\n );\n }\n\n // Step 6: Encode the contract call data\n const callData = encodeFunctionData({\n abi: BTCVaultsManagerABI,\n functionName: \"submitPeginRequest\",\n args: [\n depositorEthAddress,\n depositorBtcPubkeyHex,\n btcPopSignature,\n unsignedPrePeginTxHex,\n depositorSignedPeginTxHex,\n vaultProvider,\n hashlock,\n payoutScriptPubKey,\n depositorLamportPkHash,\n ],\n });\n\n // Step 7: Estimate gas first to catch contract errors before showing wallet popup\n // This ensures users see actual contract revert reasons instead of gas errors\n // The gas estimate is then passed to sendTransaction to avoid double estimation\n let gasEstimate: bigint;\n try {\n gasEstimate = await publicClient.estimateGas({\n to: this.config.vaultContracts.btcVaultsManager,\n data: callData,\n value: peginFee,\n account: this.config.ethWallet.account.address,\n });\n } catch (error) {\n // Estimation failed - handle contract error with actual revert reason\n handleContractError(error);\n }\n\n // Step 8: Submit peg-in request to contract (estimation passed)\n try {\n // Send transaction with pre-estimated gas to skip internal estimation\n // Note: viem's sendTransaction uses `gas`, not `gasLimit`\n const ethTxHash = await this.config.ethWallet.sendTransaction({\n to: this.config.vaultContracts.btcVaultsManager,\n data: callData,\n value: peginFee,\n account: this.config.ethWallet.account,\n chain: this.config.ethChain,\n gas: gasEstimate,\n });\n\n return {\n ethTxHash,\n vaultId,\n btcPopSignature,\n };\n } catch (error) {\n // Use proper error handler for better error messages\n handleContractError(error);\n }\n }\n\n /**\n * Check if a vault already exists for a given vault ID.\n *\n * @param vaultId - The Bitcoin transaction hash (vault ID)\n * @returns True if vault exists, false otherwise\n */\n private async checkVaultExists(vaultId: Hex): Promise<boolean> {\n try {\n // Create a public client to read from the contract\n const publicClient = createPublicClient({\n chain: this.config.ethChain,\n transport: http(),\n });\n\n const vault = (await publicClient.readContract({\n address: this.config.vaultContracts.btcVaultsManager,\n abi: BTCVaultsManagerABI,\n functionName: \"getBTCVault\",\n args: [vaultId],\n })) as { depositor: Address };\n\n // If depositor is not zero address, vault exists\n return vault.depositor !== zeroAddress;\n } catch {\n // If reading fails, assume vault doesn't exist and let contract handle it\n return false;\n }\n }\n\n /**\n * Resolve the BTC payout address to a scriptPubKey hex for the contract.\n *\n * If a payout address is provided, converts it directly.\n * If omitted, uses the wallet's address and validates it against the\n * wallet's public key to guard against a compromised wallet provider.\n */\n private async resolvePayoutScriptPubKey(\n depositorPayoutBtcAddress?: string,\n ): Promise<Hex> {\n let address: string;\n\n if (depositorPayoutBtcAddress) {\n address = depositorPayoutBtcAddress;\n } else {\n address = await this.config.btcWallet.getAddress();\n const walletPubkey = await this.config.btcWallet.getPublicKeyHex();\n if (\n !isAddressFromPublicKey(\n address,\n walletPubkey,\n this.config.btcNetwork,\n )\n ) {\n throw new Error(\n \"The BTC address from your wallet does not match the wallet's public key. \" +\n \"Please ensure your wallet is using a supported address type (Taproot or Native SegWit).\",\n );\n }\n }\n\n const network = getNetwork(this.config.btcNetwork);\n try {\n return `0x${bitcoin.address.toOutputScript(address, network).toString(\"hex\")}` as Hex;\n } catch {\n throw new Error(\n `Invalid BTC payout address: \"${address}\". ` +\n `Please provide a valid Bitcoin address for the ${this.config.btcNetwork} network.`,\n );\n }\n }\n\n /**\n * Resolve or create a BTC Proof-of-Possession signature.\n *\n * Reuses a pre-signed signature when provided (e.g. multi-vault deposits),\n * otherwise signs a BIP-322 message with the BTC wallet.\n */\n private async resolvePopSignature(\n depositorEthAddress: Address,\n preSignedBtcPopSignature?: Hex,\n ): Promise<Hex> {\n if (preSignedBtcPopSignature) {\n return preSignedBtcPopSignature;\n }\n\n // Message format matches BTCProofOfPossession.sol buildMessage()\n const verifyingContract = this.config.vaultContracts.btcVaultsManager;\n const popMessage = `${depositorEthAddress.toLowerCase()}:${this.config.ethChain.id}:pegin:${verifyingContract.toLowerCase()}`;\n const btcPopSignatureRaw = await this.config.btcWallet.signMessage(\n popMessage,\n \"bip322-simple\",\n );\n\n // BTC wallets return base64, Ethereum contracts expect hex\n if (btcPopSignatureRaw.startsWith(\"0x\")) {\n return btcPopSignatureRaw as Hex;\n }\n const signatureBytes = Buffer.from(btcPopSignatureRaw, \"base64\");\n return `0x${signatureBytes.toString(\"hex\")}` as Hex;\n }\n\n /**\n * Gets the configured Bitcoin network.\n *\n * @returns The Bitcoin network (mainnet, testnet, signet, regtest)\n */\n getNetwork(): Network {\n return this.config.btcNetwork;\n }\n\n /**\n * Gets the configured BTCVaultsManager contract address.\n *\n * @returns The Ethereum address of the BTCVaultsManager contract\n */\n getVaultContractAddress(): Address {\n return this.config.vaultContracts.btcVaultsManager;\n }\n}\n","/**\n * Payout Manager\n *\n * High-level manager that orchestrates the payout signing flow by coordinating\n * SDK primitives ({@link buildPayoutPsbt}, {@link extractPayoutSignature})\n * with a user-provided Bitcoin wallet.\n *\n * The Payout transaction references the Assert transaction (input 1).\n *\n * @see {@link PeginManager} - For Steps 1, 2, and 4 of peg-in flow\n * @see {@link buildPayoutPsbt} - Lower-level primitive for custom implementations\n * @see {@link extractPayoutSignature} - Extract signatures from signed PSBTs\n *\n * @module managers/PayoutManager\n */\n\nimport type { BitcoinWallet } from \"../../../shared/wallets/interfaces/BitcoinWallet\";\nimport {\n buildPayoutPsbt,\n extractPayoutSignature,\n validateWalletPubkey,\n type Network,\n} from \"../primitives\";\n\n/**\n * Configuration for the PayoutManager.\n */\nexport interface PayoutManagerConfig {\n /**\n * Bitcoin network to use for transactions.\n */\n network: Network;\n\n /**\n * Bitcoin wallet for signing payout transactions.\n */\n btcWallet: BitcoinWallet;\n}\n\n/**\n * Base parameters shared by both payout transaction types.\n */\ninterface SignPayoutBaseParams {\n /**\n * Peg-in transaction hex.\n * The original transaction that created the vault output being spent.\n */\n peginTxHex: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex).\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex).\n */\n vaultKeeperBtcPubkeys: string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex).\n */\n universalChallengerBtcPubkeys: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex).\n * This should be the public key that was used when creating the vault,\n * as stored on-chain. If not provided, will be fetched from the wallet.\n */\n depositorBtcPubkey?: string;\n}\n\n/**\n * Parameters for signing a Payout transaction.\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface SignPayoutParams extends SignPayoutBaseParams {\n /**\n * Payout transaction hex (unsigned).\n * This is the transaction from the vault provider that needs depositor signature.\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex.\n * Payout input 1 references Assert output 0.\n */\n assertTxHex: string;\n}\n\n/**\n * Result of signing a payout transaction.\n */\nexport interface PayoutSignatureResult {\n /**\n * 64-byte Schnorr signature (128 hex characters).\n */\n signature: string;\n\n /**\n * Depositor's BTC public key used for signing.\n */\n depositorBtcPubkey: string;\n}\n\n/**\n * High-level manager for payout transaction signing.\n *\n * @remarks\n * After registering your peg-in on Ethereum (Step 2), the vault provider prepares\n * claim/payout transaction pairs. You must sign each payout transaction using this\n * manager and submit the signatures to the vault provider's RPC API.\n *\n * **What happens internally:**\n * 1. Validates your wallet's public key matches the vault's depositor\n * 2. Builds an unsigned PSBT with taproot script path spend info\n * 3. Signs input 0 (the vault UTXO) with your wallet\n * 4. Extracts the 64-byte Schnorr signature\n *\n * **Note:** The payout transaction has 2 inputs. PayoutManager only signs input 0\n * (from the peg-in tx). Input 1 (from the assert tx) is signed by the vault provider.\n *\n * @see {@link PeginManager} - For the complete peg-in flow context\n * @see {@link buildPayoutPsbt} - Lower-level primitive used internally\n * @see {@link extractPayoutSignature} - Signature extraction primitive\n */\nexport class PayoutManager {\n private readonly config: PayoutManagerConfig;\n\n /**\n * Creates a new PayoutManager instance.\n *\n * @param config - Manager configuration including wallet\n */\n constructor(config: PayoutManagerConfig) {\n this.config = config;\n }\n\n /**\n * Signs a Payout transaction and extracts the Schnorr signature.\n *\n * Flow:\n * 1. Vault provider submits Claim transaction\n * 2. Claimer submits Assert transaction to prove validity\n * 3. Payout can be executed (references Assert tx)\n *\n * This method orchestrates the following steps:\n * 1. Get wallet's public key and convert to x-only format\n * 2. Validate wallet pubkey matches on-chain depositor pubkey (if provided)\n * 3. Build unsigned PSBT using primitives\n * 4. Sign PSBT via btcWallet.signPsbt()\n * 5. Extract 64-byte Schnorr signature using primitives\n *\n * The returned signature can be submitted to the vault provider API.\n *\n * @param params - Payout signing parameters\n * @returns Signature result with 64-byte Schnorr signature and depositor pubkey\n * @throws Error if wallet pubkey doesn't match depositor pubkey\n * @throws Error if wallet operations fail or signature extraction fails\n */\n async signPayoutTransaction(\n params: SignPayoutParams,\n ): Promise<PayoutSignatureResult> {\n // Validate wallet pubkey matches depositor and get both formats\n const walletPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n const { depositorPubkey } = validateWalletPubkey(\n walletPubkeyRaw,\n params.depositorBtcPubkey,\n );\n\n // Build unsigned PSBT for Payout (uses Assert tx)\n const payoutPsbt = await buildPayoutPsbt({\n payoutTxHex: params.payoutTxHex,\n peginTxHex: params.peginTxHex,\n assertTxHex: params.assertTxHex,\n depositorBtcPubkey: depositorPubkey,\n vaultProviderBtcPubkey: params.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: params.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys: params.universalChallengerBtcPubkeys,\n timelockPegin: params.timelockPegin,\n network: this.config.network,\n });\n\n // Sign PSBT via wallet\n // - signInputs restricts signing to input 0 only (input 1 is signed by claimer/challengers)\n // - walletPubkeyRaw uses compressed format (66 chars) as expected by wallets like UniSat\n // - disableTweakSigner is required for Taproot script path spend (uses untweaked key)\n const signedPsbtHex = await this.config.btcWallet.signPsbt(\n payoutPsbt.psbtHex,\n {\n autoFinalized: false,\n signInputs: [\n {\n index: 0,\n publicKey: walletPubkeyRaw,\n disableTweakSigner: true,\n },\n ],\n },\n );\n\n // Extract Schnorr signature\n const signature = extractPayoutSignature(signedPsbtHex, depositorPubkey);\n\n return {\n signature,\n depositorBtcPubkey: depositorPubkey,\n };\n }\n\n /**\n * Gets the configured Bitcoin network.\n *\n * @returns The Bitcoin network (mainnet, testnet, signet, regtest)\n */\n getNetwork(): Network {\n return this.config.network;\n }\n\n /**\n * Checks if the wallet supports batch signing (signPsbts).\n *\n * @returns true if batch signing is supported\n */\n supportsBatchSigning(): boolean {\n return typeof this.config.btcWallet.signPsbts === \"function\";\n }\n\n /**\n * Batch signs multiple payout transactions (1 per claimer).\n * This allows signing all transactions with a single wallet interaction.\n *\n * @param transactions - Array of payout params to sign\n * @returns Array of signature results matching input order\n * @throws Error if wallet doesn't support batch signing\n * @throws Error if any signing operation fails\n */\n async signPayoutTransactionsBatch(\n transactions: SignPayoutParams[],\n ): Promise<\n Array<{\n payoutSignature: string;\n depositorBtcPubkey: string;\n }>\n > {\n if (!this.supportsBatchSigning()) {\n throw new Error(\n \"Wallet does not support batch signing (signPsbts method not available)\",\n );\n }\n\n // Get wallet pubkey once\n const walletPubkeyRaw = await this.config.btcWallet.getPublicKeyHex();\n\n // Build all PSBTs (1 per claimer)\n const psbtsToSign: string[] = [];\n const signOptions: Array<{\n autoFinalized: boolean;\n signInputs: Array<{\n index: number;\n publicKey: string;\n disableTweakSigner: boolean;\n }>;\n }> = [];\n const depositorPubkeys: string[] = [];\n\n for (const tx of transactions) {\n // Validate wallet pubkey matches depositor\n const { depositorPubkey } = validateWalletPubkey(\n walletPubkeyRaw,\n tx.depositorBtcPubkey,\n );\n depositorPubkeys.push(depositorPubkey);\n\n // Build Payout PSBT\n const payoutPsbt = await buildPayoutPsbt({\n payoutTxHex: tx.payoutTxHex,\n peginTxHex: tx.peginTxHex,\n assertTxHex: tx.assertTxHex,\n depositorBtcPubkey: depositorPubkey,\n vaultProviderBtcPubkey: tx.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: tx.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys: tx.universalChallengerBtcPubkeys,\n timelockPegin: tx.timelockPegin,\n network: this.config.network,\n });\n psbtsToSign.push(payoutPsbt.psbtHex);\n signOptions.push({\n autoFinalized: false,\n signInputs: [\n {\n index: 0,\n publicKey: walletPubkeyRaw,\n disableTweakSigner: true,\n },\n ],\n });\n }\n\n // Batch sign all PSBTs with single wallet interaction\n const signedPsbts = await this.config.btcWallet.signPsbts!(\n psbtsToSign,\n signOptions,\n );\n\n // Validate that wallet returned the expected number of signed PSBTs\n if (signedPsbts.length !== transactions.length) {\n throw new Error(\n `Expected ${transactions.length} signed PSBTs but received ${signedPsbts.length}`,\n );\n }\n\n // Extract signatures from signed PSBTs\n const results: Array<{\n payoutSignature: string;\n depositorBtcPubkey: string;\n }> = [];\n\n for (let i = 0; i < transactions.length; i++) {\n const depositorPubkey = depositorPubkeys[i];\n const payoutSignature = extractPayoutSignature(\n signedPsbts[i],\n depositorPubkey,\n );\n\n results.push({\n payoutSignature,\n depositorBtcPubkey: depositorPubkey,\n });\n }\n\n return results;\n }\n}\n"],"names":["selectUtxosForPegin","availableUTXOs","peginAmount","feeRate","validUTXOs","utxo","script","Buffer","bitcoinScript","sortedUTXOs","b","selectedUTXOs","accumulatedValue","estimatedFee","inputSize","P2TR_INPUT_SIZE","outputSize","MAX_NON_LEGACY_OUTPUT_SIZE","baseTxSize","TX_BUFFER_SIZE_OVERHEAD","rateBasedTxBufferFee","DUST_THRESHOLD","changeOutputFee","finalChangeAmount","shouldAddChangeOutput","changeAmount","getDustThreshold","BTC_DUST_SAT","calculateBtcTxHash","txHex","cleanHex","Transaction","createSplitTransaction","inputs","outputs","network","output","btcNetwork","getNetwork","tx","input","txidBuffer","outputUtxos","i","outputScript","bitcoinAddress","error","txid","createSplitTransactionPsbt","unsignedTxHex","publicKeyNoCoord","psbt","Psbt","expectedTxid","expectedVout","inputScript","witnessUtxo","BitcoinScriptType","getScriptType","scriptPubKey","length","getPsbtInputFields","type","MEMPOOL_API_URLS","fetchApi","url","options","response","errorText","contentType","pushTx","apiUrl","message","getTxInfo","getTxHex","getUtxoInfo","vout","txInfo","getAddressUtxos","address","utxos","addressInfo","a","getMempoolApiUrl","getAddressTxs","getNetworkFees","data","BTCVaultsManagerABI","CONTRACT_ERRORS","extractErrorData","err","current","depth","maxDepth","cause","hexMatch","getContractErrorMessage","errorData","selector","isKnownContractError","handleContractError","knownError","errorMsg","errorHint","PeginManager","config","__publicField","params","depositorBtcPubkeyRaw","depositorBtcPubkey","vaultProviderBtcPubkey","stripHexPrefix","vaultKeeperBtcPubkeys","universalChallengerBtcPubkeys","prePeginParams","prePeginResult","buildPrePeginPsbt","utxoSelection","fundedPrePeginTxHex","fundPeginTransaction","prePeginTxid","peginTxResult","buildPeginTxFromFundedPrePegin","peginInputPsbtResult","buildPeginInputPsbt","signedPeginInputPsbtHex","peginInputSignature","extractPeginInputSignature","cleanPubkey","utxoDataPromises","utxoData","inputsWithUtxoData","psbtInputFields","signedPsbtHex","signedPsbt","e","inp","signedTxHex","unsignedPrePeginTx","depositorSignedPeginTx","vaultProvider","hashlock","onPopSigned","depositorPayoutBtcAddress","depositorLamportPkHash","preSignedBtcPopSignature","depositorEthAddress","btcPopSignature","depositorBtcPubkeyHex","ensureHexPrefix","unsignedPrePeginTxHex","depositorSignedPeginTxHex","payoutScriptPubKey","vaultId","publicClient","createPublicClient","http","peginFee","callData","encodeFunctionData","gasEstimate","zeroAddress","walletPubkey","isAddressFromPublicKey","bitcoin","verifyingContract","popMessage","btcPopSignatureRaw","PayoutManager","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","extractPayoutSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const y=require("@babylonlabs-io/babylon-tbv-rust-wasm"),f=require("bitcoinjs-lib"),a=require("buffer"),q=require("@bitcoin-js/tiny-secp256k1-asmjs");function L(t){const n=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const e in t)if(e!=="default"){const r=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(n,e,r.get?r:{enumerable:!0,get:()=>t[e]})}}return n.default=t,Object.freeze(n)}const _=L(f),T=L(q),D=58,M=43,X=11,$=546,O=BigInt($),R=30,F=2,Y=1.1;function z(t){return t<=F?R:0}const Z=5;function P(t){return t.startsWith("0x")?t.slice(2):t}function j(t){return t.startsWith("0x")?t:`0x${t}`}function g(t){const n=P(t);if(!E(n))throw new Error(`Invalid hex string: ${t}`);const e=new Uint8Array(n.length/2);for(let r=0;r<n.length;r+=2)e[r/2]=parseInt(n.slice(r,r+2),16);return e}function b(t){return Array.from(t).map(n=>n.toString(16).padStart(2,"0")).join("")}function N(t){return t.length===32?t:t.slice(1,33)}function E(t){return/^[0-9a-fA-F]*$/.test(t)&&t.length%2===0}function m(t){const n=P(t);if(!E(n))throw new Error(`Invalid hex characters in public key: ${t}`);if(n.length===64)return n;if(n.length!==66&&n.length!==130)throw new Error(`Invalid public key length: ${n.length} (expected 64, 66, or 130 hex chars)`);const e=g(n);return b(N(e))}function G(t){const n=P(t);return E(n)}function Q(t,n){const e=m(t),r=n??e;if(e.toLowerCase()!==r.toLowerCase())throw new Error(`Wallet public key does not match vault depositor. Expected: ${r}, Got: ${e}. Please connect the wallet that was used to create this vault.`);return{walletPubkeyRaw:t,walletPubkeyXOnly:e,depositorPubkey:r}}let U=!1;function J(){U||(f.initEccLib(T),U=!0)}function I(t){switch(t){case"bitcoin":return f.networks.bitcoin;case"testnet":case"signet":return f.networks.testnet;case"regtest":return f.networks.regtest;default:throw new Error(`Unknown network: ${t}`)}}function V(t,n){J();const e=g(m(t)),{address:r}=f.payments.p2tr({internalPubkey:a.Buffer.from(e),network:I(n)});if(!r)throw new Error("Failed to derive taproot address from public key");return r}function W(t,n){const e=P(t);if(e.length!==66)throw new Error(`Native SegWit requires a compressed public key (66 hex chars), got ${e.length}`);const{address:r}=f.payments.p2wpkh({pubkey:a.Buffer.from(g(e)),network:I(n)});if(!r)throw new Error("Failed to derive native segwit address from public key");return r}function tt(t,n,e){const r=P(n);try{if(t===V(r,e))return!0}catch{}const i=[];r.length===66?i.push(r):r.length===64&&i.push(`02${r}`,`03${r}`);for(const o of i)try{if(t===W(o,e))return!0}catch{}return!1}function B(t){const e=t.substring(8,12)==="0001"?12:8,r=parseInt(t.substring(e,e+2),16),i=parseInt(t.substring(e+2,e+4),16);if(r!==0)throw new Error(`Expected 0 inputs from WASM, got ${r}`);if(i===0)throw new Error("Expected at least 1 output from WASM, got 0");const o=a.Buffer.from(t.substring(0,8),"hex").readUInt32LE(0),c=a.Buffer.from(t.substring(t.length-8),"hex").readUInt32LE(0),u=[];let s=e+4;for(let p=0;p<i;p++){const l=t.substring(s,s+16),d=Number(a.Buffer.from(l,"hex").readBigUInt64LE(0));s+=16;const h=parseInt(t.substring(s,s+2),16);s+=2;const x=t.substring(s,s+h*2),k=a.Buffer.from(x,"hex");s+=h*2,u.push({value:d,script:k})}return{version:o,locktime:c,outputs:u}}function et(t){const{unfundedTxHex:n,selectedUTXOs:e,changeAddress:r,changeAmount:i,network:o}=t,{version:c,locktime:u,outputs:s}=B(n),p=new _.Transaction;p.version=c,p.locktime=u;for(const l of e){const d=a.Buffer.from(l.txid,"hex").reverse();p.addInput(d,l.vout)}for(const l of s)p.addOutput(l.script,l.value);if(i>O){const l=_.address.toOutputScript(r,o);p.addOutput(l,Number(i))}return p.toHex()}async function nt(t){const n=await y.createPrePeginTransaction({depositorPubkey:t.depositorPubkey,vaultProviderPubkey:t.vaultProviderPubkey,vaultKeeperPubkeys:t.vaultKeeperPubkeys,universalChallengerPubkeys:t.universalChallengerPubkeys,hashH:t.hashH,timelockRefund:t.timelockRefund,pegInAmount:t.pegInAmount,feeRate:t.feeRate,numLocalChallengers:t.numLocalChallengers,councilQuorum:t.councilQuorum,councilSize:t.councilSize,network:t.network}),r=B(n.txHex).outputs.reduce((i,o)=>i+BigInt(o.value),0n);return{psbtHex:n.txHex,totalOutputValue:r,htlcValue:n.htlcValue,htlcScriptPubKey:n.htlcScriptPubKey,htlcAddress:n.htlcAddress,peginAmount:n.peginAmount,depositorClaimValue:n.depositorClaimValue}}async function rt(t){const n=await y.buildPeginTxFromPrePegin({depositorPubkey:t.prePeginParams.depositorPubkey,vaultProviderPubkey:t.prePeginParams.vaultProviderPubkey,vaultKeeperPubkeys:t.prePeginParams.vaultKeeperPubkeys,universalChallengerPubkeys:t.prePeginParams.universalChallengerPubkeys,hashH:t.prePeginParams.hashH,timelockRefund:t.prePeginParams.timelockRefund,pegInAmount:t.prePeginParams.pegInAmount,feeRate:t.prePeginParams.feeRate,numLocalChallengers:t.prePeginParams.numLocalChallengers,councilQuorum:t.prePeginParams.councilQuorum,councilSize:t.prePeginParams.councilSize,network:t.prePeginParams.network},t.timelockPegin,t.fundedPrePeginTxid);return{txHex:n.txHex,txid:n.txid,vaultScriptPubKey:n.vaultScriptPubKey,vaultValue:n.vaultValue}}async function ot(t){const n=P(t.peginTxHex),e=P(t.fundedPrePeginTxHex),r=await y.getPrePeginHtlcConnectorInfo({depositorPubkey:t.depositorPubkey,vaultProviderPubkey:t.vaultProviderPubkey,vaultKeeperPubkeys:t.vaultKeeperPubkeys,universalChallengerPubkeys:t.universalChallengerPubkeys,hashH:t.hashH,timelockRefund:t.timelockRefund,network:t.network}),i=f.Transaction.fromHex(n),o=f.Transaction.fromHex(e);if(i.ins.length!==1)throw new Error(`PegIn transaction must have exactly 1 input, got ${i.ins.length}`);const c=i.ins[0],u=o.getId(),s=b(new Uint8Array(c.hash).slice().reverse());if(s!==u)throw new Error(`PegIn input does not reference the Pre-PegIn transaction. Expected ${u}, got ${s}`);const p=o.outs[c.index];if(!p)throw new Error(`Pre-PegIn output ${c.index} not found (Pre-PegIn has ${o.outs.length} outputs)`);const l=g(r.hashlockScript),d=g(r.hashlockControlBlock),h=new f.Psbt;h.setVersion(i.version),h.setLocktime(i.locktime),h.addInput({hash:c.hash,index:c.index,sequence:c.sequence,witnessUtxo:{script:p.script,value:p.value},tapLeafScript:[{leafVersion:192,script:a.Buffer.from(l),controlBlock:a.Buffer.from(d)}],tapInternalKey:a.Buffer.from(y.tapInternalPubkey)});for(const x of i.outs)h.addOutput({script:x.script,value:x.value});return{psbtHex:h.toHex()}}function it(t,n){const r=f.Psbt.fromHex(t).data.inputs[0];if(!r)throw new Error("PegIn PSBT has no inputs");if(r.tapScriptSig&&r.tapScriptSig.length>0){const i=a.Buffer.from(g(n));for(const o of r.tapScriptSig)if(o.pubkey.equals(i))return st(o.signature);throw new Error(`No PegIn input signature found for depositor pubkey: ${n}`)}throw r.finalScriptWitness&&r.finalScriptWitness.length>0?new Error("PegIn input PSBT is already finalized. Cannot reliably extract the depositor signature from the witness stack. Ensure the wallet returns a non-finalized PSBT with tapScriptSig entries."):new Error("No tapScriptSig or finalScriptWitness found in signed PegIn input PSBT")}function st(t){if(t.length===64)return b(new Uint8Array(t));if(t.length===65)return b(new Uint8Array(t.subarray(0,64)));throw new Error(`Unexpected PegIn input signature length: ${t.length}`)}async function K(t){const n=await y.createPayoutConnector({depositor:t.depositor,vaultProvider:t.vaultProvider,vaultKeepers:t.vaultKeepers,universalChallengers:t.universalChallengers,timelockPegin:t.timelockPegin},t.network);return{payoutScript:n.payoutScript,taprootScriptHash:n.taprootScriptHash,scriptPubKey:n.scriptPubKey,address:n.address}}f.initEccLib(T);async function ut(t){const n=P(t.payoutTxHex),e=P(t.peginTxHex),r=P(t.assertTxHex),i=await K({depositor:t.depositorBtcPubkey,vaultProvider:t.vaultProviderBtcPubkey,vaultKeepers:t.vaultKeeperBtcPubkeys,universalChallengers:t.universalChallengerBtcPubkeys,timelockPegin:t.timelockPegin,network:t.network}),o=g(i.payoutScript),c=lt(y.tapInternalPubkey,o),u=f.Transaction.fromHex(n),s=f.Transaction.fromHex(e),p=f.Transaction.fromHex(r),l=new f.Psbt;if(l.setVersion(u.version),l.setLocktime(u.locktime),u.ins.length!==2)throw new Error(`Payout transaction must have exactly 2 inputs, got ${u.ins.length}`);const d=u.ins[0],h=u.ins[1],x=b(new Uint8Array(d.hash).slice().reverse()),k=s.getId();if(x!==k)throw new Error(`Input 0 does not reference pegin transaction. Expected ${k}, got ${x}`);const w=b(new Uint8Array(h.hash).slice().reverse()),A=p.getId();if(w!==A)throw new Error(`Input 1 does not reference assert transaction. Expected ${A}, got ${w}`);const v=s.outs[d.index];if(!v)throw new Error(`Previous output not found for input 0 (txid: ${x}, index: ${d.index})`);const S=p.outs[h.index];if(!S)throw new Error(`Previous output not found for input 1 (txid: ${w}, index: ${h.index})`);l.addInput({hash:d.hash,index:d.index,sequence:d.sequence,witnessUtxo:{script:v.script,value:v.value},tapLeafScript:[{leafVersion:192,script:a.Buffer.from(o),controlBlock:a.Buffer.from(c)}],tapInternalKey:a.Buffer.from(y.tapInternalPubkey)}),l.addInput({hash:h.hash,index:h.index,sequence:h.sequence,witnessUtxo:{script:S.script,value:S.value}});for(const H of u.outs)l.addOutput({script:H.script,value:H.value});return{psbtHex:l.toHex()}}function ct(t,n,e=0){const r=f.Psbt.fromHex(t);if(e>=r.data.inputs.length)throw new Error(`Input index ${e} out of range (${r.data.inputs.length} inputs)`);const i=r.data.inputs[e];if(i.tapScriptSig&&i.tapScriptSig.length>0){const o=g(n);for(const c of i.tapScriptSig)if(c.pubkey.equals(a.Buffer.from(o)))return C(c.signature,e);throw new Error(`No signature found for depositor pubkey: ${n} at input ${e}`)}if(i.finalScriptWitness&&i.finalScriptWitness.length>0){const o=at(i.finalScriptWitness);if(o.length>=1)return C(o[0],e)}throw new Error(`No tapScriptSig or finalScriptWitness found in signed PSBT at input ${e}`)}function C(t,n){if(t.length===64)return b(new Uint8Array(t));if(t.length===65)return b(new Uint8Array(t.subarray(0,64)));throw new Error(`Unexpected signature length at input ${n}: ${t.length}`)}function at(t){const n=[];let e=0;const r=()=>{const o=t[e++];if(o<253)return o;if(o===253){const c=t[e]|t[e+1]<<8;return e+=2,c}if(o===254){const c=t[e]|t[e+1]<<8|t[e+2]<<16|t[e+3]<<24;return e+=4,c}return e+=8,0},i=r();for(let o=0;o<i;o++){const c=r();n.push(t.subarray(e,e+c)),e+=c}return n}function lt(t,n){const e={output:a.Buffer.from(n)},i=f.payments.p2tr({internalPubkey:a.Buffer.from(t),scriptTree:e}).pubkey;if(!i)throw new Error("Failed to compute output key");const o=192,c=i[0]===3?1:0,u=o|c,s=new Uint8Array(1+t.length);return s[0]=u,s.set(t,1),s}f.initEccLib(T);async function pt(t){const n=P(t.payoutTxHex),e=f.Transaction.fromHex(n),r=await y.getPeginPayoutScript(t.connectorParams),i=g(r),o=ft(y.tapInternalPubkey,i),c=new f.Psbt;c.setVersion(e.version),c.setLocktime(e.locktime);for(let u=0;u<e.ins.length;u++){const s=e.ins[u],p=t.prevouts[u];if(!p)throw new Error(`Missing prevout data for input ${u}`);const l={hash:s.hash,index:s.index,sequence:s.sequence,witnessUtxo:{script:a.Buffer.from(g(P(p.script_pubkey))),value:p.value}};u===0&&(l.tapLeafScript=[{leafVersion:192,script:a.Buffer.from(i),controlBlock:a.Buffer.from(o)}],l.tapInternalKey=a.Buffer.from(y.tapInternalPubkey)),c.addInput(l)}for(const u of e.outs)c.addOutput({script:u.script,value:u.value});return c.toHex()}function ft(t,n){const e={output:a.Buffer.from(n)},i=f.payments.p2tr({internalPubkey:a.Buffer.from(t),scriptTree:e}).pubkey;if(!i)throw new Error("Failed to compute output key");const o=192,c=i[0]===3?1:0,u=o|c,s=new Uint8Array(1+t.length);return s[0]=u,s.set(t,1),s}async function dt(t){const n=P(t.noPayoutTxHex),e=f.Transaction.fromHex(n),{noPayoutScript:r,noPayoutControlBlock:i}=await y.getAssertNoPayoutScriptInfo(t.connectorParams,t.challengerPubkey),o=g(r),c=g(i),u=new f.Psbt;u.setVersion(e.version),u.setLocktime(e.locktime);for(let s=0;s<e.ins.length;s++){const p=e.ins[s],l=t.prevouts[s];if(!l)throw new Error(`Missing prevout data for input ${s}`);const d={hash:p.hash,index:p.index,sequence:p.sequence,witnessUtxo:{script:a.Buffer.from(g(P(l.script_pubkey))),value:l.value}};s===0&&(d.tapLeafScript=[{leafVersion:192,script:a.Buffer.from(o),controlBlock:a.Buffer.from(c)}],d.tapInternalKey=a.Buffer.from(y.tapInternalPubkey)),u.addInput(d)}for(const s of e.outs)u.addOutput({script:s.script,value:s.value});return u.toHex()}async function Pt(t){const n=P(t.challengeAssertTxHex),e=f.Transaction.fromHex(n);if(t.connectorParamsPerInput.length!==e.ins.length)throw new Error(`Expected ${e.ins.length} connector params, got ${t.connectorParamsPerInput.length}`);const r=await Promise.all(t.connectorParamsPerInput.map(o=>y.getChallengeAssertScriptInfo(o))),i=new f.Psbt;i.setVersion(e.version),i.setLocktime(e.locktime);for(let o=0;o<e.ins.length;o++){const c=e.ins[o],u=t.prevouts[o];if(!u)throw new Error(`Missing prevout data for input ${o}`);const{script:s,controlBlock:p}=r[o],l=g(s),d=g(p);i.addInput({hash:c.hash,index:c.index,sequence:c.sequence,witnessUtxo:{script:a.Buffer.from(g(P(u.script_pubkey))),value:u.value},tapLeafScript:[{leafVersion:192,script:a.Buffer.from(l),controlBlock:a.Buffer.from(d)}],tapInternalKey:a.Buffer.from(y.tapInternalPubkey)})}for(const o of e.outs)i.addOutput({script:o.script,value:o.value});return i.toHex()}exports.BTC_DUST_SAT=$;exports.DUST_THRESHOLD=O;exports.FEE_SAFETY_MARGIN=Y;exports.LOW_RATE_ESTIMATION_ACCURACY_BUFFER=R;exports.MAX_NON_LEGACY_OUTPUT_SIZE=M;exports.P2TR_INPUT_SIZE=D;exports.SPLIT_TX_FEE_SAFETY_MULTIPLIER=Z;exports.TX_BUFFER_SIZE_OVERHEAD=X;exports.WALLET_RELAY_FEE_RATE_THRESHOLD=F;exports.buildChallengeAssertPsbt=Pt;exports.buildDepositorPayoutPsbt=pt;exports.buildNoPayoutPsbt=dt;exports.buildPayoutPsbt=ut;exports.buildPeginInputPsbt=ot;exports.buildPeginTxFromFundedPrePegin=rt;exports.buildPrePeginPsbt=nt;exports.createPayoutScript=K;exports.deriveNativeSegwitAddress=W;exports.deriveTaprootAddress=V;exports.ensureHexPrefix=j;exports.extractPayoutSignature=ct;exports.extractPeginInputSignature=it;exports.fundPeginTransaction=et;exports.getNetwork=I;exports.hexToUint8Array=g;exports.isAddressFromPublicKey=tt;exports.isValidHex=G;exports.parseUnfundedWasmTransaction=B;exports.processPublicKeyToXOnly=m;exports.rateBasedTxBufferFee=z;exports.stripHexPrefix=P;exports.toXOnly=N;exports.uint8ArrayToHex=b;exports.validateWalletPubkey=Q;
|
|
2
|
+
//# sourceMappingURL=challengeAssert-DOa5L0kv.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"challengeAssert-DOa5L0kv.cjs","sources":["../src/tbv/core/utils/fee/constants.ts","../src/tbv/core/primitives/utils/bitcoin.ts","../src/tbv/core/utils/transaction/fundPeginTransaction.ts","../src/tbv/core/primitives/psbt/pegin.ts","../src/tbv/core/primitives/psbt/peginInput.ts","../src/tbv/core/primitives/scripts/payout.ts","../src/tbv/core/primitives/psbt/payout.ts","../src/tbv/core/primitives/psbt/depositorPayout.ts","../src/tbv/core/primitives/psbt/noPayout.ts","../src/tbv/core/primitives/psbt/challengeAssert.ts"],"sourcesContent":["/**\n * Fee calculation constants for Bitcoin transactions.\n * Based on btc-staking-ts values, adapted for vault peg-in transactions.\n */\n\n// P2TR input size in vbytes (42 vbytes non-witness + 16 vbytes witness)\nexport const P2TR_INPUT_SIZE = 58;\n\n// P2TR output size in bytes (largest non-legacy output type)\nexport const MAX_NON_LEGACY_OUTPUT_SIZE = 43;\n\n// Base transaction overhead (version, input/output counts, locktime, SegWit marker)\nexport const TX_BUFFER_SIZE_OVERHEAD = 11;\n\n// Dust threshold: outputs below this may not be relayed\nexport const BTC_DUST_SAT = 546;\n\n/** Pre-computed BigInt dust threshold to avoid repeated conversions in hot paths */\nexport const DUST_THRESHOLD = BigInt(BTC_DUST_SAT);\n\n// Buffer for low fee rate estimation accuracy (when feeRate <= 2 sat/vbyte)\nexport const LOW_RATE_ESTIMATION_ACCURACY_BUFFER = 30;\n\n// Wallet relay fee rate threshold - different buffer fees are used based on this\nexport const WALLET_RELAY_FEE_RATE_THRESHOLD = 2;\n\n// Safety margin: 10% buffer for size variations and fee market volatility\nexport const FEE_SAFETY_MARGIN = 1.1;\n\n/**\n * Adds a buffer to the transaction fee calculation if the fee rate is low.\n *\n * Some wallets have a relayer fee requirement. If the fee rate is <= 2 sat/vbyte,\n * there's a risk the fee might not be sufficient for transaction relay.\n * We add a buffer to ensure the transaction can be relayed.\n *\n * @param feeRate - Fee rate in satoshis per vbyte\n * @returns Buffer amount in satoshis to add to the transaction fee\n */\nexport function rateBasedTxBufferFee(feeRate: number): number {\n return feeRate <= WALLET_RELAY_FEE_RATE_THRESHOLD\n ? LOW_RATE_ESTIMATION_ACCURACY_BUFFER\n : 0;\n}\n\n/**\n * Safety multiplier for split transaction fee validation.\n * The signed PSBT's fee rate and absolute fee must not exceed this multiple\n * of the planned values. 5x accounts for witness estimation variance while\n * catching catastrophic wallet-side overpayment.\n */\nexport const SPLIT_TX_FEE_SAFETY_MULTIPLIER = 5;\n","/**\n * Bitcoin Utilities\n *\n * Common pure utility functions for Bitcoin operations including:\n * - Public key conversions (x-only format)\n * - Hex string manipulation\n * - Uint8Array conversions and validation\n * - Address derivation and validation\n *\n * All functions are pure (no side effects) and work in Node.js, browsers,\n * and serverless environments.\n *\n * @module primitives/utils/bitcoin\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { Buffer } from \"buffer\";\nimport { initEccLib, networks, payments } from \"bitcoinjs-lib\";\n\nimport type { Network } from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport type { Hex } from \"viem\";\n\n/**\n * Strip \"0x\" prefix from hex string if present.\n *\n * Bitcoin expects plain hex (no \"0x\" prefix), but frontend often uses\n * Ethereum-style \"0x\"-prefixed hex.\n *\n * @param hex - Hex string with or without \"0x\" prefix\n * @returns Hex string without \"0x\" prefix\n */\nexport function stripHexPrefix(hex: string): string {\n return hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n}\n\n/**\n * Ensure \"0x\" prefix on a hex string, returning viem's Hex type.\n *\n * Ethereum/viem APIs expect `0x`-prefixed hex, but Bitcoin tooling\n * typically omits the prefix. This normalises either form.\n *\n * @param hex - Hex string with or without \"0x\" prefix\n * @returns `0x`-prefixed hex string typed as viem Hex\n */\nexport function ensureHexPrefix(hex: string): Hex {\n return hex.startsWith(\"0x\") ? (hex as Hex) : (`0x${hex}` as Hex);\n}\n\n/**\n * Convert hex string to Uint8Array.\n *\n * @param hex - Hex string (with or without 0x prefix)\n * @returns Uint8Array\n * @throws If hex is invalid\n */\nexport function hexToUint8Array(hex: string): Uint8Array {\n const cleanHex = stripHexPrefix(hex);\n if (!isValidHexRaw(cleanHex)) {\n throw new Error(`Invalid hex string: ${hex}`);\n }\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.slice(i, i + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Convert Uint8Array to hex string (without 0x prefix).\n *\n * @param bytes - Uint8Array to convert\n * @returns Hex string without 0x prefix\n */\nexport function uint8ArrayToHex(bytes: Uint8Array): string {\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\n/**\n * Convert a 33-byte public key to 32-byte x-only format (removes first byte).\n *\n * Used for Taproot/Schnorr signatures which only need the x-coordinate.\n * If the input is already 32 bytes, returns it unchanged.\n *\n * @param pubKey - 33-byte or 32-byte public key\n * @returns 32-byte x-only public key\n */\nexport function toXOnly(pubKey: Uint8Array): Uint8Array {\n return pubKey.length === 32 ? pubKey : pubKey.slice(1, 33);\n}\n\n/**\n * Internal helper: Validate hex string format without stripping prefix\n *\n * @internal\n * @param hex - Hex string (must already have prefix stripped)\n * @returns true if valid hex string\n */\nfunction isValidHexRaw(hex: string): boolean {\n return /^[0-9a-fA-F]*$/.test(hex) && hex.length % 2 === 0;\n}\n\n/**\n * Process and convert a public key to x-only format (32 bytes hex).\n *\n * Handles:\n * - 0x prefix removal\n * - Hex character validation\n * - Length validation\n * - Conversion to x-only format\n *\n * Accepts:\n * - 64 hex chars (32 bytes) - already x-only\n * - 66 hex chars (33 bytes) - compressed pubkey\n * - 130 hex chars (65 bytes) - uncompressed pubkey\n *\n * @param publicKeyHex - Public key in hex format (with or without 0x prefix)\n * @returns X-only public key as 32 bytes hex string (without 0x prefix)\n * @throws If public key format is invalid or contains invalid hex characters\n */\nexport function processPublicKeyToXOnly(publicKeyHex: string): string {\n // Remove '0x' prefix if present\n const cleanHex = stripHexPrefix(publicKeyHex);\n\n // Validate hex characters early to prevent silent failures\n if (!isValidHexRaw(cleanHex)) {\n throw new Error(`Invalid hex characters in public key: ${publicKeyHex}`);\n }\n\n // If already 64 chars (32 bytes), it's already x-only format\n if (cleanHex.length === 64) {\n return cleanHex;\n }\n\n // Validate public key length (should be 66 chars for compressed or 130 for uncompressed)\n if (cleanHex.length !== 66 && cleanHex.length !== 130) {\n throw new Error(\n `Invalid public key length: ${cleanHex.length} (expected 64, 66, or 130 hex chars)`,\n );\n }\n\n const pubkeyBytes = hexToUint8Array(cleanHex);\n return uint8ArrayToHex(toXOnly(pubkeyBytes));\n}\n\n/**\n * Validate hex string format.\n *\n * Checks that the string contains only valid hexadecimal characters (0-9, a-f, A-F)\n * and has an even length (since each byte is represented by 2 hex characters).\n *\n * @param hex - String to validate (with or without 0x prefix)\n * @returns true if valid hex string\n */\nexport function isValidHex(hex: string): boolean {\n const cleanHex = stripHexPrefix(hex);\n return isValidHexRaw(cleanHex);\n}\n\n/**\n * Result of validating a wallet public key against an expected depositor public key.\n */\nexport interface WalletPubkeyValidationResult {\n /** Wallet's raw public key (as returned by wallet, may be compressed) */\n walletPubkeyRaw: string;\n /** Wallet's public key in x-only format (32 bytes, 64 hex chars) */\n walletPubkeyXOnly: string;\n /** The validated depositor public key (x-only format) */\n depositorPubkey: string;\n}\n\n/**\n * Validate that a wallet's public key matches the expected depositor public key.\n *\n * This function:\n * 1. Converts the wallet pubkey to x-only format\n * 2. Uses the expected depositor pubkey if provided, otherwise falls back to wallet pubkey\n * 3. Validates they match (case-insensitive)\n *\n * @param walletPubkeyRaw - Raw public key from wallet (may be compressed 66 chars or x-only 64 chars)\n * @param expectedDepositorPubkey - Expected depositor public key (x-only, optional)\n * @returns Validation result with both pubkey formats\n * @throws If wallet pubkey doesn't match expected depositor pubkey\n */\nexport function validateWalletPubkey(\n walletPubkeyRaw: string,\n expectedDepositorPubkey?: string,\n): WalletPubkeyValidationResult {\n const walletPubkeyXOnly = processPublicKeyToXOnly(walletPubkeyRaw);\n const depositorPubkey = expectedDepositorPubkey ?? walletPubkeyXOnly;\n\n if (walletPubkeyXOnly.toLowerCase() !== depositorPubkey.toLowerCase()) {\n throw new Error(\n `Wallet public key does not match vault depositor. ` +\n `Expected: ${depositorPubkey}, Got: ${walletPubkeyXOnly}. ` +\n `Please connect the wallet that was used to create this vault.`\n );\n }\n\n return { walletPubkeyRaw, walletPubkeyXOnly, depositorPubkey };\n}\n\n// ============================================================================\n// Address derivation and validation\n// ============================================================================\n\nlet eccInitialized = false;\n\nfunction ensureEcc(): void {\n if (!eccInitialized) {\n initEccLib(ecc);\n eccInitialized = true;\n }\n}\n\n/**\n * Map SDK network type to bitcoinjs-lib Network object.\n *\n * @param network - Network type (\"bitcoin\", \"testnet\", \"signet\", \"regtest\")\n * @returns bitcoinjs-lib Network object\n */\nexport function getNetwork(network: Network): networks.Network {\n switch (network) {\n case \"bitcoin\":\n return networks.bitcoin;\n case \"testnet\":\n case \"signet\":\n return networks.testnet;\n case \"regtest\":\n return networks.regtest;\n default:\n throw new Error(`Unknown network: ${network}`);\n }\n}\n\n/**\n * Derive a Taproot (P2TR) address from a public key.\n *\n * @param publicKeyHex - Compressed (66 hex) or x-only (64 hex) public key\n * @param network - Bitcoin network\n * @returns Taproot address (bc1p... / tb1p... / bcrt1p...)\n */\nexport function deriveTaprootAddress(\n publicKeyHex: string,\n network: Network,\n): string {\n ensureEcc();\n const xOnly = hexToUint8Array(processPublicKeyToXOnly(publicKeyHex));\n const { address } = payments.p2tr({\n internalPubkey: Buffer.from(xOnly),\n network: getNetwork(network),\n });\n if (!address) {\n throw new Error(\"Failed to derive taproot address from public key\");\n }\n return address;\n}\n\n/**\n * Derive a Native SegWit (P2WPKH) address from a compressed public key.\n *\n * @param publicKeyHex - Compressed public key (66 hex chars, with or without 0x prefix)\n * @param network - Bitcoin network\n * @returns Native SegWit address (bc1q... / tb1q... / bcrt1q...)\n * @throws If publicKeyHex is not a compressed public key (66 hex chars)\n */\nexport function deriveNativeSegwitAddress(\n publicKeyHex: string,\n network: Network,\n): string {\n const cleanHex = stripHexPrefix(publicKeyHex);\n if (cleanHex.length !== 66) {\n throw new Error(\n `Native SegWit requires a compressed public key (66 hex chars), got ${cleanHex.length}`,\n );\n }\n const { address } = payments.p2wpkh({\n pubkey: Buffer.from(hexToUint8Array(cleanHex)),\n network: getNetwork(network),\n });\n if (!address) {\n throw new Error(\n \"Failed to derive native segwit address from public key\",\n );\n }\n return address;\n}\n\n/**\n * Validate that a BTC address was derived from the given public key.\n *\n * Derives Taproot (P2TR) and Native SegWit (P2WPKH) addresses from the\n * public key and checks if the provided address matches any of them.\n *\n * When the input is an x-only key (64 hex chars), both possible compressed\n * keys (`02` + x and `03` + x) are tried for Native SegWit derivation,\n * since the y-parity is unknown.\n *\n * @param address - BTC address to validate\n * @param publicKeyHex - Public key from the wallet (x-only 64 or compressed 66 hex chars)\n * @param network - Bitcoin network\n * @returns true if the address matches the public key\n */\nexport function isAddressFromPublicKey(\n address: string,\n publicKeyHex: string,\n network: Network,\n): boolean {\n const cleanHex = stripHexPrefix(publicKeyHex);\n\n // P2TR — works with both x-only and compressed keys\n try {\n if (address === deriveTaprootAddress(cleanHex, network)) {\n return true;\n }\n } catch {\n // derivation failed, continue\n }\n\n // Build the list of compressed keys to try for P2WPKH\n const compressedKeys: string[] = [];\n if (cleanHex.length === 66) {\n compressedKeys.push(cleanHex);\n } else if (cleanHex.length === 64) {\n // x-only key — try both even (02) and odd (03) y-parity\n compressedKeys.push(`02${cleanHex}`, `03${cleanHex}`);\n }\n\n for (const key of compressedKeys) {\n try {\n if (address === deriveNativeSegwitAddress(key, network)) {\n return true;\n }\n } catch {\n // derivation failed, continue\n }\n }\n\n return false;\n}\n","/**\n * Transaction Funding Utility for Peg-in Transactions\n *\n * This module funds an unfunded transaction template from the SDK by adding\n * UTXO inputs and change outputs, creating a transaction ready for wallet signing.\n *\n * Transaction Flow:\n * 1. SDK buildPeginPsbt() → unfunded transaction (0 inputs, vault + depositor claim outputs)\n * 2. selectUtxosForPegin() → select UTXOs and calculate fees\n * 3. fundPeginTransaction() → add inputs/change, create funded transaction\n *\n * Technical Note:\n * We manually extract the vault output from SDK hex instead of using bitcoinjs-lib\n * parsing because bitcoinjs-lib cannot parse 0-input transactions (even witness format).\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport { DUST_THRESHOLD } from \"../fee/constants\";\nimport type { UTXO } from \"../utxo/selectUtxos\";\n\nexport interface FundPeginTransactionParams {\n /** Unfunded transaction hex from SDK (0 inputs, vault + depositor claim outputs) */\n unfundedTxHex: string;\n /** Selected UTXOs to use as inputs */\n selectedUTXOs: UTXO[];\n /** Change address (from wallet) */\n changeAddress: string;\n /** Change amount in satoshis */\n changeAmount: bigint;\n /** Bitcoin network */\n network: bitcoin.Network;\n}\n\n/** A single parsed output from the unfunded WASM transaction */\ninterface ParsedOutput {\n value: number;\n script: Buffer;\n}\n\n/** Parsed data from an unfunded WASM transaction */\ninterface ParsedUnfundedTx {\n version: number;\n locktime: number;\n outputs: ParsedOutput[];\n}\n\n/**\n * Parses an unfunded transaction hex from WASM.\n *\n * WASM produces witness-format transactions with 0 inputs, which bitcoinjs-lib cannot parse.\n * This function manually extracts the transaction components.\n *\n * Format: [version:4bytes][marker:0x00][flag:0x01][inputs:1byte=0x00][outputCount:1byte]\n * [output1: value:8bytes + scriptLen:1byte + script:N bytes]\n * [output2: ...]\n * [locktime:4bytes]\n *\n * @param unfundedTxHex - Raw transaction hex from WASM\n * @returns Parsed transaction components\n * @throws Error if transaction structure is invalid\n */\nexport function parseUnfundedWasmTransaction(\n unfundedTxHex: string,\n): ParsedUnfundedTx {\n // Check if witness markers are present (0x00 0x01 after version)\n const hasWitnessMarkers = unfundedTxHex.substring(8, 12) === \"0001\";\n const dataOffset = hasWitnessMarkers ? 12 : 8; // Skip version (8) + optional witness markers (4)\n\n // Parse input/output counts\n const inputCount = parseInt(\n unfundedTxHex.substring(dataOffset, dataOffset + 2),\n 16,\n );\n const outputCount = parseInt(\n unfundedTxHex.substring(dataOffset + 2, dataOffset + 4),\n 16,\n );\n\n if (inputCount !== 0) {\n throw new Error(`Expected 0 inputs from WASM, got ${inputCount}`);\n }\n if (outputCount === 0) {\n throw new Error(\"Expected at least 1 output from WASM, got 0\");\n }\n\n // Parse version (first 4 bytes, little-endian)\n const version = Buffer.from(unfundedTxHex.substring(0, 8), \"hex\").readUInt32LE(0);\n\n // Parse locktime (last 4 bytes, little-endian)\n const locktime = Buffer.from(\n unfundedTxHex.substring(unfundedTxHex.length - 8),\n \"hex\",\n ).readUInt32LE(0);\n\n // Parse all outputs sequentially\n const outputs: ParsedOutput[] = [];\n let pos = dataOffset + 4; // position after input/output counts\n\n for (let i = 0; i < outputCount; i++) {\n const valueHex = unfundedTxHex.substring(pos, pos + 16);\n const value = Number(Buffer.from(valueHex, \"hex\").readBigUInt64LE(0));\n pos += 16;\n\n const scriptLen = parseInt(unfundedTxHex.substring(pos, pos + 2), 16);\n pos += 2;\n\n const scriptHex = unfundedTxHex.substring(pos, pos + scriptLen * 2);\n const script = Buffer.from(scriptHex, \"hex\");\n pos += scriptLen * 2;\n\n outputs.push({ value, script });\n }\n\n return { version, locktime, outputs };\n}\n\n/**\n * Funds an unfunded peg-in transaction by adding inputs and change output.\n *\n * Takes an unfunded transaction template (0 inputs, 1 vault output) from the SDK\n * and adds UTXO inputs and a change output to create a funded transaction ready\n * for wallet signing.\n *\n * @param params - Transaction funding parameters\n * @returns Transaction hex string ready for wallet signing\n */\nexport function fundPeginTransaction(\n params: FundPeginTransactionParams,\n): string {\n const { unfundedTxHex, selectedUTXOs, changeAddress, changeAmount, network } =\n params;\n\n // Parse the unfunded transaction from WASM\n const { version, locktime, outputs } =\n parseUnfundedWasmTransaction(unfundedTxHex);\n\n // Create a new transaction with the extracted data\n const tx = new bitcoin.Transaction();\n tx.version = version;\n tx.locktime = locktime;\n\n // Add inputs from selected UTXOs\n for (const utxo of selectedUTXOs) {\n // Bitcoin uses reversed byte order for txid\n const txHash = Buffer.from(utxo.txid, \"hex\").reverse();\n tx.addInput(txHash, utxo.vout);\n }\n\n // Add all WASM outputs (vault output at index 0, depositor claim at index 1, etc.)\n for (const output of outputs) {\n tx.addOutput(output.script, output.value);\n }\n\n // Add change output if above dust threshold\n if (changeAmount > DUST_THRESHOLD) {\n const changeScript = bitcoin.address.toOutputScript(changeAddress, network);\n tx.addOutput(changeScript, Number(changeAmount));\n }\n\n return tx.toHex();\n}\n\n// Re-export getNetwork from the canonical location in primitives\nexport { getNetwork } from \"../../primitives/utils/bitcoin\";\n","/**\n * Pre-PegIn PSBT Builder Primitive\n *\n * This module provides pure functions for building unfunded Pre-PegIn transactions\n * and deriving PegIn transactions from them, using the WASM implementation from\n * @babylonlabs-io/babylon-tbv-rust-wasm.\n *\n * Atomic Swap Flow:\n * 1. buildPrePeginPsbt() — creates unfunded Pre-PegIn tx (HTLC output)\n * 2. [caller funds Pre-PegIn tx and computes txid]\n * 3. buildPeginTxFromFundedPrePegin() — derives PegIn tx spending the HTLC\n * 4. buildPeginInputPsbt() — PSBT for depositor to sign PegIn HTLC leaf 0 input\n *\n * @module primitives/psbt/pegin\n */\n\nimport {\n createPrePeginTransaction,\n buildPeginTxFromPrePegin,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\nimport { parseUnfundedWasmTransaction } from \"../../utils/transaction/fundPeginTransaction\";\n\n/**\n * Parameters for building an unfunded Pre-PegIn PSBT\n */\nexport interface PrePeginParams {\n /** Depositor's BTC public key (x-only, 64-char hex without 0x prefix) */\n depositorPubkey: string;\n /** Vault provider's BTC public key (x-only, 64-char hex) */\n vaultProviderPubkey: string;\n /** Array of vault keeper BTC public keys (x-only, 64-char hex) */\n vaultKeeperPubkeys: string[];\n /** Array of universal challenger BTC public keys (x-only, 64-char hex) */\n universalChallengerPubkeys: string[];\n /** SHA256 hash commitment (64 hex chars = 32 bytes) */\n hashH: string;\n /** CSV timelock in blocks for the HTLC refund path */\n timelockRefund: number;\n /** Amount to peg in (satoshis) */\n pegInAmount: bigint;\n /** Fee rate in sat/vB from contract offchain params */\n feeRate: bigint;\n /** Number of local challengers (from contract params) */\n numLocalChallengers: number;\n /** M in M-of-N council multisig (from contract params) */\n councilQuorum: number;\n /** N in M-of-N council multisig (from contract params) */\n councilSize: number;\n /** Bitcoin network */\n network: Network;\n}\n\n/**\n * Result of building an unfunded Pre-PegIn transaction\n */\nexport interface PrePeginPsbtResult {\n /**\n * Unfunded transaction hex (no inputs, HTLC output + CPFP anchor).\n *\n * The caller is responsible for:\n * - Selecting UTXOs covering totalOutputValue + network fees\n * - Funding the transaction (add inputs and change output)\n * - Computing the funded transaction's txid\n * - Calling buildPeginTxFromFundedPrePegin() with the funded txid\n */\n psbtHex: string;\n /** Sum of all unfunded outputs (HTLC + CPFP anchor) — use this for UTXO selection */\n totalOutputValue: bigint;\n /** HTLC output value in satoshis (output 0 only, includes peginAmount + depositorClaimValue + minPeginFee) */\n htlcValue: bigint;\n /** HTLC output scriptPubKey (hex encoded) */\n htlcScriptPubKey: string;\n /** HTLC Taproot address */\n htlcAddress: string;\n /** Pegin amount in satoshis */\n peginAmount: bigint;\n /** Depositor claim value computed by WASM from contract parameters */\n depositorClaimValue: bigint;\n}\n\n/**\n * Parameters for building the PegIn transaction from a funded Pre-PegIn txid\n */\nexport interface BuildPeginTxParams {\n /** Same PrePeginParams used to create the Pre-PegIn transaction */\n prePeginParams: PrePeginParams;\n /** CSV timelock in blocks for the PegIn vault output */\n timelockPegin: number;\n /** Txid of the funded Pre-PegIn transaction (hex, 64 chars) */\n fundedPrePeginTxid: string;\n}\n\n/**\n * Result of building the PegIn transaction\n */\nexport interface PeginTxResult {\n /** PegIn transaction hex (1 input spending HTLC, 1 vault output) */\n txHex: string;\n /** PegIn transaction ID */\n txid: string;\n /** Vault output scriptPubKey (hex encoded) */\n vaultScriptPubKey: string;\n /** Vault output value in satoshis */\n vaultValue: bigint;\n}\n\n/**\n * Build unfunded Pre-PegIn transaction using WASM.\n *\n * Creates a Bitcoin transaction template with no inputs, an HTLC output, and a\n * CPFP anchor output. The HTLC value is computed internally from the contract\n * parameters — the caller does not need to compute depositorClaimValue separately.\n *\n * @param params - Pre-PegIn parameters\n * @returns Unfunded Pre-PegIn transaction details with HTLC output information\n * @throws If WASM initialization fails or parameters are invalid\n */\nexport async function buildPrePeginPsbt(\n params: PrePeginParams,\n): Promise<PrePeginPsbtResult> {\n const result = await createPrePeginTransaction({\n depositorPubkey: params.depositorPubkey,\n vaultProviderPubkey: params.vaultProviderPubkey,\n vaultKeeperPubkeys: params.vaultKeeperPubkeys,\n universalChallengerPubkeys: params.universalChallengerPubkeys,\n hashH: params.hashH,\n timelockRefund: params.timelockRefund,\n pegInAmount: params.pegInAmount,\n feeRate: params.feeRate,\n numLocalChallengers: params.numLocalChallengers,\n councilQuorum: params.councilQuorum,\n councilSize: params.councilSize,\n network: params.network,\n });\n\n // Parse the unfunded tx to sum all output values (HTLC + CPFP anchor).\n // This is the amount UTXOs must cover before adding network fees.\n const parsed = parseUnfundedWasmTransaction(result.txHex);\n const totalOutputValue = parsed.outputs.reduce(\n (sum, o) => sum + BigInt(o.value),\n 0n,\n );\n\n return {\n psbtHex: result.txHex,\n totalOutputValue,\n htlcValue: result.htlcValue,\n htlcScriptPubKey: result.htlcScriptPubKey,\n htlcAddress: result.htlcAddress,\n peginAmount: result.peginAmount,\n depositorClaimValue: result.depositorClaimValue,\n };\n}\n\n/**\n * Build the PegIn transaction from a funded Pre-PegIn txid.\n *\n * The PegIn transaction spends Pre-PegIn output 0 via the HTLC hashlock leaf (leaf 0).\n * Since Pre-PegIn inputs must be SegWit/Taproot, the txid is stable after funding.\n *\n * @param params - Build parameters including Pre-PegIn params and funded txid\n * @returns PegIn transaction details\n * @throws If WASM initialization fails or parameters are invalid\n */\nexport async function buildPeginTxFromFundedPrePegin(\n params: BuildPeginTxParams,\n): Promise<PeginTxResult> {\n const result = await buildPeginTxFromPrePegin(\n {\n depositorPubkey: params.prePeginParams.depositorPubkey,\n vaultProviderPubkey: params.prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: params.prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys: params.prePeginParams.universalChallengerPubkeys,\n hashH: params.prePeginParams.hashH,\n timelockRefund: params.prePeginParams.timelockRefund,\n pegInAmount: params.prePeginParams.pegInAmount,\n feeRate: params.prePeginParams.feeRate,\n numLocalChallengers: params.prePeginParams.numLocalChallengers,\n councilQuorum: params.prePeginParams.councilQuorum,\n councilSize: params.prePeginParams.councilSize,\n network: params.prePeginParams.network,\n },\n params.timelockPegin,\n params.fundedPrePeginTxid,\n );\n\n return {\n txHex: result.txHex,\n txid: result.txid,\n vaultScriptPubKey: result.vaultScriptPubKey,\n vaultValue: result.vaultValue,\n };\n}\n","/**\n * PegIn Input PSBT Builder\n *\n * Builds the PSBT for the depositor to sign the PegIn transaction's HTLC input\n * (Pre-PegIn HTLC leaf 0 — the hashlock + all-party script).\n *\n * This is the \"Sign Pegin transaction HTLC leaf 0 input\" step in the atomic\n * swap activation flow. The depositor signs input 0 of the PegIn transaction,\n * which spends output 0 of the funded Pre-PegIn transaction via script-path.\n *\n * @module primitives/psbt/peginInput\n */\n\nimport {\n getPrePeginHtlcConnectorInfo,\n tapInternalPubkey,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { hexToUint8Array, stripHexPrefix, uint8ArrayToHex } from \"../utils/bitcoin\";\n\n/**\n * Parameters for building the PegIn input PSBT\n */\nexport interface BuildPeginInputPsbtParams {\n /**\n * PegIn transaction hex (1 input spending Pre-PegIn HTLC output 0).\n * Returned by buildPeginTxFromFundedPrePegin().\n */\n peginTxHex: string;\n /**\n * Funded Pre-PegIn transaction hex.\n * Used to look up the HTLC output that the PegIn input spends.\n */\n fundedPrePeginTxHex: string;\n /** Depositor's BTC public key (x-only, 64-char hex) */\n depositorPubkey: string;\n /** Vault provider's BTC public key (x-only, 64-char hex) */\n vaultProviderPubkey: string;\n /** Vault keeper BTC public keys (x-only, 64-char hex) */\n vaultKeeperPubkeys: string[];\n /** Universal challenger BTC public keys (x-only, 64-char hex) */\n universalChallengerPubkeys: string[];\n /** SHA256 hash commitment (64 hex chars = 32 bytes) */\n hashH: string;\n /** CSV timelock in blocks for the HTLC refund path */\n timelockRefund: number;\n /** Bitcoin network */\n network: Network;\n}\n\n/**\n * Result of building the PegIn input PSBT\n */\nexport interface BuildPeginInputPsbtResult {\n /** PSBT hex for the depositor to sign */\n psbtHex: string;\n}\n\n/**\n * Build PSBT for depositor to sign the PegIn transaction's HTLC leaf 0 input.\n *\n * The PegIn transaction spends the Pre-PegIn HTLC output (output 0) via the\n * hashlock + all-party script (leaf 0). The depositor provides one of the required\n * signatures; the vault provider and keepers provide theirs separately via the\n * signPeginInput RPC.\n *\n * The PSBT uses Taproot script-path spending:\n * - witnessUtxo: the Pre-PegIn HTLC output\n * - tapLeafScript: hashlock leaf script + control block\n * - tapInternalKey: NUMS unspendable key (BIP-341 nothing-up-my-sleeve)\n *\n * @param params - PegIn input PSBT parameters\n * @returns PSBT hex ready for depositor signing\n * @throws If PegIn tx does not have exactly 1 input\n * @throws If PegIn input does not reference the Pre-PegIn HTLC output\n * @throws If Pre-PegIn tx output 0 is not found\n */\nexport async function buildPeginInputPsbt(\n params: BuildPeginInputPsbtParams,\n): Promise<BuildPeginInputPsbtResult> {\n const peginTxHex = stripHexPrefix(params.peginTxHex);\n const fundedPrePeginTxHex = stripHexPrefix(params.fundedPrePeginTxHex);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n depositorPubkey: params.depositorPubkey,\n vaultProviderPubkey: params.vaultProviderPubkey,\n vaultKeeperPubkeys: params.vaultKeeperPubkeys,\n universalChallengerPubkeys: params.universalChallengerPubkeys,\n hashH: params.hashH,\n timelockRefund: params.timelockRefund,\n network: params.network,\n });\n\n const peginTx = Transaction.fromHex(peginTxHex);\n const prePeginTx = Transaction.fromHex(fundedPrePeginTxHex);\n\n if (peginTx.ins.length !== 1) {\n throw new Error(\n `PegIn transaction must have exactly 1 input, got ${peginTx.ins.length}`,\n );\n }\n\n const peginInput = peginTx.ins[0];\n\n // Verify PegIn input 0 spends Pre-PegIn output 0\n const prePeginTxid = prePeginTx.getId();\n const peginInputTxid = uint8ArrayToHex(\n new Uint8Array(peginInput.hash).slice().reverse(),\n );\n\n if (peginInputTxid !== prePeginTxid) {\n throw new Error(\n `PegIn input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${peginInputTxid}`,\n );\n }\n\n const htlcOutput = prePeginTx.outs[peginInput.index];\n if (!htlcOutput) {\n throw new Error(\n `Pre-PegIn output ${peginInput.index} not found ` +\n `(Pre-PegIn has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const hashlockScript = hexToUint8Array(htlcConnector.hashlockScript);\n const hashlockControlBlock = hexToUint8Array(htlcConnector.hashlockControlBlock);\n\n const psbt = new Psbt();\n psbt.setVersion(peginTx.version);\n psbt.setLocktime(peginTx.locktime);\n\n // Input 0: PegIn input spending Pre-PegIn HTLC output 0 via hashlock leaf (leaf 0).\n // The depositor signs using Taproot script-path spending.\n psbt.addInput({\n hash: peginInput.hash,\n index: peginInput.index,\n sequence: peginInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: 0xc0,\n script: Buffer.from(hashlockScript),\n controlBlock: Buffer.from(hashlockControlBlock),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n // sighashType omitted — defaults to SIGHASH_DEFAULT (0x00) for Taproot\n });\n\n for (const output of peginTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return { psbtHex: psbt.toHex() };\n}\n\n/**\n * Extract the depositor's Schnorr signature from a signed PegIn input PSBT.\n *\n * Supports both non-finalized PSBTs (tapScriptSig) and finalized PSBTs (witness).\n *\n * @param signedPsbtHex - Signed PSBT hex\n * @param depositorPubkey - Depositor's x-only public key (64-char hex)\n * @returns 64-byte Schnorr signature (128 hex chars, no sighash flag)\n * @throws If no signature is found for the depositor's key\n */\nexport function extractPeginInputSignature(\n signedPsbtHex: string,\n depositorPubkey: string,\n): string {\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n const input = signedPsbt.data.inputs[0];\n\n if (!input) {\n throw new Error(\"PegIn PSBT has no inputs\");\n }\n\n // Non-finalized PSBT — extract from tapScriptSig\n if (input.tapScriptSig && input.tapScriptSig.length > 0) {\n const depositorPubkeyBytes = Buffer.from(\n hexToUint8Array(depositorPubkey),\n );\n\n for (const sigEntry of input.tapScriptSig) {\n if (sigEntry.pubkey.equals(depositorPubkeyBytes)) {\n return extractSchnorrSig(sigEntry.signature);\n }\n }\n\n throw new Error(\n `No PegIn input signature found for depositor pubkey: ${depositorPubkey}`,\n );\n }\n\n // Finalized PSBT — the witness stack order depends on the wallet's finalizer,\n // so we cannot reliably pick the depositor's signature by position. Require\n // the non-finalized tapScriptSig path which identifies signatures by pubkey.\n if (input.finalScriptWitness && input.finalScriptWitness.length > 0) {\n throw new Error(\n \"PegIn input PSBT is already finalized. Cannot reliably extract the \" +\n \"depositor signature from the witness stack. Ensure the wallet returns \" +\n \"a non-finalized PSBT with tapScriptSig entries.\",\n );\n }\n\n throw new Error(\n \"No tapScriptSig or finalScriptWitness found in signed PegIn input PSBT\",\n );\n}\n\n/** Extract and validate a 64-byte Schnorr signature, stripping sighash flag if present. */\nfunction extractSchnorrSig(sig: Uint8Array): string {\n if (sig.length === 64) {\n return uint8ArrayToHex(new Uint8Array(sig));\n }\n if (sig.length === 65) {\n return uint8ArrayToHex(new Uint8Array(sig.subarray(0, 64)));\n }\n throw new Error(`Unexpected PegIn input signature length: ${sig.length}`);\n}\n\n","/**\n * Payout Script Generator Primitive\n *\n * This module provides pure functions for generating payout scripts and taproot information\n * by wrapping the WASM implementation from @babylonlabs-io/babylon-tbv-rust-wasm.\n *\n * The payout script is used for signing payout transactions in the vault system.\n * It defines the spending conditions for the vault output, enabling the depositor\n * to authorize payouts during the peg-in flow (Step 3).\n *\n * @remarks\n * This is a low-level primitive. For most use cases, prefer using {@link buildPayoutPsbt}\n * which handles script creation internally. For high-level wallet orchestration, use\n * PayoutManager from the managers module.\n *\n * @see {@link buildPayoutPsbt} - Higher-level function that uses this internally\n *\n * @module primitives/scripts/payout\n */\n\nimport {\n createPayoutConnector,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\n/**\n * Parameters for creating a payout script.\n *\n * These parameters define the participants in a vault and are used to generate\n * the taproot script that controls how funds can be spent from the vault.\n */\nexport interface PayoutScriptParams {\n /**\n * Depositor's BTC public key (x-only, 64-char hex without 0x prefix).\n *\n * This is the user depositing BTC into the vault. The depositor must sign\n * payout transactions to authorize fund distribution.\n */\n depositor: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex without 0x prefix).\n *\n * The service provider managing vault operations. Also referred to as\n * \"claimer\" in the WASM layer.\n */\n vaultProvider: string;\n\n /**\n * Array of vault keeper BTC public keys (x-only, 64-char hex without 0x prefix).\n *\n * Vault keepers participate in vault operations and script spending conditions.\n */\n vaultKeepers: string[];\n\n /**\n * Array of universal challenger BTC public keys (x-only, 64-char hex without 0x prefix).\n *\n * These parties can challenge the vault under certain conditions.\n */\n universalChallengers: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Bitcoin network for script generation.\n *\n * Must match the network used for all other vault operations to ensure\n * address encoding compatibility.\n */\n network: Network;\n}\n\n/**\n * Result of creating a payout script.\n *\n * Contains all the taproot-related data needed for constructing and signing\n * payout transactions from the vault.\n */\nexport interface PayoutScriptResult {\n /**\n * The payout script hex used in taproot script path spending.\n *\n * This is the raw script bytes that define the spending conditions,\n * encoded as a hexadecimal string. Used when constructing the\n * tapLeafScript for PSBT signing.\n */\n payoutScript: string;\n\n /**\n * The taproot script hash (leaf hash) for the payout script.\n *\n * This is the tagged hash of the script used in taproot tree construction.\n * Required for computing the control block during script path spending.\n */\n taprootScriptHash: string;\n\n /**\n * The full scriptPubKey for the vault output address.\n *\n * This is the complete output script (OP_1 <32-byte-key>) that should be\n * used when creating the vault output in a peg-in transaction.\n */\n scriptPubKey: string;\n\n /**\n * The vault Bitcoin address derived from the script.\n *\n * A human-readable bech32m address (bc1p... for mainnet, tb1p... for testnet/signet)\n * that can be used to receive funds into the vault.\n */\n address: string;\n}\n\n/**\n * Create payout script and taproot information using WASM.\n *\n * This is a pure function that wraps the Rust WASM implementation.\n * The payout connector generates the necessary taproot scripts and information\n * required for signing payout transactions.\n *\n * @remarks\n * The generated script encodes spending conditions that require signatures from\n * the depositor and vault provider (or liquidators in challenge scenarios).\n * This script is used internally by {@link buildPayoutPsbt}.\n *\n * @param params - Payout script parameters defining vault participants and network\n * @returns Payout script and taproot information for PSBT construction\n *\n * @see {@link buildPayoutPsbt} - Use this for building complete payout PSBTs\n */\nexport async function createPayoutScript(\n params: PayoutScriptParams,\n): Promise<PayoutScriptResult> {\n // Call the WASM wrapper with the correct parameter structure\n const connector = await createPayoutConnector(\n {\n depositor: params.depositor,\n vaultProvider: params.vaultProvider,\n vaultKeepers: params.vaultKeepers,\n universalChallengers: params.universalChallengers,\n timelockPegin: params.timelockPegin,\n },\n params.network,\n );\n\n return {\n payoutScript: connector.payoutScript,\n taprootScriptHash: connector.taprootScriptHash,\n scriptPubKey: connector.scriptPubKey,\n address: connector.address,\n };\n}\n","/**\n * Payout PSBT Builder Primitives\n *\n * This module provides pure functions for building unsigned payout PSBTs and extracting\n * Schnorr signatures from signed PSBTs. It uses WASM-generated scripts from the payout\n * connector and bitcoinjs-lib for PSBT construction.\n *\n * The Payout transaction references the Assert transaction (input 1).\n *\n * @module primitives/psbt/payout\n */\n\nimport {\n type Network,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { Buffer } from \"buffer\";\nimport { initEccLib, payments, Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { createPayoutScript } from \"../scripts/payout\";\nimport {\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\n\n// Initialize ECC library for bitcoinjs-lib\ninitEccLib(ecc);\n\n/**\n * Parameters for building an unsigned Payout PSBT\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface PayoutParams {\n /**\n * Payout transaction hex (unsigned)\n * This is the transaction that needs to be signed by the depositor\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex\n * Payout input 1 references Assert output 0\n */\n assertTxHex: string;\n\n /**\n * Peg-in transaction hex\n * This transaction created the vault output that we're spending\n */\n peginTxHex: string;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex without 0x prefix)\n */\n depositorBtcPubkey: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex)\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex)\n */\n vaultKeeperBtcPubkeys: string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex)\n */\n universalChallengerBtcPubkeys: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Bitcoin network\n */\n network: Network;\n}\n\n/**\n * Result of building an unsigned payout PSBT\n */\nexport interface PayoutPsbtResult {\n /**\n * Unsigned PSBT hex ready for signing\n */\n psbtHex: string;\n}\n\n/**\n * Build unsigned Payout PSBT for depositor to sign.\n *\n * Payout is used in the **challenge path** when the claimer proves validity:\n * 1. Vault provider submits Claim transaction\n * 2. Challenge is raised during challenge period\n * 3. Claimer submits Assert transaction to prove validity\n * 4. Payout can be executed (references Assert tx)\n *\n * Payout transactions have the following structure:\n * - Input 0: from PeginTx output0 (signed by depositor)\n * - Input 1: from Assert output0 (NOT signed by depositor)\n *\n * @param params - Payout parameters\n * @returns Unsigned PSBT ready for depositor to sign\n *\n * @throws If payout transaction does not have exactly 2 inputs\n * @throws If input 0 does not reference the pegin transaction\n * @throws If input 1 does not reference the assert transaction\n * @throws If previous output is not found for either input\n */\nexport async function buildPayoutPsbt(\n params: PayoutParams,\n): Promise<PayoutPsbtResult> {\n // Normalize hex inputs (strip 0x prefix if present)\n const payoutTxHex = stripHexPrefix(params.payoutTxHex);\n const peginTxHex = stripHexPrefix(params.peginTxHex);\n const assertTxHex = stripHexPrefix(params.assertTxHex);\n\n // Get payout script from WASM\n const payoutConnector = await createPayoutScript({\n depositor: params.depositorBtcPubkey,\n vaultProvider: params.vaultProviderBtcPubkey,\n vaultKeepers: params.vaultKeeperBtcPubkeys,\n universalChallengers: params.universalChallengerBtcPubkeys,\n timelockPegin: params.timelockPegin,\n network: params.network,\n });\n\n const payoutScriptBytes = hexToUint8Array(payoutConnector.payoutScript);\n const controlBlock = computeControlBlock(tapInternalPubkey, payoutScriptBytes);\n\n // Parse transactions\n const payoutTx = Transaction.fromHex(payoutTxHex);\n const peginTx = Transaction.fromHex(peginTxHex);\n const assertTx = Transaction.fromHex(assertTxHex);\n\n // Create PSBT\n const psbt = new Psbt();\n psbt.setVersion(payoutTx.version);\n psbt.setLocktime(payoutTx.locktime);\n\n // PayoutTx has exactly 2 inputs:\n // - Input 0: from PeginTx output0 (signed by depositor using taproot script path)\n // - Input 1: from Assert output0 (signed by claimer/challengers, not depositor)\n //\n // IMPORTANT: For Taproot SIGHASH_DEFAULT (0x00), the sighash commits to ALL inputs'\n // prevouts, not just the one being signed. Therefore, we must include BOTH inputs\n // in the PSBT so the wallet computes the correct sighash that the VP expects.\n\n // Verify payout transaction has expected structure\n if (payoutTx.ins.length !== 2) {\n throw new Error(\n `Payout transaction must have exactly 2 inputs, got ${payoutTx.ins.length}`,\n );\n }\n\n const input0 = payoutTx.ins[0];\n const input1 = payoutTx.ins[1];\n\n // Verify input 0 references the pegin transaction\n const input0Txid = uint8ArrayToHex(\n new Uint8Array(input0.hash).slice().reverse(),\n );\n const peginTxid = peginTx.getId();\n\n if (input0Txid !== peginTxid) {\n throw new Error(\n `Input 0 does not reference pegin transaction. ` +\n `Expected ${peginTxid}, got ${input0Txid}`,\n );\n }\n\n // Verify input 1 references the assert transaction\n const input1Txid = uint8ArrayToHex(\n new Uint8Array(input1.hash).slice().reverse(),\n );\n const expectedInput1Txid = assertTx.getId();\n\n if (input1Txid !== expectedInput1Txid) {\n throw new Error(\n `Input 1 does not reference assert transaction. ` +\n `Expected ${expectedInput1Txid}, got ${input1Txid}`,\n );\n }\n\n const peginPrevOut = peginTx.outs[input0.index];\n if (!peginPrevOut) {\n throw new Error(\n `Previous output not found for input 0 (txid: ${input0Txid}, index: ${input0.index})`,\n );\n }\n\n const input1PrevOut = assertTx.outs[input1.index];\n if (!input1PrevOut) {\n throw new Error(\n `Previous output not found for input 1 (txid: ${input1Txid}, index: ${input1.index})`,\n );\n }\n\n // Input 0: Depositor signs using Taproot script path spend\n // This input includes tapLeafScript for signing\n psbt.addInput({\n hash: input0.hash,\n index: input0.index,\n sequence: input0.sequence,\n witnessUtxo: {\n script: peginPrevOut.script,\n value: peginPrevOut.value,\n },\n tapLeafScript: [\n {\n leafVersion: 0xc0,\n script: Buffer.from(payoutScriptBytes),\n controlBlock: Buffer.from(controlBlock),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n // sighashType omitted - defaults to SIGHASH_DEFAULT (0x00) for Taproot\n });\n\n // Input 1: From Assert transaction (NOT signed by depositor)\n // We include this with witnessUtxo so the sighash is computed correctly,\n // but we do NOT include tapLeafScript since the depositor doesn't sign it.\n psbt.addInput({\n hash: input1.hash,\n index: input1.index,\n sequence: input1.sequence,\n witnessUtxo: {\n script: input1PrevOut.script,\n value: input1PrevOut.value,\n },\n // No tapLeafScript - depositor doesn't sign this input\n });\n\n // Add outputs\n for (const output of payoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return {\n psbtHex: psbt.toHex(),\n };\n}\n\n/**\n * Extract Schnorr signature from signed payout PSBT.\n *\n * This function supports two cases:\n * 1. Non-finalized PSBT: Extracts from tapScriptSig field\n * 2. Finalized PSBT: Extracts from witness data\n *\n * The signature is returned as a 64-byte hex string (128 hex characters)\n * with any sighash flag byte removed if present.\n *\n * @param signedPsbtHex - Signed PSBT hex\n * @param depositorPubkey - Depositor's public key (x-only, 64-char hex)\n * @param inputIndex - Input index to extract signature from (default: 0)\n * @returns 64-byte Schnorr signature (128 hex characters, no sighash flag)\n *\n * @throws If no signature is found in the PSBT\n * @throws If the signature has an unexpected length\n */\nexport function extractPayoutSignature(\n signedPsbtHex: string,\n depositorPubkey: string,\n inputIndex = 0,\n): string {\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n\n if (inputIndex >= signedPsbt.data.inputs.length) {\n throw new Error(\n `Input index ${inputIndex} out of range (${signedPsbt.data.inputs.length} inputs)`,\n );\n }\n\n const input = signedPsbt.data.inputs[inputIndex];\n\n // Case 1: Non-finalized PSBT — extract from tapScriptSig\n if (input.tapScriptSig && input.tapScriptSig.length > 0) {\n const depositorPubkeyBytes = hexToUint8Array(depositorPubkey);\n\n for (const sigEntry of input.tapScriptSig) {\n if (sigEntry.pubkey.equals(Buffer.from(depositorPubkeyBytes))) {\n return extractSchnorrSig(sigEntry.signature, inputIndex);\n }\n }\n\n throw new Error(\n `No signature found for depositor pubkey: ${depositorPubkey} at input ${inputIndex}`,\n );\n }\n\n // Case 2: Finalized PSBT — extract from finalScriptWitness\n // Taproot script-path witness: [signature, script, controlBlock]\n if (input.finalScriptWitness && input.finalScriptWitness.length > 0) {\n const witnessStack = parseWitnessStack(input.finalScriptWitness);\n if (witnessStack.length >= 1) {\n return extractSchnorrSig(witnessStack[0], inputIndex);\n }\n }\n\n throw new Error(\n `No tapScriptSig or finalScriptWitness found in signed PSBT at input ${inputIndex}`,\n );\n}\n\n/**\n * Extract and validate a 64-byte Schnorr signature, stripping sighash flag if present.\n * @internal\n */\nfunction extractSchnorrSig(sig: Uint8Array, inputIndex: number): string {\n if (sig.length === 64) {\n return uint8ArrayToHex(new Uint8Array(sig));\n } else if (sig.length === 65) {\n return uint8ArrayToHex(new Uint8Array(sig.subarray(0, 64)));\n }\n throw new Error(\n `Unexpected signature length at input ${inputIndex}: ${sig.length}`,\n );\n}\n\n/**\n * Parse a BIP-141 serialized witness stack into individual stack items.\n * Format: [varint item_count] [varint len, data]...\n * @internal\n */\nfunction parseWitnessStack(witness: Buffer): Buffer[] {\n const items: Buffer[] = [];\n let offset = 0;\n\n const readVarInt = (): number => {\n const first = witness[offset++];\n if (first < 0xfd) return first;\n if (first === 0xfd) {\n const val = witness[offset] | (witness[offset + 1] << 8);\n offset += 2;\n return val;\n }\n if (first === 0xfe) {\n const val =\n witness[offset] |\n (witness[offset + 1] << 8) |\n (witness[offset + 2] << 16) |\n (witness[offset + 3] << 24);\n offset += 4;\n return val;\n }\n // 0xff — 8-byte, won't happen for witness data\n offset += 8;\n return 0;\n };\n\n const count = readVarInt();\n for (let i = 0; i < count; i++) {\n const len = readVarInt();\n items.push(witness.subarray(offset, offset + len) as Buffer);\n offset += len;\n }\n\n return items;\n}\n\n/**\n * Compute control block for Taproot script path spend.\n *\n * For a single script (no tree), the control block format is:\n * [leaf_version | parity] || [internal_key_x_only]\n *\n * The leaf version for Tapscript is 0xc0, and the parity bit indicates\n * whether the output key has an odd or even y-coordinate.\n *\n * @param internalKey - Taproot internal public key (x-only, 32 bytes)\n * @param script - Taproot script to compute control block for\n * @returns Control block buffer\n *\n * @internal\n */\nfunction computeControlBlock(\n internalKey: Uint8Array,\n script: Uint8Array,\n): Uint8Array {\n // Convert to actual Buffer instances for bitcoinjs-lib runtime type checks\n const scriptTree = { output: Buffer.from(script) };\n const payment = payments.p2tr({\n internalPubkey: Buffer.from(internalKey),\n scriptTree,\n });\n\n const outputKey = payment.pubkey;\n if (!outputKey) {\n throw new Error(\"Failed to compute output key\");\n }\n\n // Control block: [leaf_version | parity] || [internal_key_x_only]\n const leafVersion = 0xc0;\n const parity = outputKey[0] === 0x03 ? 1 : 0; // 0x02 = even, 0x03 = odd\n const controlByte = leafVersion | parity;\n\n const result = new Uint8Array(1 + internalKey.length);\n result[0] = controlByte;\n result.set(internalKey, 1);\n return result;\n}\n","/**\n * Depositor Payout PSBT Builder\n *\n * Builds unsigned PSBTs for the depositor's own Payout transaction\n * (depositor-as-claimer path). The depositor signs input 0 using the\n * payout taproot script from WasmPeginPayoutConnector (PegIn vault UTXO).\n *\n * Input 0 spends PegIn:0 (the vault UTXO) — the same connector used for\n * VP/VK payout signing. The VP verifies this signature using the\n * PeginPayoutConnector's payout script.\n *\n * @module primitives/psbt/depositorPayout\n * @see btc-vault crates/vault/src/sign.rs — verify_depositor_signature / get_payout_tap_leaf_hash\n */\n\nimport {\n type PayoutConnectorParams,\n getPeginPayoutScript,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { Buffer } from \"buffer\";\nimport { initEccLib, payments, Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n hexToUint8Array,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n// Initialize ECC library for bitcoinjs-lib\ninitEccLib(ecc);\n\n/**\n * Parameters for building a depositor Payout PSBT\n */\nexport interface DepositorPayoutParams {\n /** Payout transaction hex (unsigned) from VP */\n payoutTxHex: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Parameters for the PeginPayout connector (depositor, VP, VKs, UCs, timelock) */\n connectorParams: PayoutConnectorParams;\n}\n\n/**\n * Build unsigned depositor Payout PSBT.\n *\n * The depositor's payout transaction has 2 inputs:\n * - Input 0: PegIn:0 (vault UTXO) — depositor signs using PeginPayoutConnector payout script\n * - Input 1: Assert:0 — NOT signed by depositor\n *\n * @param params - Depositor payout parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildDepositorPayoutPsbt(\n params: DepositorPayoutParams,\n): Promise<string> {\n const payoutTxHex = stripHexPrefix(params.payoutTxHex);\n const payoutTx = Transaction.fromHex(payoutTxHex);\n\n // Get payout script from WASM (PeginPayoutConnector — same as VP/VK payout)\n const payoutScriptHex = await getPeginPayoutScript(params.connectorParams);\n const scriptBytes = hexToUint8Array(payoutScriptHex);\n const controlBlock = computeControlBlock(tapInternalPubkey, scriptBytes);\n\n const psbt = new Psbt();\n psbt.setVersion(payoutTx.version);\n psbt.setLocktime(payoutTx.locktime);\n\n // Add all inputs - depositor signs input 0 only\n for (let i = 0; i < payoutTx.ins.length; i++) {\n const input = payoutTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const inputData: Parameters<typeof psbt.addInput>[0] = {\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n };\n\n // Input 0: depositor signs using taproot script path\n if (i === 0) {\n inputData.tapLeafScript = [\n {\n leafVersion: 0xc0,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlock),\n },\n ];\n inputData.tapInternalKey = Buffer.from(tapInternalPubkey);\n }\n\n psbt.addInput(inputData);\n }\n\n // Add outputs\n for (const output of payoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n\n/**\n * Compute control block for Taproot script path spend.\n * @internal\n */\nfunction computeControlBlock(\n internalKey: Uint8Array,\n script: Uint8Array,\n): Uint8Array {\n const scriptTree = { output: Buffer.from(script) };\n const payment = payments.p2tr({\n internalPubkey: Buffer.from(internalKey),\n scriptTree,\n });\n\n const outputKey = payment.pubkey;\n if (!outputKey) {\n throw new Error(\"Failed to compute output key\");\n }\n\n const leafVersion = 0xc0;\n const parity = outputKey[0] === 0x03 ? 1 : 0;\n const controlByte = leafVersion | parity;\n\n const result = new Uint8Array(1 + internalKey.length);\n result[0] = controlByte;\n result.set(internalKey, 1);\n return result;\n}\n","/**\n * NoPayout PSBT Builder\n *\n * Builds unsigned PSBTs for the depositor's NoPayout transaction\n * (depositor-as-claimer path, per challenger). The depositor signs input 0\n * using the NoPayout taproot script from WasmAssertPayoutNoPayoutConnector.\n *\n * @module primitives/psbt/noPayout\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md — Assert output 0 NoPayout connector\n */\n\nimport {\n type AssertPayoutNoPayoutConnectorParams,\n getAssertNoPayoutScriptInfo,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n hexToUint8Array,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building a NoPayout PSBT\n */\nexport interface NoPayoutParams {\n /** NoPayout transaction hex (unsigned) from VP */\n noPayoutTxHex: string;\n /** Challenger's x-only public key (hex encoded) */\n challengerPubkey: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Parameters for the Assert Payout/NoPayout connector */\n connectorParams: AssertPayoutNoPayoutConnectorParams;\n}\n\n/**\n * Build unsigned NoPayout PSBT.\n *\n * The NoPayout transaction is specific to each challenger.\n * Input 0 is the one the depositor signs using the NoPayout taproot script path.\n *\n * @param params - NoPayout parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildNoPayoutPsbt(\n params: NoPayoutParams,\n): Promise<string> {\n const noPayoutTxHex = stripHexPrefix(params.noPayoutTxHex);\n const noPayoutTx = Transaction.fromHex(noPayoutTxHex);\n\n // Get NoPayout script and control block for this challenger\n const { noPayoutScript, noPayoutControlBlock } =\n await getAssertNoPayoutScriptInfo(\n params.connectorParams,\n params.challengerPubkey,\n );\n\n const scriptBytes = hexToUint8Array(noPayoutScript);\n const controlBlockBytes = hexToUint8Array(noPayoutControlBlock);\n\n const psbt = new Psbt();\n psbt.setVersion(noPayoutTx.version);\n psbt.setLocktime(noPayoutTx.locktime);\n\n // Add all inputs - depositor signs input 0 only\n for (let i = 0; i < noPayoutTx.ins.length; i++) {\n const input = noPayoutTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const inputData: Parameters<typeof psbt.addInput>[0] = {\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n };\n\n // Input 0: depositor signs using taproot script path\n if (i === 0) {\n inputData.tapLeafScript = [\n {\n leafVersion: 0xc0,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlockBytes),\n },\n ];\n inputData.tapInternalKey = Buffer.from(tapInternalPubkey);\n }\n\n psbt.addInput(inputData);\n }\n\n // Add outputs\n for (const output of noPayoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n","/**\n * ChallengeAssert PSBT Builder\n *\n * Builds an unsigned PSBT for a ChallengeAssert transaction\n * (depositor-as-claimer path, per challenger). The ChallengeAssert tx has\n * NUM_UTXOS_FOR_CHALLENGE_ASSERT (3) inputs, each spending a different Assert\n * output segment. The depositor signs ALL inputs, each with its own taproot\n * script derived from the per-segment connector params.\n *\n * @module primitives/psbt/challengeAssert\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md — ChallengeAssert connector (NUM_UTXOS_FOR_CHALLENGE_ASSERT=3)\n */\n\nimport {\n type ChallengeAssertConnectorParams,\n getChallengeAssertScriptInfo,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n hexToUint8Array,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building a ChallengeAssert PSBT\n */\nexport interface ChallengeAssertParams {\n /** ChallengeAssert transaction hex (unsigned) from VP */\n challengeAssertTxHex: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP (flat, one per input) */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Per-input connector params (one per input/segment, determines the taproot script) */\n connectorParamsPerInput: ChallengeAssertConnectorParams[];\n}\n\n/**\n * Build unsigned ChallengeAssert PSBT.\n *\n * The ChallengeAssert transaction has 3 inputs (one per Assert output segment).\n * Each input has its own taproot script derived from its connector params.\n * The depositor signs all inputs.\n *\n * @param params - ChallengeAssert parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildChallengeAssertPsbt(\n params: ChallengeAssertParams,\n): Promise<string> {\n const challengeAssertTxHex = stripHexPrefix(params.challengeAssertTxHex);\n const challengeAssertTx = Transaction.fromHex(challengeAssertTxHex);\n\n if (params.connectorParamsPerInput.length !== challengeAssertTx.ins.length) {\n throw new Error(\n `Expected ${challengeAssertTx.ins.length} connector params, got ${params.connectorParamsPerInput.length}`,\n );\n }\n\n // Get script and control block for each input from WASM\n const scriptInfos = await Promise.all(\n params.connectorParamsPerInput.map((cp) => getChallengeAssertScriptInfo(cp)),\n );\n\n const psbt = new Psbt();\n psbt.setVersion(challengeAssertTx.version);\n psbt.setLocktime(challengeAssertTx.locktime);\n\n // Add all inputs — depositor signs every input\n for (let i = 0; i < challengeAssertTx.ins.length; i++) {\n const input = challengeAssertTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const { script, controlBlock } = scriptInfos[i];\n const scriptBytes = hexToUint8Array(script);\n const controlBlockBytes = hexToUint8Array(controlBlock);\n\n psbt.addInput({\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n tapLeafScript: [\n {\n leafVersion: 0xc0,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlockBytes),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n });\n }\n\n // Add outputs\n for (const output of challengeAssertTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n"],"names":["P2TR_INPUT_SIZE","MAX_NON_LEGACY_OUTPUT_SIZE","TX_BUFFER_SIZE_OVERHEAD","BTC_DUST_SAT","DUST_THRESHOLD","LOW_RATE_ESTIMATION_ACCURACY_BUFFER","WALLET_RELAY_FEE_RATE_THRESHOLD","FEE_SAFETY_MARGIN","rateBasedTxBufferFee","feeRate","SPLIT_TX_FEE_SAFETY_MULTIPLIER","stripHexPrefix","hex","ensureHexPrefix","hexToUint8Array","cleanHex","isValidHexRaw","bytes","i","uint8ArrayToHex","b","toXOnly","pubKey","processPublicKeyToXOnly","publicKeyHex","pubkeyBytes","isValidHex","validateWalletPubkey","walletPubkeyRaw","expectedDepositorPubkey","walletPubkeyXOnly","depositorPubkey","eccInitialized","ensureEcc","initEccLib","ecc","getNetwork","network","networks","deriveTaprootAddress","xOnly","address","payments","Buffer","deriveNativeSegwitAddress","isAddressFromPublicKey","compressedKeys","key","parseUnfundedWasmTransaction","unfundedTxHex","dataOffset","inputCount","outputCount","version","locktime","outputs","pos","valueHex","value","scriptLen","scriptHex","script","fundPeginTransaction","params","selectedUTXOs","changeAddress","changeAmount","tx","bitcoin","utxo","txHash","output","changeScript","buildPrePeginPsbt","result","createPrePeginTransaction","totalOutputValue","sum","buildPeginTxFromFundedPrePegin","buildPeginTxFromPrePegin","buildPeginInputPsbt","peginTxHex","fundedPrePeginTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","peginTx","Transaction","prePeginTx","peginInput","prePeginTxid","peginInputTxid","htlcOutput","hashlockScript","hashlockControlBlock","psbt","Psbt","tapInternalPubkey","extractPeginInputSignature","signedPsbtHex","input","depositorPubkeyBytes","sigEntry","extractSchnorrSig","sig","createPayoutScript","connector","createPayoutConnector","buildPayoutPsbt","payoutTxHex","assertTxHex","payoutConnector","payoutScriptBytes","controlBlock","computeControlBlock","payoutTx","assertTx","input0","input1","input0Txid","peginTxid","input1Txid","expectedInput1Txid","peginPrevOut","input1PrevOut","extractPayoutSignature","inputIndex","signedPsbt","witnessStack","parseWitnessStack","witness","items","offset","readVarInt","first","val","count","len","internalKey","scriptTree","outputKey","leafVersion","parity","controlByte","buildDepositorPayoutPsbt","payoutScriptHex","getPeginPayoutScript","scriptBytes","prevout","inputData","buildNoPayoutPsbt","noPayoutTxHex","noPayoutTx","noPayoutScript","noPayoutControlBlock","getAssertNoPayoutScriptInfo","controlBlockBytes","buildChallengeAssertPsbt","challengeAssertTxHex","challengeAssertTx","scriptInfos","cp","getChallengeAssertScriptInfo"],"mappings":"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"}
|