@babylonlabs-io/ts-sdk 0.41.0 → 0.41.1

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.
Files changed (60) hide show
  1. package/dist/{PayoutManager-B5bovfkD.cjs → PayoutManager-BwYlPF2C.cjs} +2 -2
  2. package/dist/{PayoutManager-B5bovfkD.cjs.map → PayoutManager-BwYlPF2C.cjs.map} +1 -1
  3. package/dist/{PayoutManager-DChODEOJ.js → PayoutManager-CXDccwDN.js} +2 -2
  4. package/dist/{PayoutManager-DChODEOJ.js.map → PayoutManager-CXDccwDN.js.map} +1 -1
  5. package/dist/PeginManager-BOuzU8Zo.cjs +2 -0
  6. package/dist/PeginManager-BOuzU8Zo.cjs.map +1 -0
  7. package/dist/{PeginManager-D9ZZ8wx2.js → PeginManager-Bsou6AQV.js} +44 -47
  8. package/dist/PeginManager-Bsou6AQV.js.map +1 -0
  9. package/dist/{assertPsbtUnsignedTxMatches-r1svclbd.cjs → assertPsbtUnsignedTxMatches-CABhEADu.cjs} +2 -2
  10. package/dist/{assertPsbtUnsignedTxMatches-r1svclbd.cjs.map → assertPsbtUnsignedTxMatches-CABhEADu.cjs.map} +1 -1
  11. package/dist/{assertPsbtUnsignedTxMatches-CzVv57QF.js → assertPsbtUnsignedTxMatches-GHobJP-d.js} +2 -2
  12. package/dist/{assertPsbtUnsignedTxMatches-CzVv57QF.js.map → assertPsbtUnsignedTxMatches-GHobJP-d.js.map} +1 -1
  13. package/dist/{buildAndBroadcastRefund-fIHDHiFh.js → buildAndBroadcastRefund-37Bs7-V1.js} +4 -4
  14. package/dist/{buildAndBroadcastRefund-fIHDHiFh.js.map → buildAndBroadcastRefund-37Bs7-V1.js.map} +1 -1
  15. package/dist/{buildAndBroadcastRefund-Cj8JDI7F.cjs → buildAndBroadcastRefund-DbcNEsOv.cjs} +2 -2
  16. package/dist/{buildAndBroadcastRefund-Cj8JDI7F.cjs.map → buildAndBroadcastRefund-DbcNEsOv.cjs.map} +1 -1
  17. package/dist/{challengeAssert-DLEmAhT0.js → challengeAssert-ChqnvtRg.js} +2 -2
  18. package/dist/{challengeAssert-DLEmAhT0.js.map → challengeAssert-ChqnvtRg.js.map} +1 -1
  19. package/dist/{challengeAssert-rpDaS3fH.cjs → challengeAssert-Cmj_OG6V.cjs} +2 -2
  20. package/dist/{challengeAssert-rpDaS3fH.cjs.map → challengeAssert-Cmj_OG6V.cjs.map} +1 -1
  21. package/dist/{fundPeginTransaction-t-6TsHAY.js → fundPeginTransaction-C11tYf6I.js} +32 -33
  22. package/dist/fundPeginTransaction-C11tYf6I.js.map +1 -0
  23. package/dist/fundPeginTransaction-C8qsXxNV.cjs +2 -0
  24. package/dist/fundPeginTransaction-C8qsXxNV.cjs.map +1 -0
  25. package/dist/index.cjs +1 -1
  26. package/dist/index.js +9 -9
  27. package/dist/{noPayout-CS2wnluA.js → noPayout-BtP-R-b-.js} +2 -2
  28. package/dist/{noPayout-CS2wnluA.js.map → noPayout-BtP-R-b-.js.map} +1 -1
  29. package/dist/{noPayout-B06Z9RTe.cjs → noPayout-DliaHuc6.cjs} +2 -2
  30. package/dist/{noPayout-B06Z9RTe.cjs.map → noPayout-DliaHuc6.cjs.map} +1 -1
  31. package/dist/{reservation-hjXStM03.cjs → reservation-Cwf2u4vu.cjs} +2 -2
  32. package/dist/{reservation-hjXStM03.cjs.map → reservation-Cwf2u4vu.cjs.map} +1 -1
  33. package/dist/{reservation-CB-4FBPk.js → reservation-DNOGLBt4.js} +2 -2
  34. package/dist/{reservation-CB-4FBPk.js.map → reservation-DNOGLBt4.js.map} +1 -1
  35. package/dist/tbv/core/index.cjs +1 -1
  36. package/dist/tbv/core/index.js +9 -9
  37. package/dist/tbv/core/managers/PeginManager.d.ts.map +1 -1
  38. package/dist/tbv/core/managers/index.cjs +1 -1
  39. package/dist/tbv/core/managers/index.js +2 -2
  40. package/dist/tbv/core/primitives/index.cjs +1 -1
  41. package/dist/tbv/core/primitives/index.js +3 -3
  42. package/dist/tbv/core/services/index.cjs +1 -1
  43. package/dist/tbv/core/services/index.js +2 -2
  44. package/dist/tbv/core/utils/fee/constants.d.ts +8 -12
  45. package/dist/tbv/core/utils/fee/constants.d.ts.map +1 -1
  46. package/dist/tbv/core/utils/index.cjs +1 -1
  47. package/dist/tbv/core/utils/index.js +3 -3
  48. package/dist/tbv/index.cjs +1 -1
  49. package/dist/tbv/index.js +9 -9
  50. package/dist/{waitForTransactionReceiptSmartAware-tv1mtSIY.cjs → waitForTransactionReceiptSmartAware-BFMQFEzj.cjs} +2 -2
  51. package/dist/{waitForTransactionReceiptSmartAware-tv1mtSIY.cjs.map → waitForTransactionReceiptSmartAware-BFMQFEzj.cjs.map} +1 -1
  52. package/dist/{waitForTransactionReceiptSmartAware-CmgFXFza.js → waitForTransactionReceiptSmartAware-Dt5VcMK0.js} +2 -2
  53. package/dist/{waitForTransactionReceiptSmartAware-CmgFXFza.js.map → waitForTransactionReceiptSmartAware-Dt5VcMK0.js.map} +1 -1
  54. package/package.json +1 -1
  55. package/dist/PeginManager-D9ZZ8wx2.js.map +0 -1
  56. package/dist/PeginManager-UqbOj2oV.cjs +0 -2
  57. package/dist/PeginManager-UqbOj2oV.cjs.map +0 -1
  58. package/dist/fundPeginTransaction-BBE3wTjR.cjs +0 -2
  59. package/dist/fundPeginTransaction-BBE3wTjR.cjs.map +0 -1
  60. package/dist/fundPeginTransaction-t-6TsHAY.js.map +0 -1
@@ -1,2 +1,2 @@
1
- "use strict";var T=Object.defineProperty;var B=(e,t,s)=>t in e?T(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var b=(e,t,s)=>B(e,typeof t!="symbol"?t+"":t,s);const S=require("bitcoinjs-lib"),g=require("./bitcoin-CHfKAhcI.cjs"),v=require("./sha2-DsrLC4NM.cjs"),y=require("./signing-Bnsro0hE.cjs");require("@babylonlabs-io/babylon-tbv-rust-wasm");const u=require("./assertPsbtUnsignedTxMatches-r1svclbd.cjs");function R(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const s in e)if(s!=="default"){const n=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,n.get?n:{enumerable:!0,get:()=>e[s]})}}return t.default=e,Object.freeze(t)}const d=R(S),f=106,w=32,h=34;function m(e,t,s){const n=g.stripHexPrefix(e),c=d.Transaction.fromHex(n);if(c.outs.length<=t)throw new Error(`Pre-PegIn auth-anchor OP_RETURN missing: tx has ${c.outs.length} outputs, expected at least ${t+1} (vault outputs + OP_RETURN)`);const o=c.outs[t],i=o.script;if(i.length!==h||i[0]!==f||i[1]!==w)throw new Error(`Pre-PegIn auth-anchor OP_RETURN at vout ${t} has unexpected script encoding (got ${i.length}-byte script with prefix 0x${i.slice(0,Math.min(2,i.length)).toString("hex")}; expected ${h}-byte OP_RETURN + PUSH32 layout)`);const a=i.slice(2).toString("hex").toLowerCase();if(a!==s.toLowerCase())throw new Error(`Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${t}: tx pushes ${a}, expected ${s}`);if(o.value!==0)throw new Error(`Pre-PegIn auth-anchor OP_RETURN at vout ${t} has non-zero value ${o.value}; OP_RETURN outputs must be 0-value`)}function E(e){let t;try{t=d.Transaction.fromHex(g.stripHexPrefix(e))}catch{return}const s=[];for(let n=0;n<t.outs.length;n++){const c=t.outs[n],o=c.script;o.length===h&&o[0]===f&&o[1]===w&&c.value===0&&s.push({vout:n,hash:o.slice(2).toString("hex").toLowerCase()})}return s.length===1?s[0]:void 0}const x=66;function k(e){if(!e.startsWith("0x")&&!e.startsWith("0X"))throw new Error("Expected 0x-prefixed hex string");const t=e.slice(2);if(t.length%2!==0)throw new Error(`Hex string has odd length: ${t.length}`);if(!/^[0-9a-fA-F]*$/.test(t))throw new Error("Hex string contains non-hex characters");const s=new Uint8Array(t.length/2);for(let n=0;n<s.length;n++)s[n]=parseInt(t.slice(n*2,n*2+2),16);return s}function O(e){return`0x${Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}`}function p(e,t){if(e.length!==x)throw new Error(`${t} must be exactly 32 bytes (${x} hex chars with 0x prefix), got ${e.length}`)}function H(e){p(e,"Secret");const t=k(e),s=v.sha256(t);return O(s)}function $(e,t){return p(e,"Secret"),p(t,"Hashlock"),k(t),H(e).toLowerCase()===t.toLowerCase()}class _{constructor(t){b(this,"config");this.config=t}async signPayoutTransaction(t){const s=await this.config.btcWallet.getPublicKeyHex(),{depositorPubkey:n}=g.validateWalletPubkey(s,t.depositorBtcPubkey),c=await u.buildPayoutPsbt({payoutTxHex:t.payoutTxHex,peginTxHex:t.peginTxHex,assertTxHex:t.assertTxHex,depositorBtcPubkey:n,vaultProviderBtcPubkey:t.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:t.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:t.universalChallengerBtcPubkeys,timelockPegin:t.timelockPegin,network:this.config.network,claimerBtcPubkey:t.claimerBtcPubkey,registeredPayoutScriptPubKey:t.registeredPayoutScriptPubKey,commissionBps:t.commissionBps}),o=await this.config.btcWallet.signPsbt(c.psbtHex,y.createTaprootScriptPathSignOptions(s,1));return u.assertPsbtUnsignedTxMatches({requestedPsbtHex:c.psbtHex,returnedPsbtHex:o}),{signature:u.extractPayoutSignature(o,n),depositorBtcPubkey:n}}getNetwork(){return this.config.network}supportsBatchSigning(){return typeof this.config.btcWallet.signPsbts=="function"}async signPayoutTransactionsBatch(t){if(!this.supportsBatchSigning())throw new Error("Wallet does not support batch signing (signPsbts method not available)");const s=await this.config.btcWallet.getPublicKeyHex(),n=[],c=[],o=[];for(const r of t){const{depositorPubkey:l}=g.validateWalletPubkey(s,r.depositorBtcPubkey);o.push(l);const P=await u.buildPayoutPsbt({payoutTxHex:r.payoutTxHex,peginTxHex:r.peginTxHex,assertTxHex:r.assertTxHex,depositorBtcPubkey:l,vaultProviderBtcPubkey:r.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:r.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:r.universalChallengerBtcPubkeys,timelockPegin:r.timelockPegin,network:this.config.network,claimerBtcPubkey:r.claimerBtcPubkey,registeredPayoutScriptPubKey:r.registeredPayoutScriptPubKey,commissionBps:r.commissionBps});n.push(P.psbtHex),c.push(y.createTaprootScriptPathSignOptions(s,1))}const i=await this.config.btcWallet.signPsbts(n,c);if(i.length!==t.length)throw new Error(`Expected ${t.length} signed PSBTs but received ${i.length}`);const a=[];for(let r=0;r<t.length;r++){const l=o[r];u.assertPsbtUnsignedTxMatches({requestedPsbtHex:n[r],returnedPsbtHex:i[r]});const P=u.extractPayoutSignature(i[r],l);a.push({payoutSignature:P,depositorBtcPubkey:l})}return a}}exports.PayoutManager=_;exports.assertAuthAnchorOpReturn=m;exports.computeHashlock=H;exports.findAuthAnchorOpReturn=E;exports.validateSecretAgainstHashlock=$;
2
- //# sourceMappingURL=PayoutManager-B5bovfkD.cjs.map
1
+ "use strict";var T=Object.defineProperty;var B=(e,t,s)=>t in e?T(e,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[t]=s;var b=(e,t,s)=>B(e,typeof t!="symbol"?t+"":t,s);const S=require("bitcoinjs-lib"),g=require("./bitcoin-CHfKAhcI.cjs"),v=require("./sha2-DsrLC4NM.cjs"),y=require("./signing-Bnsro0hE.cjs");require("@babylonlabs-io/babylon-tbv-rust-wasm");const u=require("./assertPsbtUnsignedTxMatches-CABhEADu.cjs");function R(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const s in e)if(s!=="default"){const n=Object.getOwnPropertyDescriptor(e,s);Object.defineProperty(t,s,n.get?n:{enumerable:!0,get:()=>e[s]})}}return t.default=e,Object.freeze(t)}const d=R(S),f=106,w=32,h=34;function m(e,t,s){const n=g.stripHexPrefix(e),c=d.Transaction.fromHex(n);if(c.outs.length<=t)throw new Error(`Pre-PegIn auth-anchor OP_RETURN missing: tx has ${c.outs.length} outputs, expected at least ${t+1} (vault outputs + OP_RETURN)`);const o=c.outs[t],i=o.script;if(i.length!==h||i[0]!==f||i[1]!==w)throw new Error(`Pre-PegIn auth-anchor OP_RETURN at vout ${t} has unexpected script encoding (got ${i.length}-byte script with prefix 0x${i.slice(0,Math.min(2,i.length)).toString("hex")}; expected ${h}-byte OP_RETURN + PUSH32 layout)`);const a=i.slice(2).toString("hex").toLowerCase();if(a!==s.toLowerCase())throw new Error(`Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${t}: tx pushes ${a}, expected ${s}`);if(o.value!==0)throw new Error(`Pre-PegIn auth-anchor OP_RETURN at vout ${t} has non-zero value ${o.value}; OP_RETURN outputs must be 0-value`)}function E(e){let t;try{t=d.Transaction.fromHex(g.stripHexPrefix(e))}catch{return}const s=[];for(let n=0;n<t.outs.length;n++){const c=t.outs[n],o=c.script;o.length===h&&o[0]===f&&o[1]===w&&c.value===0&&s.push({vout:n,hash:o.slice(2).toString("hex").toLowerCase()})}return s.length===1?s[0]:void 0}const x=66;function k(e){if(!e.startsWith("0x")&&!e.startsWith("0X"))throw new Error("Expected 0x-prefixed hex string");const t=e.slice(2);if(t.length%2!==0)throw new Error(`Hex string has odd length: ${t.length}`);if(!/^[0-9a-fA-F]*$/.test(t))throw new Error("Hex string contains non-hex characters");const s=new Uint8Array(t.length/2);for(let n=0;n<s.length;n++)s[n]=parseInt(t.slice(n*2,n*2+2),16);return s}function O(e){return`0x${Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}`}function p(e,t){if(e.length!==x)throw new Error(`${t} must be exactly 32 bytes (${x} hex chars with 0x prefix), got ${e.length}`)}function H(e){p(e,"Secret");const t=k(e),s=v.sha256(t);return O(s)}function $(e,t){return p(e,"Secret"),p(t,"Hashlock"),k(t),H(e).toLowerCase()===t.toLowerCase()}class _{constructor(t){b(this,"config");this.config=t}async signPayoutTransaction(t){const s=await this.config.btcWallet.getPublicKeyHex(),{depositorPubkey:n}=g.validateWalletPubkey(s,t.depositorBtcPubkey),c=await u.buildPayoutPsbt({payoutTxHex:t.payoutTxHex,peginTxHex:t.peginTxHex,assertTxHex:t.assertTxHex,depositorBtcPubkey:n,vaultProviderBtcPubkey:t.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:t.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:t.universalChallengerBtcPubkeys,timelockPegin:t.timelockPegin,network:this.config.network,claimerBtcPubkey:t.claimerBtcPubkey,registeredPayoutScriptPubKey:t.registeredPayoutScriptPubKey,commissionBps:t.commissionBps}),o=await this.config.btcWallet.signPsbt(c.psbtHex,y.createTaprootScriptPathSignOptions(s,1));return u.assertPsbtUnsignedTxMatches({requestedPsbtHex:c.psbtHex,returnedPsbtHex:o}),{signature:u.extractPayoutSignature(o,n),depositorBtcPubkey:n}}getNetwork(){return this.config.network}supportsBatchSigning(){return typeof this.config.btcWallet.signPsbts=="function"}async signPayoutTransactionsBatch(t){if(!this.supportsBatchSigning())throw new Error("Wallet does not support batch signing (signPsbts method not available)");const s=await this.config.btcWallet.getPublicKeyHex(),n=[],c=[],o=[];for(const r of t){const{depositorPubkey:l}=g.validateWalletPubkey(s,r.depositorBtcPubkey);o.push(l);const P=await u.buildPayoutPsbt({payoutTxHex:r.payoutTxHex,peginTxHex:r.peginTxHex,assertTxHex:r.assertTxHex,depositorBtcPubkey:l,vaultProviderBtcPubkey:r.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:r.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:r.universalChallengerBtcPubkeys,timelockPegin:r.timelockPegin,network:this.config.network,claimerBtcPubkey:r.claimerBtcPubkey,registeredPayoutScriptPubKey:r.registeredPayoutScriptPubKey,commissionBps:r.commissionBps});n.push(P.psbtHex),c.push(y.createTaprootScriptPathSignOptions(s,1))}const i=await this.config.btcWallet.signPsbts(n,c);if(i.length!==t.length)throw new Error(`Expected ${t.length} signed PSBTs but received ${i.length}`);const a=[];for(let r=0;r<t.length;r++){const l=o[r];u.assertPsbtUnsignedTxMatches({requestedPsbtHex:n[r],returnedPsbtHex:i[r]});const P=u.extractPayoutSignature(i[r],l);a.push({payoutSignature:P,depositorBtcPubkey:l})}return a}}exports.PayoutManager=_;exports.assertAuthAnchorOpReturn=m;exports.computeHashlock=H;exports.findAuthAnchorOpReturn=E;exports.validateSecretAgainstHashlock=$;
2
+ //# sourceMappingURL=PayoutManager-BwYlPF2C.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"PayoutManager-B5bovfkD.cjs","sources":["../src/tbv/core/managers/pegin/assertAuthAnchorOpReturn.ts","../src/tbv/core/services/htlc/index.ts","../src/tbv/core/managers/PayoutManager.ts"],"sourcesContent":["/**\n * Structural verifier for the auth-anchor OP_RETURN in a funded\n * Pre-PegIn transaction.\n *\n * @module managers/pegin/assertAuthAnchorOpReturn\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport { stripHexPrefix } from \"../../primitives/utils/bitcoin\";\n\n/** OP_RETURN opcode. */\nconst OP_RETURN = 0x6a;\n/** Push-32-bytes opcode (raw push, not OP_PUSHDATA1). */\nconst OP_PUSH32 = 0x20;\n/** Encoded length of a standard OP_RETURN script with a 32-byte payload. */\nconst OP_RETURN_PUSH32_SCRIPT_LEN = 1 + 1 + 32;\n\n/**\n * Verify the broadcast Pre-PegIn carries the expected OP_RETURN\n * commitment to the auth anchor.\n *\n * The OP_RETURN sits at `vout = vaultCount` (right after the per-vault\n * HTLC outputs and before the depositor-claim/change outputs) and\n * pushes the 32-byte `SHA256(authAnchor)`. The script encoding is\n * exactly `OP_RETURN || PUSH32 || <32 bytes>` (34 bytes). A\n * non-conformant WASM build that omitted the OP_RETURN, swapped its\n * position, or changed its push payload would let the depositor\n * obtain a valid bearer token for a Pre-PegIn whose on-chain\n * commitment doesn't actually bind the anchor — degrading the auth\n * from on-chain-bound to a shared secret. Fail closed.\n *\n * @throws If the OP_RETURN is missing, mis-located, mis-encoded, or\n * pushes a payload other than `expectedAuthAnchorHashHex`.\n */\nexport function assertAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n vaultCount: number,\n expectedAuthAnchorHashHex: string,\n): void {\n const cleanHex = stripHexPrefix(fundedPrePeginTxHex);\n const tx = bitcoin.Transaction.fromHex(cleanHex);\n\n if (tx.outs.length <= vaultCount) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN missing: tx has ${tx.outs.length} ` +\n `outputs, expected at least ${vaultCount + 1} (vault outputs + OP_RETURN)`,\n );\n }\n\n const opReturnOutput = tx.outs[vaultCount];\n const script = opReturnOutput.script;\n if (\n script.length !== OP_RETURN_PUSH32_SCRIPT_LEN ||\n script[0] !== OP_RETURN ||\n script[1] !== OP_PUSH32\n ) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has unexpected ` +\n `script encoding (got ${script.length}-byte script with prefix ` +\n `0x${script.slice(0, Math.min(2, script.length)).toString(\"hex\")}; ` +\n `expected ${OP_RETURN_PUSH32_SCRIPT_LEN}-byte OP_RETURN + PUSH32 layout)`,\n );\n }\n\n const pushedHex = script.slice(2).toString(\"hex\").toLowerCase();\n if (pushedHex !== expectedAuthAnchorHashHex.toLowerCase()) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${vaultCount}: ` +\n `tx pushes ${pushedHex}, expected ${expectedAuthAnchorHashHex}`,\n );\n }\n\n if (opReturnOutput.value !== 0) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has non-zero ` +\n `value ${opReturnOutput.value}; OP_RETURN outputs must be 0-value`,\n );\n }\n}\n\n/**\n * Scan a funded Pre-PegIn transaction for its auth-anchor commitment\n * (an `OP_RETURN || PUSH32 || <32 bytes>` output with value 0).\n *\n * Returns `{ vout, hash }` when exactly one such output is found.\n * Returns `undefined` when:\n * - the hex is unparseable,\n * - no matching output exists (legacy non-auth-anchored Pre-PegIn),\n * - more than one matching output exists (ambiguous / malformed).\n *\n * Used by the refund orchestrator to (a) locate the on-chain anchor\n * regardless of how many HTLCs preceded it and (b) detect multi-vault\n * funded transactions structurally: the single-vault refund path\n * reconstructs only one hashlock and expects the anchor at vout 1, so\n * any other vout signals a layout this call cannot safely refund.\n */\nexport function findAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n): { vout: number; hash: string } | undefined {\n let tx: bitcoin.Transaction;\n try {\n tx = bitcoin.Transaction.fromHex(stripHexPrefix(fundedPrePeginTxHex));\n } catch {\n return undefined;\n }\n\n const hits: { vout: number; hash: string }[] = [];\n for (let i = 0; i < tx.outs.length; i++) {\n const output = tx.outs[i];\n const script = output.script;\n if (\n script.length === OP_RETURN_PUSH32_SCRIPT_LEN &&\n script[0] === OP_RETURN &&\n script[1] === OP_PUSH32 &&\n output.value === 0\n ) {\n hits.push({\n vout: i,\n hash: script.slice(2).toString(\"hex\").toLowerCase(),\n });\n }\n }\n\n return hits.length === 1 ? hits[0] : undefined;\n}\n","/**\n * HTLC Secret / Hashlock Utilities\n *\n * Pure functions for computing and validating SHA-256 hashlocks used in the\n * vault deposit protocol's HTLC (Hash Time Lock Contract).\n *\n * The SDK does NOT generate secrets — that is the caller's responsibility.\n * Today callers use `crypto.getRandomValues(32)`; when the `deriveContextHash`\n * wallet API ships, callers will use `wallet.deriveContextHash(\"babylon-btc-vault\", ctx)`.\n * These utilities work identically regardless of how the secret was produced.\n *\n * On-chain contract validation (BTCVaultRegistry.activateVaultWithSecret):\n * if (sha256(abi.encodePacked(s)) != hashlock) revert InvalidSecret();\n *\n * @module htlc\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport type { Hex } from \"viem\";\n\n/** Expected hex length for a 0x-prefixed bytes32 value. */\nconst HEX_BYTES32_LENGTH = 66; // \"0x\" + 64 hex chars\n\n/**\n * Decode a 0x-prefixed hex string to bytes, with strict validation.\n * @throws if the input is not a valid 0x-prefixed hex string\n */\nfunction hexToBytes(hex: Hex): Uint8Array {\n if (!hex.startsWith(\"0x\") && !hex.startsWith(\"0X\")) {\n throw new Error(\"Expected 0x-prefixed hex string\");\n }\n const clean = hex.slice(2);\n if (clean.length % 2 !== 0) {\n throw new Error(`Hex string has odd length: ${clean.length}`);\n }\n if (!/^[0-9a-fA-F]*$/.test(clean)) {\n throw new Error(\"Hex string contains non-hex characters\");\n }\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Encode a Uint8Array as a 0x-prefixed lowercase hex string.\n */\nfunction bytesToHex(bytes: Uint8Array): Hex {\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Validate that a value is a 0x-prefixed bytes32 (exactly 32 bytes).\n * @throws if the value is not exactly 32 bytes\n */\nfunction assertBytes32(value: Hex, label: string): void {\n if (value.length !== HEX_BYTES32_LENGTH) {\n throw new Error(\n `${label} must be exactly 32 bytes (${HEX_BYTES32_LENGTH} hex chars with 0x prefix), got ${value.length}`,\n );\n }\n}\n\n/**\n * Compute the SHA-256 hashlock from a secret preimage.\n *\n * Matches the on-chain validation: `sha256(abi.encodePacked(s))` where `s` is a `bytes32`.\n * `abi.encodePacked(bytes32)` is just the raw 32 bytes — no ABI padding.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @returns 0x-prefixed bytes32 SHA-256 hash\n * @throws if secret is not exactly 32 bytes\n */\nexport function computeHashlock(secret: Hex): Hex {\n assertBytes32(secret, \"Secret\");\n const secretBytes = hexToBytes(secret);\n const hash = sha256(secretBytes);\n return bytesToHex(hash);\n}\n\n/**\n * Validate that a secret's SHA-256 hash matches the expected hashlock.\n *\n * Use this for client-side pre-validation before sending the activation\n * transaction to avoid wasting gas on a contract revert.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @param hashlock - 0x-prefixed bytes32 expected hashlock from the vault\n * @returns true if SHA-256(secret) matches the hashlock\n * @throws if secret or hashlock is not exactly 32 bytes\n */\nexport function validateSecretAgainstHashlock(\n secret: Hex,\n hashlock: Hex,\n): boolean {\n assertBytes32(secret, \"Secret\");\n assertBytes32(hashlock, \"Hashlock\");\n // Validate hashlock is valid hex (secret is validated inside computeHashlock)\n hexToBytes(hashlock);\n\n const computed = computeHashlock(secret);\n return computed.toLowerCase() === hashlock.toLowerCase();\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–4 of the 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 {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../shared/wallets\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\nimport {\n assertPsbtUnsignedTxMatches,\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). This MUST be the\n * key registered on-chain for the vault — typically read from\n * `BTCVaultRegistry.getBtcVaultBasicInfo(...).depositorBtcPubKey`.\n *\n * Required: omitting it would degrade `validateWalletPubkey` to a\n * self-comparison, allowing the wrong wallet to produce a signature\n * over a script tree that doesn't match the on-chain UTXO.\n */\n depositorBtcPubkey: string;\n\n /**\n * The on-chain registered depositor payout scriptPubKey (hex, with or without 0x prefix).\n * Used to validate that the VP-provided payout transaction actually pays to the\n * correct depositor payout address before signing.\n */\n registeredPayoutScriptPubKey: string;\n\n /**\n * The claimer's x-only BTC public key for this payout (64-char hex, no prefix).\n * Forwarded to {@link buildPayoutPsbt} for per-role output validation.\n */\n claimerBtcPubkey: string;\n\n /**\n * VP commission in basis points (`1..=9999`). Forwarded to {@link buildPayoutPsbt}.\n */\n commissionBps: number;\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 3), 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). Per-role output\n // validation happens inside buildPayoutPsbt against the resolved input\n // values.\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 claimerBtcPubkey: params.claimerBtcPubkey,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n });\n\n // Sign PSBT via wallet (Taproot script-path spend, input 0 only)\n const signedPsbtHex = await this.config.btcWallet.signPsbt(\n payoutPsbt.psbtHex,\n createTaprootScriptPathSignOptions(walletPubkeyRaw, 1),\n );\n\n assertPsbtUnsignedTxMatches({\n requestedPsbtHex: payoutPsbt.psbtHex,\n returnedPsbtHex: signedPsbtHex,\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: SignPsbtOptions[] = [];\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 (output validation runs inside buildPayoutPsbt\n // against resolved input values).\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 claimerBtcPubkey: tx.claimerBtcPubkey,\n registeredPayoutScriptPubKey: tx.registeredPayoutScriptPubKey,\n commissionBps: tx.commissionBps,\n });\n psbtsToSign.push(payoutPsbt.psbtHex);\n signOptions.push(createTaprootScriptPathSignOptions(walletPubkeyRaw, 1));\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 assertPsbtUnsignedTxMatches({\n requestedPsbtHex: psbtsToSign[i],\n returnedPsbtHex: signedPsbts[i],\n });\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}\n"],"names":["OP_RETURN","OP_PUSH32","OP_RETURN_PUSH32_SCRIPT_LEN","assertAuthAnchorOpReturn","fundedPrePeginTxHex","vaultCount","expectedAuthAnchorHashHex","cleanHex","stripHexPrefix","tx","bitcoin","opReturnOutput","script","pushedHex","findAuthAnchorOpReturn","hits","i","output","HEX_BYTES32_LENGTH","hexToBytes","hex","clean","bytes","bytesToHex","b","assertBytes32","value","label","computeHashlock","secret","secretBytes","hash","sha256","validateSecretAgainstHashlock","hashlock","PayoutManager","config","__publicField","params","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","signedPsbtHex","createTaprootScriptPathSignOptions","assertPsbtUnsignedTxMatches","extractPayoutSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature"],"mappings":"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"}
1
+ {"version":3,"file":"PayoutManager-BwYlPF2C.cjs","sources":["../src/tbv/core/managers/pegin/assertAuthAnchorOpReturn.ts","../src/tbv/core/services/htlc/index.ts","../src/tbv/core/managers/PayoutManager.ts"],"sourcesContent":["/**\n * Structural verifier for the auth-anchor OP_RETURN in a funded\n * Pre-PegIn transaction.\n *\n * @module managers/pegin/assertAuthAnchorOpReturn\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport { stripHexPrefix } from \"../../primitives/utils/bitcoin\";\n\n/** OP_RETURN opcode. */\nconst OP_RETURN = 0x6a;\n/** Push-32-bytes opcode (raw push, not OP_PUSHDATA1). */\nconst OP_PUSH32 = 0x20;\n/** Encoded length of a standard OP_RETURN script with a 32-byte payload. */\nconst OP_RETURN_PUSH32_SCRIPT_LEN = 1 + 1 + 32;\n\n/**\n * Verify the broadcast Pre-PegIn carries the expected OP_RETURN\n * commitment to the auth anchor.\n *\n * The OP_RETURN sits at `vout = vaultCount` (right after the per-vault\n * HTLC outputs and before the depositor-claim/change outputs) and\n * pushes the 32-byte `SHA256(authAnchor)`. The script encoding is\n * exactly `OP_RETURN || PUSH32 || <32 bytes>` (34 bytes). A\n * non-conformant WASM build that omitted the OP_RETURN, swapped its\n * position, or changed its push payload would let the depositor\n * obtain a valid bearer token for a Pre-PegIn whose on-chain\n * commitment doesn't actually bind the anchor — degrading the auth\n * from on-chain-bound to a shared secret. Fail closed.\n *\n * @throws If the OP_RETURN is missing, mis-located, mis-encoded, or\n * pushes a payload other than `expectedAuthAnchorHashHex`.\n */\nexport function assertAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n vaultCount: number,\n expectedAuthAnchorHashHex: string,\n): void {\n const cleanHex = stripHexPrefix(fundedPrePeginTxHex);\n const tx = bitcoin.Transaction.fromHex(cleanHex);\n\n if (tx.outs.length <= vaultCount) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN missing: tx has ${tx.outs.length} ` +\n `outputs, expected at least ${vaultCount + 1} (vault outputs + OP_RETURN)`,\n );\n }\n\n const opReturnOutput = tx.outs[vaultCount];\n const script = opReturnOutput.script;\n if (\n script.length !== OP_RETURN_PUSH32_SCRIPT_LEN ||\n script[0] !== OP_RETURN ||\n script[1] !== OP_PUSH32\n ) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has unexpected ` +\n `script encoding (got ${script.length}-byte script with prefix ` +\n `0x${script.slice(0, Math.min(2, script.length)).toString(\"hex\")}; ` +\n `expected ${OP_RETURN_PUSH32_SCRIPT_LEN}-byte OP_RETURN + PUSH32 layout)`,\n );\n }\n\n const pushedHex = script.slice(2).toString(\"hex\").toLowerCase();\n if (pushedHex !== expectedAuthAnchorHashHex.toLowerCase()) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${vaultCount}: ` +\n `tx pushes ${pushedHex}, expected ${expectedAuthAnchorHashHex}`,\n );\n }\n\n if (opReturnOutput.value !== 0) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has non-zero ` +\n `value ${opReturnOutput.value}; OP_RETURN outputs must be 0-value`,\n );\n }\n}\n\n/**\n * Scan a funded Pre-PegIn transaction for its auth-anchor commitment\n * (an `OP_RETURN || PUSH32 || <32 bytes>` output with value 0).\n *\n * Returns `{ vout, hash }` when exactly one such output is found.\n * Returns `undefined` when:\n * - the hex is unparseable,\n * - no matching output exists (legacy non-auth-anchored Pre-PegIn),\n * - more than one matching output exists (ambiguous / malformed).\n *\n * Used by the refund orchestrator to (a) locate the on-chain anchor\n * regardless of how many HTLCs preceded it and (b) detect multi-vault\n * funded transactions structurally: the single-vault refund path\n * reconstructs only one hashlock and expects the anchor at vout 1, so\n * any other vout signals a layout this call cannot safely refund.\n */\nexport function findAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n): { vout: number; hash: string } | undefined {\n let tx: bitcoin.Transaction;\n try {\n tx = bitcoin.Transaction.fromHex(stripHexPrefix(fundedPrePeginTxHex));\n } catch {\n return undefined;\n }\n\n const hits: { vout: number; hash: string }[] = [];\n for (let i = 0; i < tx.outs.length; i++) {\n const output = tx.outs[i];\n const script = output.script;\n if (\n script.length === OP_RETURN_PUSH32_SCRIPT_LEN &&\n script[0] === OP_RETURN &&\n script[1] === OP_PUSH32 &&\n output.value === 0\n ) {\n hits.push({\n vout: i,\n hash: script.slice(2).toString(\"hex\").toLowerCase(),\n });\n }\n }\n\n return hits.length === 1 ? hits[0] : undefined;\n}\n","/**\n * HTLC Secret / Hashlock Utilities\n *\n * Pure functions for computing and validating SHA-256 hashlocks used in the\n * vault deposit protocol's HTLC (Hash Time Lock Contract).\n *\n * The SDK does NOT generate secrets — that is the caller's responsibility.\n * Today callers use `crypto.getRandomValues(32)`; when the `deriveContextHash`\n * wallet API ships, callers will use `wallet.deriveContextHash(\"babylon-btc-vault\", ctx)`.\n * These utilities work identically regardless of how the secret was produced.\n *\n * On-chain contract validation (BTCVaultRegistry.activateVaultWithSecret):\n * if (sha256(abi.encodePacked(s)) != hashlock) revert InvalidSecret();\n *\n * @module htlc\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport type { Hex } from \"viem\";\n\n/** Expected hex length for a 0x-prefixed bytes32 value. */\nconst HEX_BYTES32_LENGTH = 66; // \"0x\" + 64 hex chars\n\n/**\n * Decode a 0x-prefixed hex string to bytes, with strict validation.\n * @throws if the input is not a valid 0x-prefixed hex string\n */\nfunction hexToBytes(hex: Hex): Uint8Array {\n if (!hex.startsWith(\"0x\") && !hex.startsWith(\"0X\")) {\n throw new Error(\"Expected 0x-prefixed hex string\");\n }\n const clean = hex.slice(2);\n if (clean.length % 2 !== 0) {\n throw new Error(`Hex string has odd length: ${clean.length}`);\n }\n if (!/^[0-9a-fA-F]*$/.test(clean)) {\n throw new Error(\"Hex string contains non-hex characters\");\n }\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Encode a Uint8Array as a 0x-prefixed lowercase hex string.\n */\nfunction bytesToHex(bytes: Uint8Array): Hex {\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Validate that a value is a 0x-prefixed bytes32 (exactly 32 bytes).\n * @throws if the value is not exactly 32 bytes\n */\nfunction assertBytes32(value: Hex, label: string): void {\n if (value.length !== HEX_BYTES32_LENGTH) {\n throw new Error(\n `${label} must be exactly 32 bytes (${HEX_BYTES32_LENGTH} hex chars with 0x prefix), got ${value.length}`,\n );\n }\n}\n\n/**\n * Compute the SHA-256 hashlock from a secret preimage.\n *\n * Matches the on-chain validation: `sha256(abi.encodePacked(s))` where `s` is a `bytes32`.\n * `abi.encodePacked(bytes32)` is just the raw 32 bytes — no ABI padding.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @returns 0x-prefixed bytes32 SHA-256 hash\n * @throws if secret is not exactly 32 bytes\n */\nexport function computeHashlock(secret: Hex): Hex {\n assertBytes32(secret, \"Secret\");\n const secretBytes = hexToBytes(secret);\n const hash = sha256(secretBytes);\n return bytesToHex(hash);\n}\n\n/**\n * Validate that a secret's SHA-256 hash matches the expected hashlock.\n *\n * Use this for client-side pre-validation before sending the activation\n * transaction to avoid wasting gas on a contract revert.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @param hashlock - 0x-prefixed bytes32 expected hashlock from the vault\n * @returns true if SHA-256(secret) matches the hashlock\n * @throws if secret or hashlock is not exactly 32 bytes\n */\nexport function validateSecretAgainstHashlock(\n secret: Hex,\n hashlock: Hex,\n): boolean {\n assertBytes32(secret, \"Secret\");\n assertBytes32(hashlock, \"Hashlock\");\n // Validate hashlock is valid hex (secret is validated inside computeHashlock)\n hexToBytes(hashlock);\n\n const computed = computeHashlock(secret);\n return computed.toLowerCase() === hashlock.toLowerCase();\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–4 of the 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 {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../shared/wallets\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\nimport {\n assertPsbtUnsignedTxMatches,\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). This MUST be the\n * key registered on-chain for the vault — typically read from\n * `BTCVaultRegistry.getBtcVaultBasicInfo(...).depositorBtcPubKey`.\n *\n * Required: omitting it would degrade `validateWalletPubkey` to a\n * self-comparison, allowing the wrong wallet to produce a signature\n * over a script tree that doesn't match the on-chain UTXO.\n */\n depositorBtcPubkey: string;\n\n /**\n * The on-chain registered depositor payout scriptPubKey (hex, with or without 0x prefix).\n * Used to validate that the VP-provided payout transaction actually pays to the\n * correct depositor payout address before signing.\n */\n registeredPayoutScriptPubKey: string;\n\n /**\n * The claimer's x-only BTC public key for this payout (64-char hex, no prefix).\n * Forwarded to {@link buildPayoutPsbt} for per-role output validation.\n */\n claimerBtcPubkey: string;\n\n /**\n * VP commission in basis points (`1..=9999`). Forwarded to {@link buildPayoutPsbt}.\n */\n commissionBps: number;\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 3), 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). Per-role output\n // validation happens inside buildPayoutPsbt against the resolved input\n // values.\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 claimerBtcPubkey: params.claimerBtcPubkey,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n });\n\n // Sign PSBT via wallet (Taproot script-path spend, input 0 only)\n const signedPsbtHex = await this.config.btcWallet.signPsbt(\n payoutPsbt.psbtHex,\n createTaprootScriptPathSignOptions(walletPubkeyRaw, 1),\n );\n\n assertPsbtUnsignedTxMatches({\n requestedPsbtHex: payoutPsbt.psbtHex,\n returnedPsbtHex: signedPsbtHex,\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: SignPsbtOptions[] = [];\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 (output validation runs inside buildPayoutPsbt\n // against resolved input values).\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 claimerBtcPubkey: tx.claimerBtcPubkey,\n registeredPayoutScriptPubKey: tx.registeredPayoutScriptPubKey,\n commissionBps: tx.commissionBps,\n });\n psbtsToSign.push(payoutPsbt.psbtHex);\n signOptions.push(createTaprootScriptPathSignOptions(walletPubkeyRaw, 1));\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 assertPsbtUnsignedTxMatches({\n requestedPsbtHex: psbtsToSign[i],\n returnedPsbtHex: signedPsbts[i],\n });\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}\n"],"names":["OP_RETURN","OP_PUSH32","OP_RETURN_PUSH32_SCRIPT_LEN","assertAuthAnchorOpReturn","fundedPrePeginTxHex","vaultCount","expectedAuthAnchorHashHex","cleanHex","stripHexPrefix","tx","bitcoin","opReturnOutput","script","pushedHex","findAuthAnchorOpReturn","hits","i","output","HEX_BYTES32_LENGTH","hexToBytes","hex","clean","bytes","bytesToHex","b","assertBytes32","value","label","computeHashlock","secret","secretBytes","hash","sha256","validateSecretAgainstHashlock","hashlock","PayoutManager","config","__publicField","params","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","signedPsbtHex","createTaprootScriptPathSignOptions","assertPsbtUnsignedTxMatches","extractPayoutSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature"],"mappings":"osBAYMA,EAAY,IAEZC,EAAY,GAEZC,EAA8B,GAmB7B,SAASC,EACdC,EACAC,EACAC,EACM,CACN,MAAMC,EAAWC,EAAAA,eAAeJ,CAAmB,EAC7CK,EAAKC,EAAQ,YAAY,QAAQH,CAAQ,EAE/C,GAAIE,EAAG,KAAK,QAAUJ,EACpB,MAAM,IAAI,MACR,mDAAmDI,EAAG,KAAK,MAAM,+BACjCJ,EAAa,CAAC,8BAAA,EAIlD,MAAMM,EAAiBF,EAAG,KAAKJ,CAAU,EACnCO,EAASD,EAAe,OAC9B,GACEC,EAAO,SAAWV,GAClBU,EAAO,CAAC,IAAMZ,GACdY,EAAO,CAAC,IAAMX,EAEd,MAAM,IAAI,MACR,2CAA2CI,CAAU,wCAC3BO,EAAO,MAAM,8BAChCA,EAAO,MAAM,EAAG,KAAK,IAAI,EAAGA,EAAO,MAAM,CAAC,EAAE,SAAS,KAAK,CAAC,cACpDV,CAA2B,kCAAA,EAI7C,MAAMW,EAAYD,EAAO,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,YAAA,EAClD,GAAIC,IAAcP,EAA0B,cAC1C,MAAM,IAAI,MACR,4DAA4DD,CAAU,eACvDQ,CAAS,cAAcP,CAAyB,EAAA,EAInE,GAAIK,EAAe,QAAU,EAC3B,MAAM,IAAI,MACR,2CAA2CN,CAAU,uBAC1CM,EAAe,KAAK,qCAAA,CAGrC,CAkBO,SAASG,EACdV,EAC4C,CAC5C,IAAIK,EACJ,GAAI,CACFA,EAAKC,EAAQ,YAAY,QAAQF,EAAAA,eAAeJ,CAAmB,CAAC,CACtE,MAAQ,CACN,MACF,CAEA,MAAMW,EAAyC,CAAA,EAC/C,QAASC,EAAI,EAAGA,EAAIP,EAAG,KAAK,OAAQO,IAAK,CACvC,MAAMC,EAASR,EAAG,KAAKO,CAAC,EAClBJ,EAASK,EAAO,OAEpBL,EAAO,SAAWV,GAClBU,EAAO,CAAC,IAAMZ,GACdY,EAAO,CAAC,IAAMX,GACdgB,EAAO,QAAU,GAEjBF,EAAK,KAAK,CACR,KAAMC,EACN,KAAMJ,EAAO,MAAM,CAAC,EAAE,SAAS,KAAK,EAAE,YAAA,CAAY,CACnD,CAEL,CAEA,OAAOG,EAAK,SAAW,EAAIA,EAAK,CAAC,EAAI,MACvC,CCxGA,MAAMG,EAAqB,GAM3B,SAASC,EAAWC,EAAsB,CACxC,GAAI,CAACA,EAAI,WAAW,IAAI,GAAK,CAACA,EAAI,WAAW,IAAI,EAC/C,MAAM,IAAI,MAAM,iCAAiC,EAEnD,MAAMC,EAAQD,EAAI,MAAM,CAAC,EACzB,GAAIC,EAAM,OAAS,IAAM,EACvB,MAAM,IAAI,MAAM,8BAA8BA,EAAM,MAAM,EAAE,EAE9D,GAAI,CAAC,iBAAiB,KAAKA,CAAK,EAC9B,MAAM,IAAI,MAAM,wCAAwC,EAE1D,MAAMC,EAAQ,IAAI,WAAWD,EAAM,OAAS,CAAC,EAC7C,QAASL,EAAI,EAAGA,EAAIM,EAAM,OAAQN,IAChCM,EAAMN,CAAC,EAAI,SAASK,EAAM,MAAML,EAAI,EAAGA,EAAI,EAAI,CAAC,EAAG,EAAE,EAEvD,OAAOM,CACT,CAKA,SAASC,EAAWD,EAAwB,CAC1C,MAAO,KAAK,MAAM,KAAKA,CAAK,EACzB,IAAKE,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAC1C,KAAK,EAAE,CAAC,EACb,CAMA,SAASC,EAAcC,EAAYC,EAAqB,CACtD,GAAID,EAAM,SAAWR,EACnB,MAAM,IAAI,MACR,GAAGS,CAAK,8BAA8BT,CAAkB,mCAAmCQ,EAAM,MAAM,EAAA,CAG7G,CAYO,SAASE,EAAgBC,EAAkB,CAChDJ,EAAcI,EAAQ,QAAQ,EAC9B,MAAMC,EAAcX,EAAWU,CAAM,EAC/BE,EAAOC,EAAAA,OAAOF,CAAW,EAC/B,OAAOP,EAAWQ,CAAI,CACxB,CAaO,SAASE,EACdJ,EACAK,EACS,CACT,OAAAT,EAAcI,EAAQ,QAAQ,EAC9BJ,EAAcS,EAAU,UAAU,EAElCf,EAAWe,CAAQ,EAEFN,EAAgBC,CAAM,EACvB,gBAAkBK,EAAS,YAAA,CAC7C,CCuDO,MAAMC,CAAc,CAQzB,YAAYC,EAA6B,CAPxBC,EAAA,eAQf,KAAK,OAASD,CAChB,CAwBA,MAAM,sBACJE,EACgC,CAEhC,MAAMC,EAAkB,MAAM,KAAK,OAAO,UAAU,gBAAA,EAC9C,CAAE,gBAAAC,GAAoBC,EAAAA,qBAC1BF,EACAD,EAAO,kBAAA,EAMHI,EAAa,MAAMC,kBAAgB,CACvC,YAAaL,EAAO,YACpB,WAAYA,EAAO,WACnB,YAAaA,EAAO,YACpB,mBAAoBE,EACpB,uBAAwBF,EAAO,uBAC/B,sBAAuBA,EAAO,sBAC9B,8BAA+BA,EAAO,8BACtC,cAAeA,EAAO,cACtB,QAAS,KAAK,OAAO,QACrB,iBAAkBA,EAAO,iBACzB,6BAA8BA,EAAO,6BACrC,cAAeA,EAAO,aAAA,CACvB,EAGKM,EAAgB,MAAM,KAAK,OAAO,UAAU,SAChDF,EAAW,QACXG,EAAAA,mCAAmCN,EAAiB,CAAC,CAAA,EAGvDO,OAAAA,8BAA4B,CAC1B,iBAAkBJ,EAAW,QAC7B,gBAAiBE,CAAA,CAClB,EAKM,CACL,UAHgBG,EAAAA,uBAAuBH,EAAeJ,CAAe,EAIrE,mBAAoBA,CAAA,CAExB,CAOA,YAAsB,CACpB,OAAO,KAAK,OAAO,OACrB,CAOA,sBAAgC,CAC9B,OAAO,OAAO,KAAK,OAAO,UAAU,WAAc,UACpD,CAWA,MAAM,4BACJQ,EAMA,CACA,GAAI,CAAC,KAAK,uBACR,MAAM,IAAI,MACR,wEAAA,EAKJ,MAAMT,EAAkB,MAAM,KAAK,OAAO,UAAU,gBAAA,EAG9CU,EAAwB,CAAA,EACxBC,EAAiC,CAAA,EACjCC,EAA6B,CAAA,EAEnC,UAAW1C,KAAMuC,EAAc,CAE7B,KAAM,CAAE,gBAAAR,GAAoBC,EAAAA,qBAC1BF,EACA9B,EAAG,kBAAA,EAEL0C,EAAiB,KAAKX,CAAe,EAIrC,MAAME,EAAa,MAAMC,kBAAgB,CACvC,YAAalC,EAAG,YAChB,WAAYA,EAAG,WACf,YAAaA,EAAG,YAChB,mBAAoB+B,EACpB,uBAAwB/B,EAAG,uBAC3B,sBAAuBA,EAAG,sBAC1B,8BAA+BA,EAAG,8BAClC,cAAeA,EAAG,cAClB,QAAS,KAAK,OAAO,QACrB,iBAAkBA,EAAG,iBACrB,6BAA8BA,EAAG,6BACjC,cAAeA,EAAG,aAAA,CACnB,EACDwC,EAAY,KAAKP,EAAW,OAAO,EACnCQ,EAAY,KAAKL,EAAAA,mCAAmCN,EAAiB,CAAC,CAAC,CACzE,CAGA,MAAMa,EAAc,MAAM,KAAK,OAAO,UAAU,UAC9CH,EACAC,CAAA,EAIF,GAAIE,EAAY,SAAWJ,EAAa,OACtC,MAAM,IAAI,MACR,YAAYA,EAAa,MAAM,8BAA8BI,EAAY,MAAM,EAAA,EAKnF,MAAMC,EAGD,CAAA,EAEL,QAASrC,EAAI,EAAGA,EAAIgC,EAAa,OAAQhC,IAAK,CAC5C,MAAMwB,EAAkBW,EAAiBnC,CAAC,EAC1C8B,8BAA4B,CAC1B,iBAAkBG,EAAYjC,CAAC,EAC/B,gBAAiBoC,EAAYpC,CAAC,CAAA,CAC/B,EACD,MAAMsC,EAAkBP,EAAAA,uBACtBK,EAAYpC,CAAC,EACbwB,CAAA,EAGFa,EAAQ,KAAK,CACX,gBAAAC,EACA,mBAAoBd,CAAA,CACrB,CACH,CAEA,OAAOa,CACT,CAEF"}
@@ -6,7 +6,7 @@ import { s as k, v as p } from "./bitcoin-B5aNKtsk.js";
6
6
  import { s as E } from "./sha2-BYVxyZzX.js";
7
7
  import { c as b } from "./signing-DaLvGwQe.js";
8
8
  import "@babylonlabs-io/babylon-tbv-rust-wasm";
9
- import { c as x, d as y, e as d } from "./assertPsbtUnsignedTxMatches-CzVv57QF.js";
9
+ import { c as x, d as y, e as d } from "./assertPsbtUnsignedTxMatches-GHobJP-d.js";
10
10
  const H = 106, B = 32, l = 34;
11
11
  function W(e, t, s) {
12
12
  const o = k(e), c = w.Transaction.fromHex(o);
@@ -225,4 +225,4 @@ export {
225
225
  L as f,
226
226
  A as v
227
227
  };
228
- //# sourceMappingURL=PayoutManager-DChODEOJ.js.map
228
+ //# sourceMappingURL=PayoutManager-CXDccwDN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PayoutManager-DChODEOJ.js","sources":["../src/tbv/core/managers/pegin/assertAuthAnchorOpReturn.ts","../src/tbv/core/services/htlc/index.ts","../src/tbv/core/managers/PayoutManager.ts"],"sourcesContent":["/**\n * Structural verifier for the auth-anchor OP_RETURN in a funded\n * Pre-PegIn transaction.\n *\n * @module managers/pegin/assertAuthAnchorOpReturn\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport { stripHexPrefix } from \"../../primitives/utils/bitcoin\";\n\n/** OP_RETURN opcode. */\nconst OP_RETURN = 0x6a;\n/** Push-32-bytes opcode (raw push, not OP_PUSHDATA1). */\nconst OP_PUSH32 = 0x20;\n/** Encoded length of a standard OP_RETURN script with a 32-byte payload. */\nconst OP_RETURN_PUSH32_SCRIPT_LEN = 1 + 1 + 32;\n\n/**\n * Verify the broadcast Pre-PegIn carries the expected OP_RETURN\n * commitment to the auth anchor.\n *\n * The OP_RETURN sits at `vout = vaultCount` (right after the per-vault\n * HTLC outputs and before the depositor-claim/change outputs) and\n * pushes the 32-byte `SHA256(authAnchor)`. The script encoding is\n * exactly `OP_RETURN || PUSH32 || <32 bytes>` (34 bytes). A\n * non-conformant WASM build that omitted the OP_RETURN, swapped its\n * position, or changed its push payload would let the depositor\n * obtain a valid bearer token for a Pre-PegIn whose on-chain\n * commitment doesn't actually bind the anchor — degrading the auth\n * from on-chain-bound to a shared secret. Fail closed.\n *\n * @throws If the OP_RETURN is missing, mis-located, mis-encoded, or\n * pushes a payload other than `expectedAuthAnchorHashHex`.\n */\nexport function assertAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n vaultCount: number,\n expectedAuthAnchorHashHex: string,\n): void {\n const cleanHex = stripHexPrefix(fundedPrePeginTxHex);\n const tx = bitcoin.Transaction.fromHex(cleanHex);\n\n if (tx.outs.length <= vaultCount) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN missing: tx has ${tx.outs.length} ` +\n `outputs, expected at least ${vaultCount + 1} (vault outputs + OP_RETURN)`,\n );\n }\n\n const opReturnOutput = tx.outs[vaultCount];\n const script = opReturnOutput.script;\n if (\n script.length !== OP_RETURN_PUSH32_SCRIPT_LEN ||\n script[0] !== OP_RETURN ||\n script[1] !== OP_PUSH32\n ) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has unexpected ` +\n `script encoding (got ${script.length}-byte script with prefix ` +\n `0x${script.slice(0, Math.min(2, script.length)).toString(\"hex\")}; ` +\n `expected ${OP_RETURN_PUSH32_SCRIPT_LEN}-byte OP_RETURN + PUSH32 layout)`,\n );\n }\n\n const pushedHex = script.slice(2).toString(\"hex\").toLowerCase();\n if (pushedHex !== expectedAuthAnchorHashHex.toLowerCase()) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${vaultCount}: ` +\n `tx pushes ${pushedHex}, expected ${expectedAuthAnchorHashHex}`,\n );\n }\n\n if (opReturnOutput.value !== 0) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has non-zero ` +\n `value ${opReturnOutput.value}; OP_RETURN outputs must be 0-value`,\n );\n }\n}\n\n/**\n * Scan a funded Pre-PegIn transaction for its auth-anchor commitment\n * (an `OP_RETURN || PUSH32 || <32 bytes>` output with value 0).\n *\n * Returns `{ vout, hash }` when exactly one such output is found.\n * Returns `undefined` when:\n * - the hex is unparseable,\n * - no matching output exists (legacy non-auth-anchored Pre-PegIn),\n * - more than one matching output exists (ambiguous / malformed).\n *\n * Used by the refund orchestrator to (a) locate the on-chain anchor\n * regardless of how many HTLCs preceded it and (b) detect multi-vault\n * funded transactions structurally: the single-vault refund path\n * reconstructs only one hashlock and expects the anchor at vout 1, so\n * any other vout signals a layout this call cannot safely refund.\n */\nexport function findAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n): { vout: number; hash: string } | undefined {\n let tx: bitcoin.Transaction;\n try {\n tx = bitcoin.Transaction.fromHex(stripHexPrefix(fundedPrePeginTxHex));\n } catch {\n return undefined;\n }\n\n const hits: { vout: number; hash: string }[] = [];\n for (let i = 0; i < tx.outs.length; i++) {\n const output = tx.outs[i];\n const script = output.script;\n if (\n script.length === OP_RETURN_PUSH32_SCRIPT_LEN &&\n script[0] === OP_RETURN &&\n script[1] === OP_PUSH32 &&\n output.value === 0\n ) {\n hits.push({\n vout: i,\n hash: script.slice(2).toString(\"hex\").toLowerCase(),\n });\n }\n }\n\n return hits.length === 1 ? hits[0] : undefined;\n}\n","/**\n * HTLC Secret / Hashlock Utilities\n *\n * Pure functions for computing and validating SHA-256 hashlocks used in the\n * vault deposit protocol's HTLC (Hash Time Lock Contract).\n *\n * The SDK does NOT generate secrets — that is the caller's responsibility.\n * Today callers use `crypto.getRandomValues(32)`; when the `deriveContextHash`\n * wallet API ships, callers will use `wallet.deriveContextHash(\"babylon-btc-vault\", ctx)`.\n * These utilities work identically regardless of how the secret was produced.\n *\n * On-chain contract validation (BTCVaultRegistry.activateVaultWithSecret):\n * if (sha256(abi.encodePacked(s)) != hashlock) revert InvalidSecret();\n *\n * @module htlc\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport type { Hex } from \"viem\";\n\n/** Expected hex length for a 0x-prefixed bytes32 value. */\nconst HEX_BYTES32_LENGTH = 66; // \"0x\" + 64 hex chars\n\n/**\n * Decode a 0x-prefixed hex string to bytes, with strict validation.\n * @throws if the input is not a valid 0x-prefixed hex string\n */\nfunction hexToBytes(hex: Hex): Uint8Array {\n if (!hex.startsWith(\"0x\") && !hex.startsWith(\"0X\")) {\n throw new Error(\"Expected 0x-prefixed hex string\");\n }\n const clean = hex.slice(2);\n if (clean.length % 2 !== 0) {\n throw new Error(`Hex string has odd length: ${clean.length}`);\n }\n if (!/^[0-9a-fA-F]*$/.test(clean)) {\n throw new Error(\"Hex string contains non-hex characters\");\n }\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Encode a Uint8Array as a 0x-prefixed lowercase hex string.\n */\nfunction bytesToHex(bytes: Uint8Array): Hex {\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Validate that a value is a 0x-prefixed bytes32 (exactly 32 bytes).\n * @throws if the value is not exactly 32 bytes\n */\nfunction assertBytes32(value: Hex, label: string): void {\n if (value.length !== HEX_BYTES32_LENGTH) {\n throw new Error(\n `${label} must be exactly 32 bytes (${HEX_BYTES32_LENGTH} hex chars with 0x prefix), got ${value.length}`,\n );\n }\n}\n\n/**\n * Compute the SHA-256 hashlock from a secret preimage.\n *\n * Matches the on-chain validation: `sha256(abi.encodePacked(s))` where `s` is a `bytes32`.\n * `abi.encodePacked(bytes32)` is just the raw 32 bytes — no ABI padding.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @returns 0x-prefixed bytes32 SHA-256 hash\n * @throws if secret is not exactly 32 bytes\n */\nexport function computeHashlock(secret: Hex): Hex {\n assertBytes32(secret, \"Secret\");\n const secretBytes = hexToBytes(secret);\n const hash = sha256(secretBytes);\n return bytesToHex(hash);\n}\n\n/**\n * Validate that a secret's SHA-256 hash matches the expected hashlock.\n *\n * Use this for client-side pre-validation before sending the activation\n * transaction to avoid wasting gas on a contract revert.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @param hashlock - 0x-prefixed bytes32 expected hashlock from the vault\n * @returns true if SHA-256(secret) matches the hashlock\n * @throws if secret or hashlock is not exactly 32 bytes\n */\nexport function validateSecretAgainstHashlock(\n secret: Hex,\n hashlock: Hex,\n): boolean {\n assertBytes32(secret, \"Secret\");\n assertBytes32(hashlock, \"Hashlock\");\n // Validate hashlock is valid hex (secret is validated inside computeHashlock)\n hexToBytes(hashlock);\n\n const computed = computeHashlock(secret);\n return computed.toLowerCase() === hashlock.toLowerCase();\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–4 of the 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 {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../shared/wallets\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\nimport {\n assertPsbtUnsignedTxMatches,\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). This MUST be the\n * key registered on-chain for the vault — typically read from\n * `BTCVaultRegistry.getBtcVaultBasicInfo(...).depositorBtcPubKey`.\n *\n * Required: omitting it would degrade `validateWalletPubkey` to a\n * self-comparison, allowing the wrong wallet to produce a signature\n * over a script tree that doesn't match the on-chain UTXO.\n */\n depositorBtcPubkey: string;\n\n /**\n * The on-chain registered depositor payout scriptPubKey (hex, with or without 0x prefix).\n * Used to validate that the VP-provided payout transaction actually pays to the\n * correct depositor payout address before signing.\n */\n registeredPayoutScriptPubKey: string;\n\n /**\n * The claimer's x-only BTC public key for this payout (64-char hex, no prefix).\n * Forwarded to {@link buildPayoutPsbt} for per-role output validation.\n */\n claimerBtcPubkey: string;\n\n /**\n * VP commission in basis points (`1..=9999`). Forwarded to {@link buildPayoutPsbt}.\n */\n commissionBps: number;\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 3), 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). Per-role output\n // validation happens inside buildPayoutPsbt against the resolved input\n // values.\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 claimerBtcPubkey: params.claimerBtcPubkey,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n });\n\n // Sign PSBT via wallet (Taproot script-path spend, input 0 only)\n const signedPsbtHex = await this.config.btcWallet.signPsbt(\n payoutPsbt.psbtHex,\n createTaprootScriptPathSignOptions(walletPubkeyRaw, 1),\n );\n\n assertPsbtUnsignedTxMatches({\n requestedPsbtHex: payoutPsbt.psbtHex,\n returnedPsbtHex: signedPsbtHex,\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: SignPsbtOptions[] = [];\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 (output validation runs inside buildPayoutPsbt\n // against resolved input values).\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 claimerBtcPubkey: tx.claimerBtcPubkey,\n registeredPayoutScriptPubKey: tx.registeredPayoutScriptPubKey,\n commissionBps: tx.commissionBps,\n });\n psbtsToSign.push(payoutPsbt.psbtHex);\n signOptions.push(createTaprootScriptPathSignOptions(walletPubkeyRaw, 1));\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 assertPsbtUnsignedTxMatches({\n requestedPsbtHex: psbtsToSign[i],\n returnedPsbtHex: signedPsbts[i],\n });\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}\n"],"names":["OP_RETURN","OP_PUSH32","OP_RETURN_PUSH32_SCRIPT_LEN","assertAuthAnchorOpReturn","fundedPrePeginTxHex","vaultCount","expectedAuthAnchorHashHex","cleanHex","stripHexPrefix","tx","bitcoin","opReturnOutput","script","pushedHex","findAuthAnchorOpReturn","hits","i","output","HEX_BYTES32_LENGTH","hexToBytes","hex","clean","bytes","bytesToHex","b","assertBytes32","value","label","computeHashlock","secret","secretBytes","hash","sha256","validateSecretAgainstHashlock","hashlock","PayoutManager","config","__publicField","params","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","signedPsbtHex","createTaprootScriptPathSignOptions","assertPsbtUnsignedTxMatches","extractPayoutSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature"],"mappings":"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"}
1
+ {"version":3,"file":"PayoutManager-CXDccwDN.js","sources":["../src/tbv/core/managers/pegin/assertAuthAnchorOpReturn.ts","../src/tbv/core/services/htlc/index.ts","../src/tbv/core/managers/PayoutManager.ts"],"sourcesContent":["/**\n * Structural verifier for the auth-anchor OP_RETURN in a funded\n * Pre-PegIn transaction.\n *\n * @module managers/pegin/assertAuthAnchorOpReturn\n */\n\nimport * as bitcoin from \"bitcoinjs-lib\";\n\nimport { stripHexPrefix } from \"../../primitives/utils/bitcoin\";\n\n/** OP_RETURN opcode. */\nconst OP_RETURN = 0x6a;\n/** Push-32-bytes opcode (raw push, not OP_PUSHDATA1). */\nconst OP_PUSH32 = 0x20;\n/** Encoded length of a standard OP_RETURN script with a 32-byte payload. */\nconst OP_RETURN_PUSH32_SCRIPT_LEN = 1 + 1 + 32;\n\n/**\n * Verify the broadcast Pre-PegIn carries the expected OP_RETURN\n * commitment to the auth anchor.\n *\n * The OP_RETURN sits at `vout = vaultCount` (right after the per-vault\n * HTLC outputs and before the depositor-claim/change outputs) and\n * pushes the 32-byte `SHA256(authAnchor)`. The script encoding is\n * exactly `OP_RETURN || PUSH32 || <32 bytes>` (34 bytes). A\n * non-conformant WASM build that omitted the OP_RETURN, swapped its\n * position, or changed its push payload would let the depositor\n * obtain a valid bearer token for a Pre-PegIn whose on-chain\n * commitment doesn't actually bind the anchor — degrading the auth\n * from on-chain-bound to a shared secret. Fail closed.\n *\n * @throws If the OP_RETURN is missing, mis-located, mis-encoded, or\n * pushes a payload other than `expectedAuthAnchorHashHex`.\n */\nexport function assertAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n vaultCount: number,\n expectedAuthAnchorHashHex: string,\n): void {\n const cleanHex = stripHexPrefix(fundedPrePeginTxHex);\n const tx = bitcoin.Transaction.fromHex(cleanHex);\n\n if (tx.outs.length <= vaultCount) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN missing: tx has ${tx.outs.length} ` +\n `outputs, expected at least ${vaultCount + 1} (vault outputs + OP_RETURN)`,\n );\n }\n\n const opReturnOutput = tx.outs[vaultCount];\n const script = opReturnOutput.script;\n if (\n script.length !== OP_RETURN_PUSH32_SCRIPT_LEN ||\n script[0] !== OP_RETURN ||\n script[1] !== OP_PUSH32\n ) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has unexpected ` +\n `script encoding (got ${script.length}-byte script with prefix ` +\n `0x${script.slice(0, Math.min(2, script.length)).toString(\"hex\")}; ` +\n `expected ${OP_RETURN_PUSH32_SCRIPT_LEN}-byte OP_RETURN + PUSH32 layout)`,\n );\n }\n\n const pushedHex = script.slice(2).toString(\"hex\").toLowerCase();\n if (pushedHex !== expectedAuthAnchorHashHex.toLowerCase()) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${vaultCount}: ` +\n `tx pushes ${pushedHex}, expected ${expectedAuthAnchorHashHex}`,\n );\n }\n\n if (opReturnOutput.value !== 0) {\n throw new Error(\n `Pre-PegIn auth-anchor OP_RETURN at vout ${vaultCount} has non-zero ` +\n `value ${opReturnOutput.value}; OP_RETURN outputs must be 0-value`,\n );\n }\n}\n\n/**\n * Scan a funded Pre-PegIn transaction for its auth-anchor commitment\n * (an `OP_RETURN || PUSH32 || <32 bytes>` output with value 0).\n *\n * Returns `{ vout, hash }` when exactly one such output is found.\n * Returns `undefined` when:\n * - the hex is unparseable,\n * - no matching output exists (legacy non-auth-anchored Pre-PegIn),\n * - more than one matching output exists (ambiguous / malformed).\n *\n * Used by the refund orchestrator to (a) locate the on-chain anchor\n * regardless of how many HTLCs preceded it and (b) detect multi-vault\n * funded transactions structurally: the single-vault refund path\n * reconstructs only one hashlock and expects the anchor at vout 1, so\n * any other vout signals a layout this call cannot safely refund.\n */\nexport function findAuthAnchorOpReturn(\n fundedPrePeginTxHex: string,\n): { vout: number; hash: string } | undefined {\n let tx: bitcoin.Transaction;\n try {\n tx = bitcoin.Transaction.fromHex(stripHexPrefix(fundedPrePeginTxHex));\n } catch {\n return undefined;\n }\n\n const hits: { vout: number; hash: string }[] = [];\n for (let i = 0; i < tx.outs.length; i++) {\n const output = tx.outs[i];\n const script = output.script;\n if (\n script.length === OP_RETURN_PUSH32_SCRIPT_LEN &&\n script[0] === OP_RETURN &&\n script[1] === OP_PUSH32 &&\n output.value === 0\n ) {\n hits.push({\n vout: i,\n hash: script.slice(2).toString(\"hex\").toLowerCase(),\n });\n }\n }\n\n return hits.length === 1 ? hits[0] : undefined;\n}\n","/**\n * HTLC Secret / Hashlock Utilities\n *\n * Pure functions for computing and validating SHA-256 hashlocks used in the\n * vault deposit protocol's HTLC (Hash Time Lock Contract).\n *\n * The SDK does NOT generate secrets — that is the caller's responsibility.\n * Today callers use `crypto.getRandomValues(32)`; when the `deriveContextHash`\n * wallet API ships, callers will use `wallet.deriveContextHash(\"babylon-btc-vault\", ctx)`.\n * These utilities work identically regardless of how the secret was produced.\n *\n * On-chain contract validation (BTCVaultRegistry.activateVaultWithSecret):\n * if (sha256(abi.encodePacked(s)) != hashlock) revert InvalidSecret();\n *\n * @module htlc\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport type { Hex } from \"viem\";\n\n/** Expected hex length for a 0x-prefixed bytes32 value. */\nconst HEX_BYTES32_LENGTH = 66; // \"0x\" + 64 hex chars\n\n/**\n * Decode a 0x-prefixed hex string to bytes, with strict validation.\n * @throws if the input is not a valid 0x-prefixed hex string\n */\nfunction hexToBytes(hex: Hex): Uint8Array {\n if (!hex.startsWith(\"0x\") && !hex.startsWith(\"0X\")) {\n throw new Error(\"Expected 0x-prefixed hex string\");\n }\n const clean = hex.slice(2);\n if (clean.length % 2 !== 0) {\n throw new Error(`Hex string has odd length: ${clean.length}`);\n }\n if (!/^[0-9a-fA-F]*$/.test(clean)) {\n throw new Error(\"Hex string contains non-hex characters\");\n }\n const bytes = new Uint8Array(clean.length / 2);\n for (let i = 0; i < bytes.length; i++) {\n bytes[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16);\n }\n return bytes;\n}\n\n/**\n * Encode a Uint8Array as a 0x-prefixed lowercase hex string.\n */\nfunction bytesToHex(bytes: Uint8Array): Hex {\n return `0x${Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\")}`;\n}\n\n/**\n * Validate that a value is a 0x-prefixed bytes32 (exactly 32 bytes).\n * @throws if the value is not exactly 32 bytes\n */\nfunction assertBytes32(value: Hex, label: string): void {\n if (value.length !== HEX_BYTES32_LENGTH) {\n throw new Error(\n `${label} must be exactly 32 bytes (${HEX_BYTES32_LENGTH} hex chars with 0x prefix), got ${value.length}`,\n );\n }\n}\n\n/**\n * Compute the SHA-256 hashlock from a secret preimage.\n *\n * Matches the on-chain validation: `sha256(abi.encodePacked(s))` where `s` is a `bytes32`.\n * `abi.encodePacked(bytes32)` is just the raw 32 bytes — no ABI padding.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @returns 0x-prefixed bytes32 SHA-256 hash\n * @throws if secret is not exactly 32 bytes\n */\nexport function computeHashlock(secret: Hex): Hex {\n assertBytes32(secret, \"Secret\");\n const secretBytes = hexToBytes(secret);\n const hash = sha256(secretBytes);\n return bytesToHex(hash);\n}\n\n/**\n * Validate that a secret's SHA-256 hash matches the expected hashlock.\n *\n * Use this for client-side pre-validation before sending the activation\n * transaction to avoid wasting gas on a contract revert.\n *\n * @param secret - 0x-prefixed bytes32 secret (66 hex chars)\n * @param hashlock - 0x-prefixed bytes32 expected hashlock from the vault\n * @returns true if SHA-256(secret) matches the hashlock\n * @throws if secret or hashlock is not exactly 32 bytes\n */\nexport function validateSecretAgainstHashlock(\n secret: Hex,\n hashlock: Hex,\n): boolean {\n assertBytes32(secret, \"Secret\");\n assertBytes32(hashlock, \"Hashlock\");\n // Validate hashlock is valid hex (secret is validated inside computeHashlock)\n hexToBytes(hashlock);\n\n const computed = computeHashlock(secret);\n return computed.toLowerCase() === hashlock.toLowerCase();\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–4 of the 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 {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../shared/wallets\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\nimport {\n assertPsbtUnsignedTxMatches,\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). This MUST be the\n * key registered on-chain for the vault — typically read from\n * `BTCVaultRegistry.getBtcVaultBasicInfo(...).depositorBtcPubKey`.\n *\n * Required: omitting it would degrade `validateWalletPubkey` to a\n * self-comparison, allowing the wrong wallet to produce a signature\n * over a script tree that doesn't match the on-chain UTXO.\n */\n depositorBtcPubkey: string;\n\n /**\n * The on-chain registered depositor payout scriptPubKey (hex, with or without 0x prefix).\n * Used to validate that the VP-provided payout transaction actually pays to the\n * correct depositor payout address before signing.\n */\n registeredPayoutScriptPubKey: string;\n\n /**\n * The claimer's x-only BTC public key for this payout (64-char hex, no prefix).\n * Forwarded to {@link buildPayoutPsbt} for per-role output validation.\n */\n claimerBtcPubkey: string;\n\n /**\n * VP commission in basis points (`1..=9999`). Forwarded to {@link buildPayoutPsbt}.\n */\n commissionBps: number;\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 3), 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). Per-role output\n // validation happens inside buildPayoutPsbt against the resolved input\n // values.\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 claimerBtcPubkey: params.claimerBtcPubkey,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n });\n\n // Sign PSBT via wallet (Taproot script-path spend, input 0 only)\n const signedPsbtHex = await this.config.btcWallet.signPsbt(\n payoutPsbt.psbtHex,\n createTaprootScriptPathSignOptions(walletPubkeyRaw, 1),\n );\n\n assertPsbtUnsignedTxMatches({\n requestedPsbtHex: payoutPsbt.psbtHex,\n returnedPsbtHex: signedPsbtHex,\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: SignPsbtOptions[] = [];\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 (output validation runs inside buildPayoutPsbt\n // against resolved input values).\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 claimerBtcPubkey: tx.claimerBtcPubkey,\n registeredPayoutScriptPubKey: tx.registeredPayoutScriptPubKey,\n commissionBps: tx.commissionBps,\n });\n psbtsToSign.push(payoutPsbt.psbtHex);\n signOptions.push(createTaprootScriptPathSignOptions(walletPubkeyRaw, 1));\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 assertPsbtUnsignedTxMatches({\n requestedPsbtHex: psbtsToSign[i],\n returnedPsbtHex: signedPsbts[i],\n });\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}\n"],"names":["OP_RETURN","OP_PUSH32","OP_RETURN_PUSH32_SCRIPT_LEN","assertAuthAnchorOpReturn","fundedPrePeginTxHex","vaultCount","expectedAuthAnchorHashHex","cleanHex","stripHexPrefix","tx","bitcoin","opReturnOutput","script","pushedHex","findAuthAnchorOpReturn","hits","i","output","HEX_BYTES32_LENGTH","hexToBytes","hex","clean","bytes","bytesToHex","b","assertBytes32","value","label","computeHashlock","secret","secretBytes","hash","sha256","validateSecretAgainstHashlock","hashlock","PayoutManager","config","__publicField","params","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","signedPsbtHex","createTaprootScriptPathSignOptions","assertPsbtUnsignedTxMatches","extractPayoutSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";var Lt=Object.defineProperty;var Xt=(n,t,e)=>t in n?Lt(n,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[t]=e;var T=(n,t,e)=>Xt(n,typeof t!="symbol"?t+"":t,e);const b=require("./sha2-DsrLC4NM.cjs"),K=require("bitcoinjs-lib"),et=require("buffer"),O=require("viem"),I=require("./BTCVaultRegistry.abi-CHFGevwa.cjs"),R=require("./errors-BP73_stm.cjs"),F=require("@babylonlabs-io/babylon-tbv-rust-wasm"),U=require("./assertPsbtUnsignedTxMatches-CABhEADu.cjs"),j=require("./peginInput-DH6X4ITS.cjs"),l=require("./bitcoin-CHfKAhcI.cjs"),Dt=require("./signing-Bnsro0hE.cjs"),ct=require("./validation-u8W7Lp2x.cjs"),bt=require("./PayoutManager-BwYlPF2C.cjs"),C=require("./waitForTransactionReceiptSmartAware-BFMQFEzj.cjs"),lt=require("./fundPeginTransaction-C8qsXxNV.cjs"),xt=require("./mempoolApi-DEAS9wVa.cjs");function Kt(n){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(n){for(const e in n)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(n,e);Object.defineProperty(t,e,s.get?s:{enumerable:!0,get:()=>n[e]})}}return t.default=n,Object.freeze(t)}const wt=Kt(K),W=BigInt(2**32-1),ut=BigInt(32);function qt(n,t=!1){return t?{h:Number(n&W),l:Number(n>>ut&W)}:{h:Number(n>>ut&W)|0,l:Number(n&W)|0}}function Gt(n,t=!1){const e=n.length;let s=new Uint32Array(e),r=new Uint32Array(e);for(let o=0;o<e;o++){const{h:i,l:a}=qt(n[o],t);[s[o],r[o]]=[i,a]}return[s,r]}const zt=(n,t,e)=>n<<e|t>>>32-e,jt=(n,t,e)=>t<<e|n>>>32-e,Yt=(n,t,e)=>t<<e-32|n>>>64-e,Zt=(n,t,e)=>n<<e-32|t>>>64-e,N=32,Y=32,nt=36,yt=32,q=4,Qt=q+N+q+yt;function st(n,t,e){n[t]=e>>>24&255,n[t+1]=e>>>16&255,n[t+2]=e>>>8&255,n[t+3]=e&255}function Jt(n){if(n.txid.length!==Y)throw new Error(`outpoint.txid must be exactly ${Y} bytes, got ${n.txid.length}`);if(!Number.isInteger(n.vout)||n.vout<0||n.vout>4294967295)throw new Error(`outpoint.vout must be a u32, got ${n.vout}`);const t=new Uint8Array(nt);return t.set(n.txid,0),st(t,Y,n.vout),t}function ht(n,t){const e=Math.min(n.length,t.length);for(let s=0;s<e;s++)if(n[s]!==t[s])return n[s]-t[s];return n.length-t.length}function kt(n){if(n.length===0)throw new Error("buildFundingOutpointsCommitment: outpoints must be non-empty");const t=n.map(Jt);t.sort(ht);for(let s=1;s<t.length;s++)if(ht(t[s-1],t[s])===0)throw new Error("buildFundingOutpointsCommitment: duplicate outpoint detected");const e=new Uint8Array(t.length*nt);for(let s=0;s<t.length;s++)e.set(t[s],s*nt);return b.sha256(e)}function Tt(n){if(n.depositorBtcPubkey.length!==N)throw new Error(`vaultContext: depositorBtcPubkey must be exactly ${N} bytes, got ${n.depositorBtcPubkey.length}`);const t=kt(n.fundingOutpoints),e=new Uint8Array(Qt);let s=0;return st(e,s,N),s+=q,e.set(n.depositorBtcPubkey,s),s+=N,st(e,s,yt),s+=q,e.set(t,s),e}const Et="babylon-btc-vault",Bt=32,dt=Bt*2,te=/^[0-9a-f]+$/;async function _t(n,t){const e=Tt(t),s=l.uint8ArrayToHex(e),r=await n.deriveContextHash(Et,s);if(typeof r!="string")throw new Error(`deriveVaultRoot: wallet must return a string, got ${typeof r}`);if(r.length!==dt)throw new Error(`deriveVaultRoot: wallet must return a ${dt}-character hex string (${Bt} bytes), got length ${r.length}`);if(!te.test(r))throw new Error("deriveVaultRoot: wallet must return lowercase hex per derive-context-hash.md §2.1; got value with non-lowercase or non-hex characters");return l.hexToUint8Array(r)}const ee=Uint8Array.from([7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8]),At=Uint8Array.from(new Array(16).fill(0).map((n,t)=>t)),ne=At.map(n=>(9*n+5)%16),St=(()=>{const e=[[At],[ne]];for(let s=0;s<4;s++)for(let r of e)r.push(r[s].map(o=>ee[o]));return e})(),vt=St[0],It=St[1],Ct=[[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8],[12,13,11,15,6,9,9,7,12,15,11,13,7,8,7,7],[13,15,14,11,7,7,6,8,13,14,13,12,5,5,6,9],[14,11,12,14,8,6,5,5,15,12,15,14,9,9,8,6],[15,12,13,13,9,5,8,6,14,11,12,11,8,6,5,5]].map(n=>Uint8Array.from(n)),se=vt.map((n,t)=>n.map(e=>Ct[t][e])),re=It.map((n,t)=>n.map(e=>Ct[t][e])),oe=Uint32Array.from([0,1518500249,1859775393,2400959708,2840853838]),ie=Uint32Array.from([1352829926,1548603684,1836072691,2053994217,0]);function gt(n,t,e,s){return n===0?t^e^s:n===1?t&e|~t&s:n===2?(t|~e)^s:n===3?t&s|e&~s:t^(e|~s)}const L=new Uint32Array(16);class ae extends b.HashMD{constructor(){super(64,20,8,!0);T(this,"h0",1732584193);T(this,"h1",-271733879);T(this,"h2",-1732584194);T(this,"h3",271733878);T(this,"h4",-1009589776)}get(){const{h0:e,h1:s,h2:r,h3:o,h4:i}=this;return[e,s,r,o,i]}set(e,s,r,o,i){this.h0=e|0,this.h1=s|0,this.h2=r|0,this.h3=o|0,this.h4=i|0}process(e,s){for(let f=0;f<16;f++,s+=4)L[f]=e.getUint32(s,!0);let r=this.h0|0,o=r,i=this.h1|0,a=i,c=this.h2|0,h=c,u=this.h3|0,P=u,x=this.h4|0,w=x;for(let f=0;f<5;f++){const p=4-f,E=oe[f],S=ie[f],B=vt[f],m=It[f],y=se[f],k=re[f];for(let d=0;d<16;d++){const g=b.rotl(r+gt(f,i,c,u)+L[B[d]]+E,y[d])+x|0;r=x,x=u,u=b.rotl(c,10)|0,c=i,i=g}for(let d=0;d<16;d++){const g=b.rotl(o+gt(p,a,h,P)+L[m[d]]+S,k[d])+w|0;o=w,w=P,P=b.rotl(h,10)|0,h=a,a=g}}this.set(this.h1+c+P|0,this.h2+u+w|0,this.h3+x+o|0,this.h4+r+a|0,this.h0+i+h|0)}roundClean(){b.clean(L)}destroy(){this.destroyed=!0,b.clean(this.buffer),this.set(0,0,0,0,0)}}const ce=b.createHasher(()=>new ae),le=BigInt(0),V=BigInt(1),ue=BigInt(2),he=BigInt(7),de=BigInt(256),ge=BigInt(113),Ht=[],Rt=[],Ot=[];for(let n=0,t=V,e=1,s=0;n<24;n++){[e,s]=[s,(2*e+3*s)%5],Ht.push(2*(5*s+e)),Rt.push((n+1)*(n+2)/2%64);let r=le;for(let o=0;o<7;o++)t=(t<<V^(t>>he)*ge)%de,t&ue&&(r^=V<<(V<<BigInt(o))-V);Ot.push(r)}const $t=Gt(Ot,!0),fe=$t[0],pe=$t[1],ft=(n,t,e)=>e>32?Yt(n,t,e):zt(n,t,e),pt=(n,t,e)=>e>32?Zt(n,t,e):jt(n,t,e);function me(n,t=24){const e=new Uint32Array(10);for(let s=24-t;s<24;s++){for(let i=0;i<10;i++)e[i]=n[i]^n[i+10]^n[i+20]^n[i+30]^n[i+40];for(let i=0;i<10;i+=2){const a=(i+8)%10,c=(i+2)%10,h=e[c],u=e[c+1],P=ft(h,u,1)^e[a],x=pt(h,u,1)^e[a+1];for(let w=0;w<50;w+=10)n[i+w]^=P,n[i+w+1]^=x}let r=n[2],o=n[3];for(let i=0;i<24;i++){const a=Rt[i],c=ft(r,o,a),h=pt(r,o,a),u=Ht[i];r=n[u],o=n[u+1],n[u]=c,n[u+1]=h}for(let i=0;i<50;i+=10){for(let a=0;a<10;a++)e[a]=n[i+a];for(let a=0;a<10;a++)n[i+a]^=~e[(a+2)%10]&e[(a+4)%10]}n[0]^=fe[s],n[1]^=pe[s]}b.clean(e)}class it{constructor(t,e,s,r=!1,o=24){T(this,"state");T(this,"pos",0);T(this,"posOut",0);T(this,"finished",!1);T(this,"state32");T(this,"destroyed",!1);T(this,"blockLen");T(this,"suffix");T(this,"outputLen");T(this,"enableXOF",!1);T(this,"rounds");if(this.blockLen=t,this.suffix=e,this.outputLen=s,this.enableXOF=r,this.rounds=o,b.anumber(s,"outputLen"),!(0<t&&t<200))throw new Error("only keccak-f1600 function is supported");this.state=new Uint8Array(200),this.state32=b.u32(this.state)}clone(){return this._cloneInto()}keccak(){b.swap32IfBE(this.state32),me(this.state32,this.rounds),b.swap32IfBE(this.state32),this.posOut=0,this.pos=0}update(t){b.aexists(this),b.abytes(t);const{blockLen:e,state:s}=this,r=t.length;for(let o=0;o<r;){const i=Math.min(e-this.pos,r-o);for(let a=0;a<i;a++)s[this.pos++]^=t[o++];this.pos===e&&this.keccak()}return this}finish(){if(this.finished)return;this.finished=!0;const{state:t,suffix:e,pos:s,blockLen:r}=this;t[s]^=e,(e&128)!==0&&s===r-1&&this.keccak(),t[r-1]^=128,this.keccak()}writeInto(t){b.aexists(this,!1),b.abytes(t),this.finish();const e=this.state,{blockLen:s}=this;for(let r=0,o=t.length;r<o;){this.posOut>=s&&this.keccak();const i=Math.min(s-this.posOut,o-r);t.set(e.subarray(this.posOut,this.posOut+i),r),this.posOut+=i,r+=i}return t}xofInto(t){if(!this.enableXOF)throw new Error("XOF is not possible for this instance");return this.writeInto(t)}xof(t){return b.anumber(t),this.xofInto(new Uint8Array(t))}digestInto(t){if(b.aoutput(t,this),this.finished)throw new Error("digest() was already called");return this.writeInto(t),this.destroy(),t}digest(){return this.digestInto(new Uint8Array(this.outputLen))}destroy(){this.destroyed=!0,b.clean(this.state)}_cloneInto(t){const{blockLen:e,suffix:s,outputLen:r,rounds:o,enableXOF:i}=this;return t||(t=new it(e,s,r,i,o)),t.state32.set(this.state32),t.pos=this.pos,t.posOut=this.posOut,t.finished=this.finished,t.rounds=o,t.suffix=s,t.outputLen=r,t.enableXOF=i,t.destroyed=this.destroyed,t}}const Pe=(n,t,e,s={})=>b.createHasher(()=>new it(t,n,e),s),be=Pe(1,136,32),mt=64,_=20,rt=4,Ut=2,xe=0,we=1,X=[64,64],ye=n=>Array.from(n).map(t=>t.toString(16).padStart(2,"0")).join("");function at(n){return ce(b.sha256(n))}function Vt(n){return(1<<n)-1}function ke(n){let t=1;for(;t*t<n+1;)t++;return Math.max(t,2)}function Te(n){const t=rt,e=n*Vt(t);return{d:t,n,checksum_radix:ke(e)}}function Z(n,t){const e=[];let s=t;for(;s>0;)e.push(s&255),s>>>=8;const r=new Uint8Array(n.length+e.length);r.set(n);for(let o=0;o<e.length;o++)r[n.length+o]=e[o];return at(r)}function Q(n,t){let e=n;for(let s=0;s<t;s++)e=at(e);return e}function Ee(n,t){const e=Vt(t.d),s=t.checksum_radix-1,r=Math.floor(t.n*e/t.checksum_radix),o=[];for(let u=0;u<t.n;u++){const P=Z(n,u+Ut),x=Q(P,e);o.push(Array.from(x))}const i=Z(n,xe),a=Q(i,s),c=Z(n,we),h=Q(c,r);return{config:t,message_terminals:o,checksum_major_terminal:Array.from(h),checksum_minor_terminal:Array.from(a)}}async function Mt(n){try{if(n.length!==mt)throw new Error(`WOTS seed must be exactly ${mt} bytes, got ${n.length}`);const t=[];for(let e=0;e<X.length;e++){const s=X[e],r=Te(s),o=new Uint8Array(n.length+1);o.set(n),o[n.length]=e;const i=at(o);try{const a=Ee(i,r);if(a.config.d!==rt)throw new Error(`Block ${e}: expected d=${rt}, got d=${a.config.d}`);if(a.config.n!==s)throw new Error(`Block ${e}: expected n=${s}, got n=${a.config.n}`);if(a.message_terminals.length!==s)throw new Error(`Block ${e}: expected ${s} message terminals, got ${a.message_terminals.length}`);for(let c=0;c<a.message_terminals.length;c++)if(a.message_terminals[c].length!==_)throw new Error(`Block ${e} terminal ${c}: expected ${_} bytes, got ${a.message_terminals[c].length}`);if(a.checksum_minor_terminal.length!==_)throw new Error(`Block ${e} checksum_minor: expected ${_} bytes`);if(a.checksum_major_terminal.length!==_)throw new Error(`Block ${e} checksum_major: expected ${_} bytes`);t.push(a)}finally{o.fill(0),i.fill(0)}}if(t.length!==X.length)throw new Error(`Expected ${X.length} blocks, got ${t.length}`);return t}finally{n.fill(0)}}function J(n,t,e){if(n.length!==_)throw new Error(`Block ${t} ${e}: expected ${_} bytes, got ${n.length}`);for(let s=0;s<n.length;s++){const r=n[s];if(!Number.isInteger(r)||r<0||r>255)throw new Error(`Block ${t} ${e}[${s}]: invalid byte value ${r}`)}}function Nt(n){if(n.length===0)throw new Error("Public keys array must not be empty");for(let o=0;o<n.length;o++){const i=n[o];J(i.checksum_minor_terminal,o,"checksum_minor_terminal"),J(i.checksum_major_terminal,o,"checksum_major_terminal");for(let a=0;a<i.message_terminals.length;a++)J(i.message_terminals[a],o,`message_terminal[${a}]`)}let t=0;for(const o of n)t+=Ut+o.message_terminals.length;const e=new Uint8Array(t*_);let s=0;for(const o of n){e.set(o.checksum_minor_terminal,s),s+=_,e.set(o.checksum_major_terminal,s),s+=_;for(const i of o.message_terminals)e.set(i,s),s+=_}const r=be(e);return`0x${ye(r)}`}async function Be(n,t){const e=[],s=[],r=[],o=[];try{for(let i=0;i<t;i++){const a=await F.expandWotsSeed(n,i);try{const h=await Mt(a);e.push(h),s.push(Nt(h))}finally{a.fill(0)}const c=await F.expandHashlockSecret(n,i);try{const h=l.uint8ArrayToHex(c);r.push(h),o.push(bt.computeHashlock(l.ensureHexPrefix(h)).slice(2))}finally{c.fill(0)}}}finally{n.fill(0)}return{perVaultWotsKeys:e,wotsPkHashes:s,htlcSecretHexes:r,hashlocks:o}}const _e=/^0x[0-9a-f]+$/i,Ae=/^[0-9a-f]+$/i,Se=/^[A-Za-z0-9+/]+={0,2}$/;function M(n){if(typeof n!="string"||n.length===0)throw new Error("BTC wallet returned empty public key");return l.processPublicKeyToXOnly(n).toLowerCase()}function ve(n){if(typeof n!="string"||n.length===0)throw new Error("BTC wallet returned empty BIP-322 signature");if(n.startsWith("0x")||n.startsWith("0X")){if(!_e.test(n)||n.length<4||n.length%2!==0)throw new Error("BTC wallet returned malformed hex BIP-322 signature");return n.toLowerCase()}if(Ae.test(n)){if(n.length%2!==0)throw new Error("BTC wallet returned malformed hex BIP-322 signature");return`0x${n.toLowerCase()}`}if(!Se.test(n)||n.length%4!==0)throw new Error("BTC wallet returned malformed base64 BIP-322 signature");const t=et.Buffer.from(n,"base64");if(t.length===0||t.toString("base64")!==n)throw new Error("BTC wallet returned malformed base64 BIP-322 signature");return`0x${t.toString("hex")}`}async function Ie(n,t,e){if(typeof n.signPsbts=="function"){const r=await n.signPsbts(t,e);if(r.length!==t.length)throw new Error(`Expected ${t.length} signed PSBTs but received ${r.length}`);return r}const s=[];for(let r=0;r<t.length;r++){const o=await n.signPsbt(t[r],e[r]);s.push(o)}return s}const Ft=0,D=25,ot=9999,tt="00".repeat(32);function Ce(n,t){const e={bitcoin:"bc",testnet:"tb",signet:"tb",regtest:"bcrt"};try{const s=wt.address.fromBech32(n);return s.prefix===e[t]&&s.version===0&&s.data.length===20}catch{return!1}}function He(n,t,e,s){const r=e==null?void 0:e[`${n}:${t}`];return r?Promise.resolve({txid:n,vout:t,value:r.value,scriptPubKey:r.scriptPubKey}):xt.getUtxoInfo(n,t,s)}const Pt=12e4;class Re{constructor(t){T(this,"config");this.config=t}async preparePegin(t){if(t.amounts.length===0)throw new Error("amounts must contain at least one entry");const e=await this.config.btcWallet.getPublicKeyHex(),s=M(e);if(!l.isAddressFromPublicKey(t.changeAddress,e,this.config.btcNetwork))throw new Error(`Pre-PegIn changeAddress "${t.changeAddress}" is not derived from the connected wallet's public key. Refusing to build a tx that would send change to an address the signing key doesn't control.`);const r=await this.prepareSizing(s,t),o=r.selectedUTXOs.map(p=>({txid:l.hexToUint8Array(p.txid),vout:p.vout})),i=await _t(this.config.btcWallet,{depositorBtcPubkey:l.hexToUint8Array(s),fundingOutpoints:o});let a,c;try{const p=await F.expandAuthAnchor(i);try{a=l.uint8ArrayToHex(p),c=l.uint8ArrayToHex(b.sha256(p))}finally{p.fill(0)}}catch(p){throw i.fill(0),p}const h=await Be(i,t.amounts.length),{perVaultWotsKeys:u,wotsPkHashes:P,htlcSecretHexes:x,hashlocks:w}=h,f=await this.preparePeginCommit({depositorBtcPubkeyRaw:e,depositorBtcPubkey:s,hashlocks:w,authAnchorHash:c,sizing:r,params:t});for(let p=0;p<f.perVault.length;p++)if(f.perVault[p].htlcVout!==p)throw new Error(`Internal invariant violation: htlcVout/index mismatch at vault ${p} (expected ${p}, got ${f.perVault[p].htlcVout})`);return bt.assertAuthAnchorOpReturn(f.fundedPrePeginTxHex,t.amounts.length,c),{transaction:{...f,selectedUTXOs:r.selectedUTXOs,fee:r.fee,changeAmount:r.changeAmount},depositorBtcPubkey:s,derivedSecrets:{perVaultWotsKeys:u,wotsPkHashes:P,htlcSecretHexes:x,authAnchorHex:a}}}async prepareSizing(t,e){const s=e.amounts.map(()=>tt),r=e.vaultKeeperBtcPubkeys.length,o=await U.buildPrePeginPsbt({depositorPubkey:t,vaultProviderPubkey:l.stripHexPrefix(e.vaultProviderBtcPubkey),vaultKeeperPubkeys:e.vaultKeeperBtcPubkeys.map(l.stripHexPrefix),universalChallengerPubkeys:e.universalChallengerBtcPubkeys.map(l.stripHexPrefix),hashlocks:s,timelockRefund:e.timelockRefund,pegInAmounts:e.amounts,feeRate:e.protocolFeeRate,minPeginFeeRate:e.minPeginFeeRate,numLocalChallengers:r,councilQuorum:e.councilQuorum,councilSize:e.councilSize,network:this.config.btcNetwork,authAnchorHash:tt}),i=C.selectUtxosForPegin([...e.availableUTXOs],o.totalOutputValue,e.mempoolFeeRate,lt.peginOutputCount(o.htlcValues.length,!0));return{selectedUTXOs:i.selectedUTXOs,fee:i.fee,changeAmount:i.changeAmount}}async preparePeginCommit(t){const{depositorBtcPubkeyRaw:e,depositorBtcPubkey:s,hashlocks:r,authAnchorHash:o,sizing:i,params:a}=t,c=tt.toLowerCase();for(let g=0;g<r.length;g++)if(r[g].toLowerCase()===c)throw new Error(`preparePeginCommit refusing to build with sizing-pass placeholder hashlock at vault ${g} — internal substitution bug`);if(o.toLowerCase()===c)throw new Error("preparePeginCommit refusing to build with sizing-pass placeholder auth-anchor hash — internal substitution bug");const h=l.stripHexPrefix(a.vaultProviderBtcPubkey),u=a.vaultKeeperBtcPubkeys.map(l.stripHexPrefix),P=a.universalChallengerBtcPubkeys.map(l.stripHexPrefix),x=u.length,w={depositorPubkey:s,vaultProviderPubkey:h,vaultKeeperPubkeys:u,universalChallengerPubkeys:P,hashlocks:r,timelockRefund:a.timelockRefund,pegInAmounts:a.amounts,feeRate:a.protocolFeeRate,minPeginFeeRate:a.minPeginFeeRate,numLocalChallengers:x,councilQuorum:a.councilQuorum,councilSize:a.councilSize,network:this.config.btcNetwork,authAnchorHash:o},f=await U.buildPrePeginPsbt(w),p=l.getNetwork(this.config.btcNetwork),E=lt.fundPeginTransaction({unfundedTxHex:f.psbtHex,selectedUTXOs:i.selectedUTXOs,changeAddress:a.changeAddress,changeAmount:i.changeAmount,network:p}),S=l.stripHexPrefix(C.calculateBtcTxHash(E)),B=[],m=[],y=[];for(let g=0;g<r.length;g++){const A=await U.buildPeginTxFromFundedPrePegin({prePeginParams:w,timelockPegin:a.timelockPegin,fundedPrePeginTxHex:E,htlcVout:g}),v=await j.buildPeginInputPsbt({peginTxHex:A.txHex,fundedPrePeginTxHex:E,depositorPubkey:s,vaultProviderPubkey:h,vaultKeeperPubkeys:u,universalChallengerPubkeys:P,hashlock:r[g],timelockRefund:a.timelockRefund,network:this.config.btcNetwork});B.push(A),m.push(v.psbtHex),y.push(Dt.createTaprootScriptPathSignOptions(e,1))}const k=await Ie(this.config.btcWallet,m,y),d=[];for(let g=0;g<k.length;g++){U.assertPsbtUnsignedTxMatches({requestedPsbtHex:m[g],returnedPsbtHex:k[g]});const A=j.extractPeginInputSignature(k[g],s),v=j.finalizePeginInputPsbt(k[g]);d.push({htlcVout:g,htlcValue:f.htlcValues[g],peginTxHex:v,peginTxid:B[g].txid,peginInputSignature:A,vaultScriptPubKey:B[g].vaultScriptPubKey})}return{fundedPrePeginTxHex:E,prePeginTxid:S,perVault:d}}async signAndBroadcast(t){const{fundedPrePeginTxHex:e,depositorBtcPubkey:s}=t,r=e.startsWith("0x")?e.slice(2):e,o=K.Transaction.fromHex(r);if(o.ins.length===0)throw new Error("Transaction has no inputs");const i=new K.Psbt;i.setVersion(o.version),i.setLocktime(o.locktime);const a=et.Buffer.from(M(s),"hex"),c=this.config.mempoolApiUrl,h=o.ins.map(m=>{const y=et.Buffer.from(m.hash).reverse().toString("hex"),k=m.index;return He(y,k,t.localPrevouts,c).then(d=>({input:m,utxoData:d,txid:y,vout:k}))}),u=await Promise.all(h),P=u.reduce((m,y)=>m+BigInt(y.utxoData.value),0n),x=o.outs.reduce((m,y)=>m+BigInt(y.value),0n);if(P<x)throw new Error(`UTXO value mismatch: total input value (${P} sat) is less than total output value (${x} sat). This may indicate the mempool API returned manipulated UTXO data.`);const w=P-x;if(w>ct.MAX_REASONABLE_FEE_SATS)throw new Error(`Implied transaction fee (${w} sat) exceeds maximum reasonable fee (${ct.MAX_REASONABLE_FEE_SATS} sat). This may indicate manipulated UTXO data.`);for(const{input:m,utxoData:y,txid:k,vout:d}of u){const g=C.getPsbtInputFields({value:y.value,scriptPubKey:y.scriptPubKey},a);i.addInput({hash:m.hash,index:m.index,sequence:m.sequence,...g})}for(const m of o.outs)i.addOutput({script:m.script,value:m.value});const f=i.toHex(),p=await this.config.btcWallet.signPsbt(f);U.assertPsbtUnsignedTxMatches({requestedPsbtHex:f,returnedPsbtHex:p});const E=K.Psbt.fromHex(p);try{E.finalizeAllInputs()}catch(m){if(!E.data.inputs.every(k=>k.finalScriptWitness||k.finalScriptSig))throw new Error(`PSBT finalization failed and wallet did not auto-finalize: ${m}`)}const S=E.extractTransaction().toHex();return await xt.pushTx(S,c)}async registerPeginOnChain(t){const{unsignedPrePeginTx:e,depositorSignedPeginTx:s,vaultProvider:r,hashlock:o,htlcVout:i,depositorPayoutBtcAddress:a,depositorWotsPkHash:c,popSignature:h}=t;if(!this.config.ethWallet.account)throw new Error("Ethereum wallet account not found");const u=this.config.ethWallet.account.address;if(!O.isAddressEqual(h.depositorEthAddress,u))throw new Error(`Proof of possession was signed for ${h.depositorEthAddress} but the Ethereum wallet is currently connected to ${u}. Reconnect the original account or call signProofOfPossession() again.`);const P=await this.assertPopMatchesBtcWallet(h),x=h.btcPopSignature,w=l.ensureHexPrefix(h.depositorBtcPubkey),f=l.ensureHexPrefix(e),p=l.ensureHexPrefix(s),E=a??await this.config.btcWallet.getAddress(),S=this.resolvePayoutScriptPubKey(P,E),B=C.calculateBtcTxHash(p),m=await F.deriveVaultId(l.stripHexPrefix(B),l.stripHexPrefix(u)),y=l.ensureHexPrefix(m);if(await this.checkVaultExists(y))throw new Error(`Vault already exists (ID: ${y}, peginTxHash: ${B}). Vault IDs are derived from the pegin transaction hash and depositor address. To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`);const d=this.config.publicClient;let g;try{g=await d.readContract({address:this.config.vaultContracts.btcVaultRegistry,abi:I.BTCVaultRegistryABI,functionName:"getPegInFee",args:[r]})}catch($){throw new Error("Failed to query pegin fee from the contract. Please check your network connection and that the contract address is correct.",{cause:$})}const A=await this.resolveMaxAcceptableCommissionBps(r,t.quotedCommissionBps),v=O.encodeFunctionData({abi:I.BTCVaultRegistryABI,functionName:"submitPeginRequest",args:[u,w,x,f,p,r,A,o,i,S,c]});let H;try{H=await d.estimateGas({to:this.config.vaultContracts.btcVaultRegistry,data:v,value:g,account:this.config.ethWallet.account.address})}catch($){R.handleContractError($)}let G;try{G=await this.config.ethWallet.sendTransaction({to:this.config.vaultContracts.btcVaultRegistry,data:v,value:g,account:this.config.ethWallet.account,chain:this.config.ethChain,gas:H})}catch($){R.handleContractError($)}const z=await C.waitForTransactionReceiptSmartAware({publicClient:d,walletAddress:this.config.ethWallet.account.address,hash:G,timeout:Pt});return z.status==="reverted"&&R.handleContractError(new Error(`Transaction reverted. Hash: ${z.transactionHash}. Check the transaction on block explorer for details.`)),{ethTxHash:z.transactionHash,vaultId:y,peginTxHash:B}}async registerPeginBatchOnChain(t){const{vaultProvider:e,unsignedPrePeginTx:s,requests:r,popSignature:o}=t;if(r.length===0)throw new Error("Batch pegin requires at least one request");if(!this.config.ethWallet.account)throw new Error("Ethereum wallet account not found");const i=this.config.ethWallet.account.address;if(!O.isAddressEqual(o.depositorEthAddress,i))throw new Error(`Proof of possession was signed for ${o.depositorEthAddress} but the Ethereum wallet is currently connected to ${i}. Reconnect the original account or call signProofOfPossession() again.`);const a=await this.assertPopMatchesBtcWallet(o),c=o.btcPopSignature,h=r.map(d=>this.resolvePayoutScriptPubKey(a,d.depositorPayoutBtcAddress)),u=[];for(const d of r){const g=l.ensureHexPrefix(d.depositorSignedPeginTx),A=C.calculateBtcTxHash(g),v=await F.deriveVaultId(l.stripHexPrefix(A),l.stripHexPrefix(i)),H=l.ensureHexPrefix(v);if(await this.checkVaultExists(H))throw new Error(`Vault already exists (ID: ${H}, peginTxHash: ${A}). To create a new vault, use different UTXOs or a different amount.`);u.push({vaultId:H,peginTxHash:A})}const P=this.config.publicClient;let x;try{x=await P.readContract({address:this.config.vaultContracts.btcVaultRegistry,abi:I.BTCVaultRegistryABI,functionName:"getPegInFee",args:[e]})}catch(d){throw new Error("Failed to query pegin fee from the contract. Please check your network connection and that the contract address is correct.",{cause:d})}const w=x*BigInt(r.length),f=await this.resolveMaxAcceptableCommissionBps(e,t.quotedCommissionBps),p=l.ensureHexPrefix(o.depositorBtcPubkey),E=l.ensureHexPrefix(s),S=r.map((d,g)=>({depositorBtcPubKey:p,btcPopSignature:c,unsignedPrePeginTx:E,depositorSignedPeginTx:l.ensureHexPrefix(d.depositorSignedPeginTx),hashlock:d.hashlock,htlcVout:d.htlcVout,referralCode:Ft,depositorPayoutBtcAddress:h[g],depositorWotsPkHash:d.depositorWotsPkHash})),B=O.encodeFunctionData({abi:I.BTCVaultRegistryABI,functionName:"submitPeginRequestBatch",args:[i,e,f,S]});let m;try{m=await P.estimateGas({to:this.config.vaultContracts.btcVaultRegistry,data:B,value:w,account:this.config.ethWallet.account.address})}catch(d){R.handleContractError(d)}let y;try{y=await this.config.ethWallet.sendTransaction({to:this.config.vaultContracts.btcVaultRegistry,data:B,value:w,account:this.config.ethWallet.account,chain:this.config.ethChain,gas:m})}catch(d){R.handleContractError(d)}const k=await C.waitForTransactionReceiptSmartAware({publicClient:P,walletAddress:this.config.ethWallet.account.address,hash:y,timeout:Pt});return k.status==="reverted"&&R.handleContractError(new Error(`Batch transaction reverted. Hash: ${k.transactionHash}. Check the transaction on block explorer for details.`)),{ethTxHash:k.transactionHash,vaults:u}}async resolveMaxAcceptableCommissionBps(t,e){let s;try{s=await this.config.publicClient.readContract({address:this.config.vaultContracts.btcVaultRegistry,abi:I.BTCVaultRegistryABI,functionName:"getVaultProviderCommission",args:[t]})}catch(r){throw new Error("Failed to query vault provider commission from the contract. Please check your network connection and that the contract address is correct.",{cause:r})}if(e!==void 0){if(s>e+D)throw new Error(`Vault provider commission changed since quote: quoted ${e} bps, chain currently reports ${s} bps (allowed drift ${D} bps). Please refresh to see the new commission and try again.`);return Math.min(e+D,ot)}return Math.min(s+D,ot)}async checkVaultExists(t){return(await this.config.publicClient.readContract({address:this.config.vaultContracts.btcVaultRegistry,abi:I.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[t]})).depositor!==O.zeroAddress}resolvePayoutScriptPubKey(t,e){if(!l.isAddressFromPublicKey(e,t,this.config.btcNetwork))throw l.stripHexPrefix(t).length===l.X_ONLY_PUBKEY_HEX_LEN&&Ce(e,this.config.btcNetwork)?new Error(`BTC payout address "${e}" is a P2WPKH (Native SegWit) address, but the connected wallet only exposes an x-only public key. P2WPKH validation requires a compressed key with known y-parity. Use a P2TR (Taproot) payout address instead.`):new Error(`BTC payout address "${e}" is not derived from the connected wallet's public key. The payout sink must be controlled by the same key that signs the pegin; refusing to register a mismatched address.`);const s=l.getNetwork(this.config.btcNetwork);try{return`0x${wt.address.toOutputScript(e,s).toString("hex")}`}catch{throw new Error(`Invalid BTC payout address: "${e}". Please provide a valid Bitcoin address for the ${this.config.btcNetwork} network.`)}}async signProofOfPossession(){if(!this.config.ethWallet.account)throw new Error("Ethereum wallet account not found");const t=this.config.ethWallet.account.address,e=M(await this.config.btcWallet.getPublicKeyHex()),s=this.config.vaultContracts.btcVaultRegistry,r=`${t.toLowerCase()}:${this.config.ethChain.id}:pegin:${s.toLowerCase()}`,o=await this.config.btcWallet.signMessage(r,"bip322-simple");return{btcPopSignature:ve(o),depositorEthAddress:t,depositorBtcPubkey:e}}async assertPopMatchesBtcWallet(t){const e=await this.config.btcWallet.getPublicKeyHex(),s=M(e),r=M(t.depositorBtcPubkey);if(s!==r)throw new Error(`Proof of possession was signed with BTC pubkey ${r} but the BTC wallet is currently connected to ${s}. Reconnect the original wallet or call signProofOfPossession() again.`);return e}getNetwork(){return this.config.btcNetwork}getVaultContractAddress(){return this.config.vaultContracts.btcVaultRegistry}}const Oe=80,$e=250,Ue=300,Ve=22,Wt="ab";function Me(n,t){const e=Wt.repeat(Ue),s=l.stripHexPrefix(n).toLowerCase(),r=t.toString(16).padStart(8,"0"),o=`${s}${r}`,i=e.slice(o.length);return`0x${o}${i}`}function Ne(n,t){const e=s=>`0x${Wt.repeat(s)}`;return{depositorBtcPubKey:e(32),btcPopSignature:e(Oe),unsignedPrePeginTx:e($e),depositorSignedPeginTx:Me(n,t),hashlock:e(32),htlcVout:t,referralCode:Ft,depositorPayoutBtcAddress:e(Ve),depositorWotsPkHash:e(32)}}async function Fe(n){const{publicClient:t,btcVaultRegistry:e,depositorEthAddress:s,vaultProvider:r,batchSize:o}=n;if(o<=0)throw new Error(`estimateSubmitPeginRequestBatchGas requires batchSize >= 1 (received ${o})`);const a=await t.readContract({address:e,abi:I.BTCVaultRegistryABI,functionName:"getPegInFee",args:[r]})*BigInt(o),c=Array.from({length:o},(u,P)=>Ne(s,P)),h=O.encodeFunctionData({abi:I.BTCVaultRegistryABI,functionName:"submitPeginRequestBatch",args:[s,r,ot,c]});return t.estimateGas({to:e,data:h,value:a,account:s})}exports.PeginManager=Re;exports.VAULT_APP_NAME=Et;exports.buildFundingOutpointsCommitment=kt;exports.buildVaultContext=Tt;exports.computeWotsBlockPublicKeysHash=Nt;exports.deriveVaultRoot=_t;exports.deriveWotsBlocksFromSeed=Mt;exports.estimateSubmitPeginRequestBatchGas=Fe;
2
+ //# sourceMappingURL=PeginManager-BOuzU8Zo.cjs.map