@babylonlabs-io/ts-sdk 0.67.0 → 0.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/PeginManager--2R3T2S8.js +1458 -0
- package/dist/PeginManager--2R3T2S8.js.map +1 -0
- package/dist/PeginManager-CKWq8ouZ.cjs +2 -0
- package/dist/PeginManager-CKWq8ouZ.cjs.map +1 -0
- package/dist/{batchPoll-cIxrSLLJ.js → batchPoll-Cjj1du0i.js} +372 -421
- package/dist/batchPoll-Cjj1du0i.js.map +1 -0
- package/dist/batchPoll-REVZiE-M.cjs +2 -0
- package/dist/batchPoll-REVZiE-M.cjs.map +1 -0
- package/dist/{bitcoin-d9eaaZB_.js → bitcoin-Ch_jxnDa.js} +3 -3
- package/dist/{bitcoin-d9eaaZB_.js.map → bitcoin-Ch_jxnDa.js.map} +1 -1
- package/dist/{buildAndBroadcastRefund-C4LiPATK.js → buildAndBroadcastRefund-CpMDJ8up.js} +142 -150
- package/dist/buildAndBroadcastRefund-CpMDJ8up.js.map +1 -0
- package/dist/buildAndBroadcastRefund-DrXwxrW1.cjs +2 -0
- package/dist/buildAndBroadcastRefund-DrXwxrW1.cjs.map +1 -0
- package/dist/challengeAssert-BNQ8sToz.js +64 -0
- package/dist/challengeAssert-BNQ8sToz.js.map +1 -0
- package/dist/challengeAssert-BrpC3-cQ.cjs +2 -0
- package/dist/challengeAssert-BrpC3-cQ.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +246 -243
- package/dist/mempoolApi-EU1La9wk.cjs +2 -0
- package/dist/{mempoolApi-CXfr-L6x.cjs.map → mempoolApi-EU1La9wk.cjs.map} +1 -1
- package/dist/{mempoolApi-BxSINXIB.js → mempoolApi-_D-jvtj_.js} +191 -117
- package/dist/{mempoolApi-BxSINXIB.js.map → mempoolApi-_D-jvtj_.js.map} +1 -1
- package/dist/{noPayout-BaZGRLD2.js → noPayout-CXn-geIS.js} +3 -3
- package/dist/{noPayout-BaZGRLD2.js.map → noPayout-CXn-geIS.js.map} +1 -1
- package/dist/{noPayout-CnQ1WLtr.cjs → noPayout-Ox27Td9x.cjs} +2 -2
- package/dist/{noPayout-CnQ1WLtr.cjs.map → noPayout-Ox27Td9x.cjs.map} +1 -1
- package/dist/{onChainBtcPubkey-DeF4cKoO.js → onChainBtcPubkey-BAHZyKQL.js} +2 -2
- package/dist/{onChainBtcPubkey-DeF4cKoO.js.map → onChainBtcPubkey-BAHZyKQL.js.map} +1 -1
- package/dist/{parseFundingOutpoints-pBRE11Hr.js → parseFundingOutpoints-CO-f6IHK.js} +2 -2
- package/dist/{parseFundingOutpoints-pBRE11Hr.js.map → parseFundingOutpoints-CO-f6IHK.js.map} +1 -1
- package/dist/{reservation-B4i_PQhY.js → reservation-CBAvoF3U.js} +2 -2
- package/dist/{reservation-B4i_PQhY.js.map → reservation-CBAvoF3U.js.map} +1 -1
- package/dist/{signPsbtsWithFallback-Bb66DfY5.js → signPsbtsWithFallback-Bv79gLFe.js} +122 -100
- package/dist/signPsbtsWithFallback-Bv79gLFe.js.map +1 -0
- package/dist/signPsbtsWithFallback-DJ4kE9UI.cjs +2 -0
- package/dist/signPsbtsWithFallback-DJ4kE9UI.cjs.map +1 -0
- package/dist/tbv/core/clients/index.cjs +1 -1
- package/dist/tbv/core/clients/index.js +3 -3
- package/dist/tbv/core/clients/vault-provider/auth/__tests__/bip322P2wpkhVectors.d.ts +32 -0
- package/dist/tbv/core/clients/vault-provider/auth/__tests__/bip322P2wpkhVectors.d.ts.map +1 -0
- package/dist/tbv/core/clients/vault-provider/auth/__tests__/bip322Verify.test.d.ts +9 -6
- package/dist/tbv/core/clients/vault-provider/auth/__tests__/bip322Verify.test.d.ts.map +1 -1
- package/dist/tbv/core/clients/vault-provider/auth/bip322Verify.d.ts +45 -20
- package/dist/tbv/core/clients/vault-provider/auth/bip322Verify.d.ts.map +1 -1
- package/dist/tbv/core/deposit-terms/__tests__/depositTerms.test.d.ts +2 -0
- package/dist/tbv/core/deposit-terms/__tests__/depositTerms.test.d.ts.map +1 -0
- package/dist/tbv/core/deposit-terms/depositTerms.d.ts +41 -4
- package/dist/tbv/core/deposit-terms/depositTerms.d.ts.map +1 -1
- package/dist/tbv/core/deposit-terms/prePeginApproval.d.ts +10 -5
- package/dist/tbv/core/deposit-terms/prePeginApproval.d.ts.map +1 -1
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.js +244 -241
- package/dist/tbv/core/managers/PayoutManager.d.ts +8 -2
- package/dist/tbv/core/managers/PayoutManager.d.ts.map +1 -1
- package/dist/tbv/core/managers/PeginManager.d.ts +7 -0
- package/dist/tbv/core/managers/PeginManager.d.ts.map +1 -1
- package/dist/tbv/core/managers/index.cjs +1 -1
- package/dist/tbv/core/managers/index.js +2 -2
- package/dist/tbv/core/managers/pegin/__tests__/verifyPopWitness.test.d.ts +11 -0
- package/dist/tbv/core/managers/pegin/__tests__/verifyPopWitness.test.d.ts.map +1 -0
- package/dist/tbv/core/managers/pegin/expandPerVaultSecrets.d.ts.map +1 -1
- package/dist/tbv/core/managers/pegin/index.d.ts +1 -0
- package/dist/tbv/core/managers/pegin/index.d.ts.map +1 -1
- package/dist/tbv/core/managers/pegin/verifyPopWitness.d.ts +21 -0
- package/dist/tbv/core/managers/pegin/verifyPopWitness.d.ts.map +1 -0
- package/dist/tbv/core/primitives/challengers.d.ts +31 -5
- package/dist/tbv/core/primitives/challengers.d.ts.map +1 -1
- package/dist/tbv/core/primitives/index.cjs +1 -1
- package/dist/tbv/core/primitives/index.d.ts +2 -0
- package/dist/tbv/core/primitives/index.d.ts.map +1 -1
- package/dist/tbv/core/primitives/index.js +43 -41
- package/dist/tbv/core/primitives/psbt/__tests__/helpers.d.ts +5 -0
- package/dist/tbv/core/primitives/psbt/__tests__/helpers.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/__tests__/verifyKeyPathSchnorrSignature.test.d.ts +12 -0
- package/dist/tbv/core/primitives/psbt/__tests__/verifyKeyPathSchnorrSignature.test.d.ts.map +1 -0
- package/dist/tbv/core/primitives/psbt/payout.d.ts +19 -7
- package/dist/tbv/core/primitives/psbt/payout.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/verifyKeyPathSchnorrSignature.d.ts +64 -0
- package/dist/tbv/core/primitives/psbt/verifyKeyPathSchnorrSignature.d.ts.map +1 -0
- package/dist/tbv/core/primitives/psbt/verifyP2wpkhEcdsaSignature.d.ts +40 -0
- package/dist/tbv/core/primitives/psbt/verifyP2wpkhEcdsaSignature.d.ts.map +1 -0
- package/dist/tbv/core/primitives/psbt/verifyScriptPathSchnorrSignature.d.ts +2 -1
- package/dist/tbv/core/primitives/psbt/verifyScriptPathSchnorrSignature.d.ts.map +1 -1
- package/dist/tbv/core/primitives/utils/__tests__/taproot.test.d.ts +13 -0
- package/dist/tbv/core/primitives/utils/__tests__/taproot.test.d.ts.map +1 -0
- package/dist/tbv/core/primitives/utils/taproot.d.ts +29 -0
- package/dist/tbv/core/primitives/utils/taproot.d.ts.map +1 -0
- package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts +2 -2
- package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts.map +1 -1
- package/dist/tbv/core/services/index.cjs +1 -1
- package/dist/tbv/core/services/index.js +2 -2
- package/dist/tbv/core/utils/index.js +2 -2
- package/dist/tbv/core/utils/witness/witnessStack.d.ts +24 -0
- package/dist/tbv/core/utils/witness/witnessStack.d.ts.map +1 -0
- package/dist/tbv/core/vault-secrets/index.js +1 -1
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +244 -241
- package/dist/testing/MockBitcoinWallet.d.ts +10 -1
- package/dist/testing/MockBitcoinWallet.d.ts.map +1 -1
- package/dist/testing/__tests__/MockBitcoinWallet.test.d.ts +2 -0
- package/dist/testing/__tests__/MockBitcoinWallet.test.d.ts.map +1 -0
- package/dist/testing/index.cjs +1 -1
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.js +134 -47
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/signBip322P2wpkhWitness.d.ts +20 -0
- package/dist/testing/signBip322P2wpkhWitness.d.ts.map +1 -0
- package/dist/{toRefundInputs-BY_fcvrv.js → toRefundInputs-9hv_6k0E.js} +6 -6
- package/dist/{toRefundInputs-BY_fcvrv.js.map → toRefundInputs-9hv_6k0E.js.map} +1 -1
- package/dist/{toRefundInputs-DYL9C-aG.cjs → toRefundInputs-D8sFs44p.cjs} +2 -2
- package/dist/{toRefundInputs-DYL9C-aG.cjs.map → toRefundInputs-D8sFs44p.cjs.map} +1 -1
- package/dist/verifyKeyPathSchnorrSignature-DCOzQkDf.cjs +2 -0
- package/dist/verifyKeyPathSchnorrSignature-DCOzQkDf.cjs.map +1 -0
- package/dist/verifyKeyPathSchnorrSignature-oGCUbjjZ.js +363 -0
- package/dist/verifyKeyPathSchnorrSignature-oGCUbjjZ.js.map +1 -0
- package/dist/verifyScriptPathSchnorrSignature-Dy9gF5RF.js +931 -0
- package/dist/verifyScriptPathSchnorrSignature-Dy9gF5RF.js.map +1 -0
- package/dist/verifyScriptPathSchnorrSignature-la8XOAFm.cjs +2 -0
- package/dist/verifyScriptPathSchnorrSignature-la8XOAFm.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/PeginManager-BBl4xkWz.js +0 -1359
- package/dist/PeginManager-BBl4xkWz.js.map +0 -1
- package/dist/PeginManager-p-ajwSxG.cjs +0 -2
- package/dist/PeginManager-p-ajwSxG.cjs.map +0 -1
- package/dist/batchPoll-6L5oToGr.cjs +0 -2
- package/dist/batchPoll-6L5oToGr.cjs.map +0 -1
- package/dist/batchPoll-cIxrSLLJ.js.map +0 -1
- package/dist/buildAndBroadcastRefund-C4LiPATK.js.map +0 -1
- package/dist/buildAndBroadcastRefund-Daw5ZUKR.cjs +0 -2
- package/dist/buildAndBroadcastRefund-Daw5ZUKR.cjs.map +0 -1
- package/dist/challengeAssert-BFRE2DM-.cjs +0 -2
- package/dist/challengeAssert-BFRE2DM-.cjs.map +0 -1
- package/dist/challengeAssert-C7PzyJ7g.js +0 -75
- package/dist/challengeAssert-C7PzyJ7g.js.map +0 -1
- package/dist/mempoolApi-CXfr-L6x.cjs +0 -2
- package/dist/peginInput-Ci921gTl.cjs +0 -2
- package/dist/peginInput-Ci921gTl.cjs.map +0 -1
- package/dist/peginInput-HQPWZfly.js +0 -123
- package/dist/peginInput-HQPWZfly.js.map +0 -1
- package/dist/signPsbtsWithFallback-Bb66DfY5.js.map +0 -1
- package/dist/signPsbtsWithFallback-PTgWxsG3.cjs +0 -2
- package/dist/signPsbtsWithFallback-PTgWxsG3.cjs.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-DPAd_qke.cjs +0 -2
- package/dist/verifyScriptPathSchnorrSignature-DPAd_qke.cjs.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-i-koT139.js +0 -817
- package/dist/verifyScriptPathSchnorrSignature-i-koT139.js.map +0 -1
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const a=require("./BTCVaultRegistry.abi-z7d_eP22.cjs"),w=require("./BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs"),I=require("./onChainBtcPubkey-C_a2L3kL.cjs"),k=require("./constants-DU5CGcqO.cjs"),u=require("./validation-CDbOaDj7.cjs"),g=65535,b=1e4,f=4294967295,P=255;function E(e){if(!Number.isInteger(e)||e<0||e>f)throw new Error(`Invalid offchainParamsVersion from contract: must be a uint32, got ${e}`)}function C(e){const t=[];if(e.timelockAssert<=0n&&t.push(`timelockAssert must be positive, got ${e.timelockAssert}`),e.timelockAssert>BigInt(g)&&t.push(`timelockAssert ${e.timelockAssert} exceeds uint16 max (${g})`),e.timelockChallengeAssert<=0n&&t.push(`timelockChallengeAssert must be positive, got ${e.timelockChallengeAssert}`),e.tRefund<=0&&t.push(`tRefund must be positive, got ${e.tRefund}`),e.tStale<=0&&t.push(`tStale must be positive, got ${e.tStale}`),e.securityCouncilKeys.length===0&&t.push("securityCouncilKeys must not be empty"),e.councilQuorum<=0&&t.push(`councilQuorum must be positive, got ${e.councilQuorum}`),e.councilQuorum>e.securityCouncilKeys.length&&t.push(`councilQuorum (${e.councilQuorum}) exceeds securityCouncilKeys count (${e.securityCouncilKeys.length})`),e.feeRate<=0n&&t.push(`feeRate must be positive, got ${e.feeRate}`),e.minPeginFeeRate<=0n&&t.push(`minPeginFeeRate must be positive, got ${e.minPeginFeeRate}`),(!Number.isInteger(e.proverCircuitVersion)||e.proverCircuitVersion<0||e.proverCircuitVersion>g)&&t.push(`proverCircuitVersion must be a uint16, got ${e.proverCircuitVersion}`),(!Number.isInteger(e.minPrepeginDepth)||e.minPrepeginDepth<=0||e.minPrepeginDepth>f)&&t.push(`minPrepeginDepth must be a uint32 in [1, ${f}], got ${e.minPrepeginDepth}`),e.babeTotalInstances<=0&&t.push(`babeTotalInstances must be positive, got ${e.babeTotalInstances}`),e.babeInstancesToFinalize<=0&&t.push(`babeInstancesToFinalize must be positive, got ${e.babeInstancesToFinalize}`),e.babeInstancesToFinalize>e.babeTotalInstances&&t.push(`babeInstancesToFinalize (${e.babeInstancesToFinalize}) exceeds babeTotalInstances (${e.babeTotalInstances})`),(e.minVpCommissionBps<0||e.minVpCommissionBps>b)&&t.push(`minVpCommissionBps must be in [0, ${b}], got ${e.minVpCommissionBps}`),t.length>0)throw new Error(`Invalid offchain protocol parameters: ${t.join("; ")}`)}function B(e){const t=[];if(e.minimumPegInAmount<=0n&&t.push(`minimumPegInAmount must be positive, got ${e.minimumPegInAmount}`),e.maxPegInAmount<e.minimumPegInAmount&&t.push(`maxPegInAmount (${e.maxPegInAmount}) must be >= minimumPegInAmount (${e.minimumPegInAmount})`),e.pegInAckTimeout<=0n&&t.push(`pegInAckTimeout must be positive, got ${e.pegInAckTimeout}`),e.pegInActivationTimeout<=0n&&t.push(`pegInActivationTimeout must be positive, got ${e.pegInActivationTimeout}`),(!Number.isInteger(e.maxHtlcOutputCount)||e.maxHtlcOutputCount<=0||e.maxHtlcOutputCount>P)&&t.push(`maxHtlcOutputCount must be an integer in [1, ${P}], got ${e.maxHtlcOutputCount}`),(typeof e.expiredPegInGraceBlocks!="bigint"||e.expiredPegInGraceBlocks<=0n)&&t.push(`expiredPegInGraceBlocks must be a positive bigint, got ${e.expiredPegInGraceBlocks}`),t.length>0)throw new Error(`Invalid TBV protocol parameters: ${t.join("; ")}`)}function N(e){if(B(e),C(e.offchainParams),!Number.isInteger(e.offchainParamsVersion)||e.offchainParamsVersion<0||e.offchainParamsVersion>f)throw new Error(`Invalid peg-in configuration: offchainParamsVersion must be a uint32, got ${e.offchainParamsVersion}`);k.assertValidVaultCoreVersion(e.activeVaultCoreVersion,"ProtocolParams.activeVaultCoreVersion()")}const $=9999;function y(e){return{depositor:e.depositor,depositorBtcPubKey:e.depositorBtcPubKey,amount:e.amount,vaultProvider:e.vaultProvider,status:e.status,applicationEntryPoint:e.applicationEntryPoint,createdAt:e.createdAt}}function m(e){const t=Number(e.offchainParamsVersion);return E(t),{depositorSignedPeginTx:e.depositorSignedPeginTx,universalChallengersVersion:e.universalChallengersVersion,appVaultKeepersVersion:e.appVaultKeepersVersion,offchainParamsVersion:t,verifiedAt:e.verifiedAt,depositorWotsPkHash:e.depositorWotsPkHash,hashlock:e.hashlock,htlcVout:e.htlcVout,depositorPopSignature:e.depositorPopSignature,prePeginTxHash:e.prePeginTxHash,vaultProviderCommissionBps:e.vaultProviderCommissionBps,claimExpiredUntil:e.claimExpiredUntil,vaultCoreVersion:e.vaultCoreVersion}}const S=1n<<64n,V=0n;function p(e,t,o){if(e<0n||e>=S)throw new Error(`getBtcVaultProtocolInfo returned ${t}=${e} for vault ${o}, outside the uint64 range — the registry may predate RFC-006`);return e}function T(e,t){return{vpKeyEpoch:p(e.vpKeyEpoch,"vpKeyEpoch",t),appKeeperKeyEpoch:p(e.appKeeperKeyEpoch,"appKeeperKeyEpoch",t),ucKeyEpoch:p(e.ucKeyEpoch,"ucKeyEpoch",t)}}class _{constructor(t,o){this.publicClient=t,this.contractAddress=o}async getVaultProviderGenesisBtcPubKey(t){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getOperationBtcKeyAtEpoch",args:[t,V]});return I.assertOnChainBtcPubkey(o,`getOperationBtcKeyAtEpoch (vp=${t}, epoch=${V})`)}async getCurrentVaultProviderOperationBtcKey(t){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getCurrentOperationBtcKey",args:[t]});return I.assertOnChainBtcPubkey(o,`getCurrentOperationBtcKey (vp=${t})`)}async getVaultKeyEpochs(t){const o=await this.publicClient.readContract({address:this.contractAddress,abi:w.BTCVaultRegistryKeyEpochsABI,functionName:"getBtcVaultProtocolInfo",args:[t]});return T(o,t)}async getVaultKeyEpochsBatch(t){return t.length===0?[]:(await this.publicClient.multicall({contracts:t.map(n=>({address:this.contractAddress,abi:w.BTCVaultRegistryKeyEpochsABI,functionName:"getBtcVaultProtocolInfo",args:[n]})),allowFailure:!1})).map((n,i)=>T(n,t[i]))}async getVaultBasicInfo(t){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[t]});return y(o)}async getVaultProtocolInfo(t){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[t]});return m(o)}async getProtocolInfoBatch(t){return t.length===0?[]:(await this.publicClient.multicall({contracts:t.map(n=>({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[n]})),allowFailure:!1})).map((n,i)=>{const r=n;if(!r.depositorSignedPeginTx||r.depositorSignedPeginTx==="0x")throw new Error(`Vault ${t[i]} not found on-chain or has no pegin transaction`);return m(r)})}async getPegInFee(t){return await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getPegInFee",args:[t]})}async getVaultProviderCommission(t){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getVaultProviderCommission",args:[t]});if(!Number.isInteger(o)||o<0||o>$)throw new Error(`getVaultProviderCommission returned ${o} bps for ${t}, outside the protocol range [0, ${$}]`);return o}async getVaultData(t){const[o,n]=await this.publicClient.multicall({contracts:[{address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[t]},{address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[t]}],allowFailure:!1}),i=y(o),r=m(n);if(!r.depositorSignedPeginTx||r.depositorSignedPeginTx==="0x")throw new Error(`Vault ${t} not found on-chain or has no pegin transaction`);return{basic:i,protocol:r}}}const U=21e6*1e8,A=3e4;async function h(e,t){const o=new AbortController,n=setTimeout(()=>o.abort(),A),i=[o.signal,t==null?void 0:t.signal].filter(Boolean),r=u.combineAbortSignals(i);try{return await fetch(e,{...t,signal:r.signal})}catch(s){throw clearTimeout(n),r.cleanup(),s!=null&&typeof s=="object"&&"name"in s&&s.name==="AbortError"?new Error(`Mempool API request timed out after ${A}ms: ${e}`):s}}const v=1e4;function x(e){return Number.isInteger(e)&&e>0&&e<=U}function M(e){return Number.isInteger(e)&&e>0&&e<=v}function d(e,t){return!Number.isInteger(e)||e<0?!1:t===void 0||e<t}function l(e){if(!u.TXID_RE.test(e))throw new Error(`Invalid transaction ID format: ${e}`)}function F(e){if(!u.BITCOIN_ADDRESS_RE.test(e))throw new Error(`Invalid Bitcoin address format: ${e}`)}function K(e,t){if(!u.HEX_RE.test(e))throw new Error(`Invalid scriptPubKey: not valid hex for ${t}`);if(!u.KNOWN_SCRIPT_PREFIXES.some(n=>e.toLowerCase().startsWith(n)))throw new Error(`Unrecognized scriptPubKey type for ${t}: prefix ${e.slice(0,6)} does not match any known Bitcoin script type`)}const R={mainnet:"https://mempool.space/api",testnet:"https://mempool.space/testnet/api",signet:"https://mempool.space/signet/api"};async function c(e,t){try{const o=await h(e,t);if(!o.ok){const i=await o.text();throw new Error(`Mempool API error (${o.status}): ${i||o.statusText}`)}const n=o.headers.get("content-type");return n!=null&&n.includes("application/json")?await o.json():await o.text()}catch(o){throw o instanceof Error?new Error(`Failed to fetch from mempool API: ${o.message}`):new Error("Failed to fetch from mempool API: Unknown error")}}async function H(e,t){try{const o=await h(`${t}/tx`,{method:"POST",body:e,headers:{"Content-Type":"text/plain"}});if(!o.ok){const i=await o.text();let r;try{const s=JSON.parse(i);r=s.message??s.error}catch{r=i}throw new Error(r||`Failed to broadcast transaction: ${o.statusText}`)}return await o.text()}catch(o){throw o instanceof Error?new Error(`Failed to broadcast BTC transaction: ${o.message}`):new Error("Failed to broadcast BTC transaction: Unknown error")}}async function O(e,t){return l(e),c(`${t}/tx/${e}`)}async function X(e){const t=await c(`${e}/blocks/tip/height`),o=t.trim();if(!/^\d+$/.test(o))throw new Error(`Mempool API returned an invalid block tip height: "${t}"`);return Number.parseInt(o,10)}async function D(e,t,o){if(l(e),!d(t))throw new Error(`Invalid vout ${t} for transaction ${e}`);return c(`${o}/tx/${e}/outspend/${t}`)}async function z(e,t){l(e);try{const o=await h(`${t}/tx/${e}/hex`);if(!o.ok){const n=await o.text();throw new Error(`Mempool API error (${o.status}): ${n||o.statusText}`)}return await o.text()}catch(o){throw o instanceof Error?new Error(`Failed to get transaction hex for ${e}: ${o.message}`):new Error(`Failed to get transaction hex for ${e}: Unknown error`)}}async function L(e,t,o){l(e);const n=await O(e,o);if(!d(t,n.vout.length))throw new Error(`Invalid vout ${t} for transaction ${e} (has ${n.vout.length} outputs)`);const i=n.vout[t];if(!x(i.value))throw new Error(`Invalid UTXO value ${i.value} for ${e}:${t}`);return K(i.scriptpubkey,`${e}:${t}`),{txid:e,vout:t,value:i.value,scriptPubKey:i.scriptpubkey}}async function Q(e,t){F(e);try{const o=await c(`${t}/address/${e}/utxo`),n=await c(`${t}/v1/validate-address/${e}`);if(!n.isvalid)throw new Error(`Invalid Bitcoin address: ${e}. Mempool API validation failed.`);K(n.scriptPubKey,e);for(const r of o){if(l(r.txid),!d(r.vout))throw new Error(`Invalid vout ${r.vout} for ${r.txid}`);if(!x(r.value))throw new Error(`Invalid UTXO value ${r.value} for ${r.txid}:${r.vout}`)}return o.sort((r,s)=>s.value-r.value).map(r=>({txid:r.txid,vout:r.vout,value:r.value,scriptPubKey:n.scriptPubKey,confirmed:r.status.confirmed}))}catch(o){throw o instanceof Error?new Error(`Failed to get UTXOs for address ${e}: ${o.message}`):new Error(`Failed to get UTXOs for address ${e}: Unknown error`)}}function j(e){return R[e]}async function q(e,t){return F(e),c(`${t}/address/${e}/txs`)}async function G(e){const t=await h(`${e}/v1/fees/recommended`);if(!t.ok)throw new Error(`Failed to fetch network fees: ${t.status} ${t.statusText}`);const o=await t.json(),n=["fastestFee","halfHourFee","hourFee","economyFee","minimumFee"];for(const i of n)if(!M(o[i]))throw new Error(`Invalid fee rate ${i}=${o[i]} from mempool API: expected a positive number ≤ ${v}`);if(o.minimumFee>o.economyFee||o.economyFee>o.hourFee||o.hourFee>o.halfHourFee||o.halfHourFee>o.fastestFee)throw new Error(`Fee rate ordering violation from mempool API: expected minimumFee (${o.minimumFee}) <= economyFee (${o.economyFee}) <= hourFee (${o.hourFee}) <= halfHourFee (${o.halfHourFee}) <= fastestFee (${o.fastestFee}).`);return o}exports.MEMPOOL_API_URLS=R;exports.ViemVaultRegistryReader=_;exports.assertValidOffchainParamsVersion=E;exports.getAddressTxs=q;exports.getAddressUtxos=Q;exports.getMempoolApiUrl=j;exports.getNetworkFees=G;exports.getOutspend=D;exports.getTipHeight=X;exports.getTxHex=z;exports.getTxInfo=O;exports.getUtxoInfo=L;exports.pushTx=H;exports.validateOffchainParams=C;exports.validatePegInConfiguration=N;exports.validateTBVProtocolParams=B;
|
|
2
|
-
//# sourceMappingURL=mempoolApi-CXfr-L6x.cjs.map
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const h=require("@babylonlabs-io/babylon-tbv-rust-wasm"),a=require("bitcoinjs-lib"),o=require("buffer"),t=require("./bitcoin-m84N5a8o.cjs");async function I(e){var x;const i=t.stripHexPrefix(e.peginTxHex),l=t.stripHexPrefix(e.fundedPrePeginTxHex),n=await h.getPrePeginHtlcConnectorInfo({txGraphVersion:e.vaultCoreVersion,depositorPubkey:e.depositorPubkey,vaultProviderPubkey:e.vaultProviderPubkey,vaultKeeperPubkeys:e.vaultKeeperPubkeys,universalChallengerPubkeys:e.universalChallengerPubkeys,hashlock:e.hashlock,timelockRefund:e.timelockRefund,network:e.network}),r=a.Transaction.fromHex(i),s=a.Transaction.fromHex(l);if(r.ins.length!==1)throw new Error(`PegIn transaction must have exactly 1 input, got ${r.ins.length}`);const u=r.ins[0],P=s.getId(),g=t.uint8ArrayToHex(new Uint8Array(u.hash).slice().reverse());if(g!==P)throw new Error(`PegIn input does not reference the Pre-PegIn transaction. Expected ${P}, got ${g}`);const p=s.outs[u.index];if(!p)throw new Error(`Pre-PegIn output ${u.index} not found (Pre-PegIn has ${s.outs.length} outputs)`);const d=t.hexToUint8Array(n.hashlockScript),b=t.hexToUint8Array(n.hashlockControlBlock);t.assertEccInitialized();const f=a.payments.p2tr({internalPubkey:o.Buffer.from(h.tapInternalPubkey),scriptTree:[{output:o.Buffer.from(d),version:t.TAPSCRIPT_LEAF_VERSION},{output:o.Buffer.from(t.hexToUint8Array(n.refundScript)),version:t.TAPSCRIPT_LEAF_VERSION}]});if(!((x=f.output)!=null&&x.equals(p.script))||!f.hash)throw new Error("PegIn HTLC taptree mismatch: the recomputed 2-leaf tree does not reproduce the funded Pre-PegIn HTLC scriptPubKey; refusing to sign.");const c=new a.Psbt;c.setVersion(r.version),c.setLocktime(r.locktime),c.addInput({hash:u.hash,index:u.index,sequence:u.sequence,witnessUtxo:{script:p.script,value:p.value},tapLeafScript:[{leafVersion:t.TAPSCRIPT_LEAF_VERSION,script:o.Buffer.from(d),controlBlock:o.Buffer.from(b)}],tapInternalKey:o.Buffer.from(h.tapInternalPubkey),tapMerkleRoot:f.hash});for(const S of r.outs)c.addOutput({script:S.script,value:S.value});return{psbtHex:c.toHex()}}function y(e,i){const n=a.Psbt.fromHex(e).data.inputs[0];if(!n)throw new Error("PegIn PSBT has no inputs");if(n.tapScriptSig&&n.tapScriptSig.length>0){const r=o.Buffer.from(t.hexToUint8Array(i));for(const s of n.tapScriptSig)if(s.pubkey.equals(r))return w(s.signature);throw new Error(`No PegIn input signature found for depositor pubkey: ${i}`)}throw n.finalScriptWitness&&n.finalScriptWitness.length>0?new Error("PegIn input PSBT is already finalized. Cannot reliably extract the depositor signature from the witness stack. Ensure the wallet returns a non-finalized PSBT with tapScriptSig entries."):new Error("No tapScriptSig or finalScriptWitness found in signed PegIn input PSBT")}function T(e){const i=a.Psbt.fromHex(e);try{i.finalizeAllInputs()}catch(l){if(!i.data.inputs.every(r=>r.finalScriptWitness||r.finalScriptSig))throw new Error(`PSBT finalization failed and wallet did not auto-finalize: ${l}`)}return i.extractTransaction().toHex()}function w(e){if(e.length===64)return t.uint8ArrayToHex(new Uint8Array(e));throw e.length===65?new Error(`Unexpected sighash byte 0x${e[64].toString(16).padStart(2,"0")} in PegIn input signature. Expected implicit SIGHASH_DEFAULT as a 64-byte signature.`):new Error(`Unexpected PegIn input signature length: ${e.length}`)}exports.buildPeginInputPsbt=I;exports.extractPeginInputSignature=y;exports.finalizePeginInputPsbt=T;
|
|
2
|
-
//# sourceMappingURL=peginInput-Ci921gTl.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"peginInput-Ci921gTl.cjs","sources":["../src/tbv/core/primitives/psbt/peginInput.ts"],"sourcesContent":["/**\n * PegIn Input PSBT Builder\n *\n * Builds the PSBT for the depositor to sign the PegIn transaction's HTLC input\n * (Pre-PegIn HTLC leaf 0 — the hashlock + all-party script).\n *\n * This is the \"Sign Pegin transaction HTLC leaf 0 input\" step in the pre-pegin\n * flow. The depositor signs input 0 of the PegIn transaction,\n * which spends output 0 of the funded Pre-PegIn transaction via script-path.\n *\n * @module primitives/psbt/peginInput\n */\n\nimport {\n getPrePeginHtlcConnectorInfo,\n tapInternalPubkey,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Psbt, Transaction, payments } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\nimport {\n TAPSCRIPT_LEAF_VERSION,\n assertEccInitialized,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building the PegIn input PSBT\n */\nexport interface BuildPeginInputPsbtParams {\n /**\n * Vault core (tx-graph) version the Pre-PegIn was built with. Must match\n * the version passed to buildPrePeginPsbt() so the HTLC connector scripts\n * are derived for the same graph.\n */\n vaultCoreVersion: number;\n /**\n * PegIn transaction hex (1 input spending Pre-PegIn HTLC output 0).\n * Returned by buildPeginTxFromFundedPrePegin().\n */\n peginTxHex: string;\n /**\n * Funded Pre-PegIn transaction hex.\n * Used to look up the HTLC output that the PegIn input spends.\n */\n fundedPrePeginTxHex: string;\n /** Depositor's BTC public key (x-only, 64-char hex) */\n depositorPubkey: string;\n /** Vault provider's BTC public key (x-only, 64-char hex) */\n vaultProviderPubkey: string;\n /** Vault keeper BTC public keys (x-only, 64-char hex) */\n vaultKeeperPubkeys: string[];\n /** Universal challenger BTC public keys (x-only, 64-char hex) */\n universalChallengerPubkeys: string[];\n /** SHA256 hash commitment (64 hex chars = 32 bytes) */\n hashlock: string;\n /** CSV timelock in blocks for the HTLC refund path */\n timelockRefund: number;\n /** Bitcoin network */\n network: Network;\n}\n\n/**\n * Result of building the PegIn input PSBT\n */\nexport interface BuildPeginInputPsbtResult {\n /** PSBT hex for the depositor to sign */\n psbtHex: string;\n}\n\n/**\n * Build PSBT for depositor to sign the PegIn transaction's HTLC leaf 0 input.\n *\n * The PegIn transaction spends the Pre-PegIn HTLC output (output 0) via the\n * hashlock + all-party script (leaf 0). The depositor provides one of the required\n * signatures; the vault provider and keepers provide theirs separately via the\n * signPeginInput RPC.\n *\n * The PSBT uses Taproot script-path spending:\n * - witnessUtxo: the Pre-PegIn HTLC output\n * - tapLeafScript: hashlock leaf script + control block\n * - tapInternalKey: NUMS unspendable key (BIP-341 nothing-up-my-sleeve)\n *\n * @param params - PegIn input PSBT parameters\n * @returns PSBT hex ready for depositor signing\n * @throws If PegIn tx does not have exactly 1 input\n * @throws If PegIn input does not reference the Pre-PegIn HTLC output\n * @throws If Pre-PegIn tx output 0 is not found\n */\nexport async function buildPeginInputPsbt(\n params: BuildPeginInputPsbtParams,\n): Promise<BuildPeginInputPsbtResult> {\n const peginTxHex = stripHexPrefix(params.peginTxHex);\n const fundedPrePeginTxHex = stripHexPrefix(params.fundedPrePeginTxHex);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: params.vaultCoreVersion,\n depositorPubkey: params.depositorPubkey,\n vaultProviderPubkey: params.vaultProviderPubkey,\n vaultKeeperPubkeys: params.vaultKeeperPubkeys,\n universalChallengerPubkeys: params.universalChallengerPubkeys,\n hashlock: params.hashlock,\n timelockRefund: params.timelockRefund,\n network: params.network,\n });\n\n const peginTx = Transaction.fromHex(peginTxHex);\n const prePeginTx = Transaction.fromHex(fundedPrePeginTxHex);\n\n if (peginTx.ins.length !== 1) {\n throw new Error(\n `PegIn transaction must have exactly 1 input, got ${peginTx.ins.length}`,\n );\n }\n\n const peginInput = peginTx.ins[0];\n\n // Verify PegIn input 0 spends Pre-PegIn output 0\n const prePeginTxid = prePeginTx.getId();\n const peginInputTxid = uint8ArrayToHex(\n new Uint8Array(peginInput.hash).slice().reverse(),\n );\n\n if (peginInputTxid !== prePeginTxid) {\n throw new Error(\n `PegIn input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${peginInputTxid}`,\n );\n }\n\n const htlcOutput = prePeginTx.outs[peginInput.index];\n if (!htlcOutput) {\n throw new Error(\n `Pre-PegIn output ${peginInput.index} not found ` +\n `(Pre-PegIn has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const hashlockScript = hexToUint8Array(htlcConnector.hashlockScript);\n const hashlockControlBlock = hexToUint8Array(\n htlcConnector.hashlockControlBlock,\n );\n\n // Merkle root recomputed from the two connector leaves — inert for extension\n // wallets, byte-compared by hardware that recomputes it. The closed loop\n // below (derived P2TR == the funded HTLC spk) is what makes it trustworthy.\n assertEccInitialized();\n const htlcTaptree = payments.p2tr({\n internalPubkey: Buffer.from(tapInternalPubkey),\n scriptTree: [\n { output: Buffer.from(hashlockScript), version: TAPSCRIPT_LEAF_VERSION },\n {\n output: Buffer.from(hexToUint8Array(htlcConnector.refundScript)),\n version: TAPSCRIPT_LEAF_VERSION,\n },\n ],\n });\n if (!htlcTaptree.output?.equals(htlcOutput.script) || !htlcTaptree.hash) {\n throw new Error(\n \"PegIn HTLC taptree mismatch: the recomputed 2-leaf tree does not \" +\n \"reproduce the funded Pre-PegIn HTLC scriptPubKey; refusing to sign.\",\n );\n }\n\n const psbt = new Psbt();\n psbt.setVersion(peginTx.version);\n psbt.setLocktime(peginTx.locktime);\n\n // Input 0: PegIn input spending Pre-PegIn HTLC output 0 via hashlock leaf (leaf 0).\n // The depositor signs using Taproot script-path spending. bitcoinjs\n // re-verifies leaf-in-tree consistency (control block vs tapMerkleRoot)\n // inside addInput — a second independent check.\n psbt.addInput({\n hash: peginInput.hash,\n index: peginInput.index,\n sequence: peginInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hashlockScript),\n controlBlock: Buffer.from(hashlockControlBlock),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n tapMerkleRoot: htlcTaptree.hash,\n // sighashType omitted — defaults to SIGHASH_DEFAULT (0x00) for Taproot\n });\n\n for (const output of peginTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return { psbtHex: psbt.toHex() };\n}\n\n/**\n * Extract the depositor's Schnorr signature from a signed PegIn input PSBT.\n *\n * Supports non-finalized PSBTs with tapScriptSig entries. Finalized PSBTs are\n * rejected because the witness stack does not reliably identify the depositor\n * signature by public key.\n *\n * PegIn input signatures must use implicit Taproot SIGHASH_DEFAULT, which is\n * encoded by omitting the sighash byte. Signatures with an appended sighash byte\n * are rejected rather than stripped.\n *\n * @param signedPsbtHex - Signed PSBT hex\n * @param depositorPubkey - Depositor's x-only public key (64-char hex)\n * @returns 64-byte Schnorr signature (128 hex chars, no sighash flag)\n * @throws If no signature is found for the depositor's key\n */\nexport function extractPeginInputSignature(\n signedPsbtHex: string,\n depositorPubkey: string,\n): string {\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n const input = signedPsbt.data.inputs[0];\n\n if (!input) {\n throw new Error(\"PegIn PSBT has no inputs\");\n }\n\n // Non-finalized PSBT — extract from tapScriptSig\n if (input.tapScriptSig && input.tapScriptSig.length > 0) {\n const depositorPubkeyBytes = Buffer.from(hexToUint8Array(depositorPubkey));\n\n for (const sigEntry of input.tapScriptSig) {\n if (sigEntry.pubkey.equals(depositorPubkeyBytes)) {\n return extractSchnorrSig(sigEntry.signature);\n }\n }\n\n throw new Error(\n `No PegIn input signature found for depositor pubkey: ${depositorPubkey}`,\n );\n }\n\n // Finalized PSBT — the witness stack order depends on the wallet's finalizer,\n // so we cannot reliably pick the depositor's signature by position. Require\n // the non-finalized tapScriptSig path which identifies signatures by pubkey.\n if (input.finalScriptWitness && input.finalScriptWitness.length > 0) {\n throw new Error(\n \"PegIn input PSBT is already finalized. Cannot reliably extract the \" +\n \"depositor signature from the witness stack. Ensure the wallet returns \" +\n \"a non-finalized PSBT with tapScriptSig entries.\",\n );\n }\n\n throw new Error(\n \"No tapScriptSig or finalScriptWitness found in signed PegIn input PSBT\",\n );\n}\n\n/**\n * Finalize a signed PegIn input PSBT and return the depositor-signed transaction hex.\n *\n * The default tapscript finalizer builds the full witness stack [sig, script, controlBlock]\n * that vaultd requires when verifying the depositor signature on-chain.\n *\n * @param signedPsbtHex - Non-finalized signed PSBT hex (returned by wallet with autoFinalized: false)\n * @returns Depositor-signed PegIn transaction hex with full taproot witness stack\n */\nexport function finalizePeginInputPsbt(signedPsbtHex: string): string {\n const psbt = Psbt.fromHex(signedPsbtHex);\n\n // Some wallets (UniSat, OKX) ignore autoFinalized: false and return\n // already-finalized PSBTs. finalizeAllInputs() throws in that case,\n // so fall back to verifying the wallet already finalized all inputs.\n try {\n psbt.finalizeAllInputs();\n } catch (e) {\n const allFinalized = psbt.data.inputs.every(\n (inp) => inp.finalScriptWitness || inp.finalScriptSig,\n );\n if (!allFinalized) {\n throw new Error(\n `PSBT finalization failed and wallet did not auto-finalize: ${e}`,\n );\n }\n }\n\n return psbt.extractTransaction().toHex();\n}\n\n/**\n * Extract and validate a 64-byte Schnorr signature.\n * PegIn input signatures must use implicit Taproot SIGHASH_DEFAULT, which is\n * encoded by omitting the sighash byte. Reject 65-byte signatures instead of\n * stripping the sighash byte because it changes the signed Taproot message.\n * @internal\n */\nexport function extractSchnorrSig(sig: Uint8Array): string {\n if (sig.length === 64) {\n return uint8ArrayToHex(new Uint8Array(sig));\n }\n if (sig.length === 65) {\n throw new Error(\n `Unexpected sighash byte 0x${sig[64].toString(16).padStart(2, \"0\")} in PegIn input signature. ` +\n \"Expected implicit SIGHASH_DEFAULT as a 64-byte signature.\",\n );\n }\n throw new Error(`Unexpected PegIn input signature length: ${sig.length}`);\n}\n"],"names":["buildPeginInputPsbt","params","peginTxHex","stripHexPrefix","fundedPrePeginTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","peginTx","Transaction","prePeginTx","peginInput","prePeginTxid","peginInputTxid","uint8ArrayToHex","htlcOutput","hashlockScript","hexToUint8Array","hashlockControlBlock","assertEccInitialized","htlcTaptree","payments","Buffer","tapInternalPubkey","TAPSCRIPT_LEAF_VERSION","_a","psbt","Psbt","output","extractPeginInputSignature","signedPsbtHex","depositorPubkey","input","depositorPubkeyBytes","sigEntry","extractSchnorrSig","finalizePeginInputPsbt","e","inp","sig"],"mappings":"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"}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { getPrePeginHtlcConnectorInfo as T, tapInternalPubkey as w } from "@babylonlabs-io/babylon-tbv-rust-wasm";
|
|
2
|
-
import { Transaction as k, payments as m, Psbt as h } from "bitcoinjs-lib";
|
|
3
|
-
import { Buffer as i } from "buffer";
|
|
4
|
-
import { s as y, u as I, h as l, l as v, T as f } from "./bitcoin-d9eaaZB_.js";
|
|
5
|
-
async function A(t) {
|
|
6
|
-
var x;
|
|
7
|
-
const r = y(t.peginTxHex), u = y(t.fundedPrePeginTxHex), e = await T({
|
|
8
|
-
txGraphVersion: t.vaultCoreVersion,
|
|
9
|
-
depositorPubkey: t.depositorPubkey,
|
|
10
|
-
vaultProviderPubkey: t.vaultProviderPubkey,
|
|
11
|
-
vaultKeeperPubkeys: t.vaultKeeperPubkeys,
|
|
12
|
-
universalChallengerPubkeys: t.universalChallengerPubkeys,
|
|
13
|
-
hashlock: t.hashlock,
|
|
14
|
-
timelockRefund: t.timelockRefund,
|
|
15
|
-
network: t.network
|
|
16
|
-
}), n = k.fromHex(r), o = k.fromHex(u);
|
|
17
|
-
if (n.ins.length !== 1)
|
|
18
|
-
throw new Error(
|
|
19
|
-
`PegIn transaction must have exactly 1 input, got ${n.ins.length}`
|
|
20
|
-
);
|
|
21
|
-
const s = n.ins[0], g = o.getId(), d = I(
|
|
22
|
-
new Uint8Array(s.hash).slice().reverse()
|
|
23
|
-
);
|
|
24
|
-
if (d !== g)
|
|
25
|
-
throw new Error(
|
|
26
|
-
`PegIn input does not reference the Pre-PegIn transaction. Expected ${g}, got ${d}`
|
|
27
|
-
);
|
|
28
|
-
const c = o.outs[s.index];
|
|
29
|
-
if (!c)
|
|
30
|
-
throw new Error(
|
|
31
|
-
`Pre-PegIn output ${s.index} not found (Pre-PegIn has ${o.outs.length} outputs)`
|
|
32
|
-
);
|
|
33
|
-
const P = l(e.hashlockScript), b = l(
|
|
34
|
-
e.hashlockControlBlock
|
|
35
|
-
);
|
|
36
|
-
v();
|
|
37
|
-
const p = m.p2tr({
|
|
38
|
-
internalPubkey: i.from(w),
|
|
39
|
-
scriptTree: [
|
|
40
|
-
{ output: i.from(P), version: f },
|
|
41
|
-
{
|
|
42
|
-
output: i.from(l(e.refundScript)),
|
|
43
|
-
version: f
|
|
44
|
-
}
|
|
45
|
-
]
|
|
46
|
-
});
|
|
47
|
-
if (!((x = p.output) != null && x.equals(c.script)) || !p.hash)
|
|
48
|
-
throw new Error(
|
|
49
|
-
"PegIn HTLC taptree mismatch: the recomputed 2-leaf tree does not reproduce the funded Pre-PegIn HTLC scriptPubKey; refusing to sign."
|
|
50
|
-
);
|
|
51
|
-
const a = new h();
|
|
52
|
-
a.setVersion(n.version), a.setLocktime(n.locktime), a.addInput({
|
|
53
|
-
hash: s.hash,
|
|
54
|
-
index: s.index,
|
|
55
|
-
sequence: s.sequence,
|
|
56
|
-
witnessUtxo: {
|
|
57
|
-
script: c.script,
|
|
58
|
-
value: c.value
|
|
59
|
-
},
|
|
60
|
-
tapLeafScript: [
|
|
61
|
-
{
|
|
62
|
-
leafVersion: f,
|
|
63
|
-
script: i.from(P),
|
|
64
|
-
controlBlock: i.from(b)
|
|
65
|
-
}
|
|
66
|
-
],
|
|
67
|
-
tapInternalKey: i.from(w),
|
|
68
|
-
tapMerkleRoot: p.hash
|
|
69
|
-
// sighashType omitted — defaults to SIGHASH_DEFAULT (0x00) for Taproot
|
|
70
|
-
});
|
|
71
|
-
for (const S of n.outs)
|
|
72
|
-
a.addOutput({
|
|
73
|
-
script: S.script,
|
|
74
|
-
value: S.value
|
|
75
|
-
});
|
|
76
|
-
return { psbtHex: a.toHex() };
|
|
77
|
-
}
|
|
78
|
-
function $(t, r) {
|
|
79
|
-
const e = h.fromHex(t).data.inputs[0];
|
|
80
|
-
if (!e)
|
|
81
|
-
throw new Error("PegIn PSBT has no inputs");
|
|
82
|
-
if (e.tapScriptSig && e.tapScriptSig.length > 0) {
|
|
83
|
-
const n = i.from(l(r));
|
|
84
|
-
for (const o of e.tapScriptSig)
|
|
85
|
-
if (o.pubkey.equals(n))
|
|
86
|
-
return E(o.signature);
|
|
87
|
-
throw new Error(
|
|
88
|
-
`No PegIn input signature found for depositor pubkey: ${r}`
|
|
89
|
-
);
|
|
90
|
-
}
|
|
91
|
-
throw e.finalScriptWitness && e.finalScriptWitness.length > 0 ? new Error(
|
|
92
|
-
"PegIn input PSBT is already finalized. Cannot reliably extract the depositor signature from the witness stack. Ensure the wallet returns a non-finalized PSBT with tapScriptSig entries."
|
|
93
|
-
) : new Error(
|
|
94
|
-
"No tapScriptSig or finalScriptWitness found in signed PegIn input PSBT"
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
function U(t) {
|
|
98
|
-
const r = h.fromHex(t);
|
|
99
|
-
try {
|
|
100
|
-
r.finalizeAllInputs();
|
|
101
|
-
} catch (u) {
|
|
102
|
-
if (!r.data.inputs.every(
|
|
103
|
-
(n) => n.finalScriptWitness || n.finalScriptSig
|
|
104
|
-
))
|
|
105
|
-
throw new Error(
|
|
106
|
-
`PSBT finalization failed and wallet did not auto-finalize: ${u}`
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
return r.extractTransaction().toHex();
|
|
110
|
-
}
|
|
111
|
-
function E(t) {
|
|
112
|
-
if (t.length === 64)
|
|
113
|
-
return I(new Uint8Array(t));
|
|
114
|
-
throw t.length === 65 ? new Error(
|
|
115
|
-
`Unexpected sighash byte 0x${t[64].toString(16).padStart(2, "0")} in PegIn input signature. Expected implicit SIGHASH_DEFAULT as a 64-byte signature.`
|
|
116
|
-
) : new Error(`Unexpected PegIn input signature length: ${t.length}`);
|
|
117
|
-
}
|
|
118
|
-
export {
|
|
119
|
-
A as b,
|
|
120
|
-
$ as e,
|
|
121
|
-
U as f
|
|
122
|
-
};
|
|
123
|
-
//# sourceMappingURL=peginInput-HQPWZfly.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"peginInput-HQPWZfly.js","sources":["../src/tbv/core/primitives/psbt/peginInput.ts"],"sourcesContent":["/**\n * PegIn Input PSBT Builder\n *\n * Builds the PSBT for the depositor to sign the PegIn transaction's HTLC input\n * (Pre-PegIn HTLC leaf 0 — the hashlock + all-party script).\n *\n * This is the \"Sign Pegin transaction HTLC leaf 0 input\" step in the pre-pegin\n * flow. The depositor signs input 0 of the PegIn transaction,\n * which spends output 0 of the funded Pre-PegIn transaction via script-path.\n *\n * @module primitives/psbt/peginInput\n */\n\nimport {\n getPrePeginHtlcConnectorInfo,\n tapInternalPubkey,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Psbt, Transaction, payments } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\nimport {\n TAPSCRIPT_LEAF_VERSION,\n assertEccInitialized,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building the PegIn input PSBT\n */\nexport interface BuildPeginInputPsbtParams {\n /**\n * Vault core (tx-graph) version the Pre-PegIn was built with. Must match\n * the version passed to buildPrePeginPsbt() so the HTLC connector scripts\n * are derived for the same graph.\n */\n vaultCoreVersion: number;\n /**\n * PegIn transaction hex (1 input spending Pre-PegIn HTLC output 0).\n * Returned by buildPeginTxFromFundedPrePegin().\n */\n peginTxHex: string;\n /**\n * Funded Pre-PegIn transaction hex.\n * Used to look up the HTLC output that the PegIn input spends.\n */\n fundedPrePeginTxHex: string;\n /** Depositor's BTC public key (x-only, 64-char hex) */\n depositorPubkey: string;\n /** Vault provider's BTC public key (x-only, 64-char hex) */\n vaultProviderPubkey: string;\n /** Vault keeper BTC public keys (x-only, 64-char hex) */\n vaultKeeperPubkeys: string[];\n /** Universal challenger BTC public keys (x-only, 64-char hex) */\n universalChallengerPubkeys: string[];\n /** SHA256 hash commitment (64 hex chars = 32 bytes) */\n hashlock: string;\n /** CSV timelock in blocks for the HTLC refund path */\n timelockRefund: number;\n /** Bitcoin network */\n network: Network;\n}\n\n/**\n * Result of building the PegIn input PSBT\n */\nexport interface BuildPeginInputPsbtResult {\n /** PSBT hex for the depositor to sign */\n psbtHex: string;\n}\n\n/**\n * Build PSBT for depositor to sign the PegIn transaction's HTLC leaf 0 input.\n *\n * The PegIn transaction spends the Pre-PegIn HTLC output (output 0) via the\n * hashlock + all-party script (leaf 0). The depositor provides one of the required\n * signatures; the vault provider and keepers provide theirs separately via the\n * signPeginInput RPC.\n *\n * The PSBT uses Taproot script-path spending:\n * - witnessUtxo: the Pre-PegIn HTLC output\n * - tapLeafScript: hashlock leaf script + control block\n * - tapInternalKey: NUMS unspendable key (BIP-341 nothing-up-my-sleeve)\n *\n * @param params - PegIn input PSBT parameters\n * @returns PSBT hex ready for depositor signing\n * @throws If PegIn tx does not have exactly 1 input\n * @throws If PegIn input does not reference the Pre-PegIn HTLC output\n * @throws If Pre-PegIn tx output 0 is not found\n */\nexport async function buildPeginInputPsbt(\n params: BuildPeginInputPsbtParams,\n): Promise<BuildPeginInputPsbtResult> {\n const peginTxHex = stripHexPrefix(params.peginTxHex);\n const fundedPrePeginTxHex = stripHexPrefix(params.fundedPrePeginTxHex);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: params.vaultCoreVersion,\n depositorPubkey: params.depositorPubkey,\n vaultProviderPubkey: params.vaultProviderPubkey,\n vaultKeeperPubkeys: params.vaultKeeperPubkeys,\n universalChallengerPubkeys: params.universalChallengerPubkeys,\n hashlock: params.hashlock,\n timelockRefund: params.timelockRefund,\n network: params.network,\n });\n\n const peginTx = Transaction.fromHex(peginTxHex);\n const prePeginTx = Transaction.fromHex(fundedPrePeginTxHex);\n\n if (peginTx.ins.length !== 1) {\n throw new Error(\n `PegIn transaction must have exactly 1 input, got ${peginTx.ins.length}`,\n );\n }\n\n const peginInput = peginTx.ins[0];\n\n // Verify PegIn input 0 spends Pre-PegIn output 0\n const prePeginTxid = prePeginTx.getId();\n const peginInputTxid = uint8ArrayToHex(\n new Uint8Array(peginInput.hash).slice().reverse(),\n );\n\n if (peginInputTxid !== prePeginTxid) {\n throw new Error(\n `PegIn input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${peginInputTxid}`,\n );\n }\n\n const htlcOutput = prePeginTx.outs[peginInput.index];\n if (!htlcOutput) {\n throw new Error(\n `Pre-PegIn output ${peginInput.index} not found ` +\n `(Pre-PegIn has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const hashlockScript = hexToUint8Array(htlcConnector.hashlockScript);\n const hashlockControlBlock = hexToUint8Array(\n htlcConnector.hashlockControlBlock,\n );\n\n // Merkle root recomputed from the two connector leaves — inert for extension\n // wallets, byte-compared by hardware that recomputes it. The closed loop\n // below (derived P2TR == the funded HTLC spk) is what makes it trustworthy.\n assertEccInitialized();\n const htlcTaptree = payments.p2tr({\n internalPubkey: Buffer.from(tapInternalPubkey),\n scriptTree: [\n { output: Buffer.from(hashlockScript), version: TAPSCRIPT_LEAF_VERSION },\n {\n output: Buffer.from(hexToUint8Array(htlcConnector.refundScript)),\n version: TAPSCRIPT_LEAF_VERSION,\n },\n ],\n });\n if (!htlcTaptree.output?.equals(htlcOutput.script) || !htlcTaptree.hash) {\n throw new Error(\n \"PegIn HTLC taptree mismatch: the recomputed 2-leaf tree does not \" +\n \"reproduce the funded Pre-PegIn HTLC scriptPubKey; refusing to sign.\",\n );\n }\n\n const psbt = new Psbt();\n psbt.setVersion(peginTx.version);\n psbt.setLocktime(peginTx.locktime);\n\n // Input 0: PegIn input spending Pre-PegIn HTLC output 0 via hashlock leaf (leaf 0).\n // The depositor signs using Taproot script-path spending. bitcoinjs\n // re-verifies leaf-in-tree consistency (control block vs tapMerkleRoot)\n // inside addInput — a second independent check.\n psbt.addInput({\n hash: peginInput.hash,\n index: peginInput.index,\n sequence: peginInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hashlockScript),\n controlBlock: Buffer.from(hashlockControlBlock),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n tapMerkleRoot: htlcTaptree.hash,\n // sighashType omitted — defaults to SIGHASH_DEFAULT (0x00) for Taproot\n });\n\n for (const output of peginTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return { psbtHex: psbt.toHex() };\n}\n\n/**\n * Extract the depositor's Schnorr signature from a signed PegIn input PSBT.\n *\n * Supports non-finalized PSBTs with tapScriptSig entries. Finalized PSBTs are\n * rejected because the witness stack does not reliably identify the depositor\n * signature by public key.\n *\n * PegIn input signatures must use implicit Taproot SIGHASH_DEFAULT, which is\n * encoded by omitting the sighash byte. Signatures with an appended sighash byte\n * are rejected rather than stripped.\n *\n * @param signedPsbtHex - Signed PSBT hex\n * @param depositorPubkey - Depositor's x-only public key (64-char hex)\n * @returns 64-byte Schnorr signature (128 hex chars, no sighash flag)\n * @throws If no signature is found for the depositor's key\n */\nexport function extractPeginInputSignature(\n signedPsbtHex: string,\n depositorPubkey: string,\n): string {\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n const input = signedPsbt.data.inputs[0];\n\n if (!input) {\n throw new Error(\"PegIn PSBT has no inputs\");\n }\n\n // Non-finalized PSBT — extract from tapScriptSig\n if (input.tapScriptSig && input.tapScriptSig.length > 0) {\n const depositorPubkeyBytes = Buffer.from(hexToUint8Array(depositorPubkey));\n\n for (const sigEntry of input.tapScriptSig) {\n if (sigEntry.pubkey.equals(depositorPubkeyBytes)) {\n return extractSchnorrSig(sigEntry.signature);\n }\n }\n\n throw new Error(\n `No PegIn input signature found for depositor pubkey: ${depositorPubkey}`,\n );\n }\n\n // Finalized PSBT — the witness stack order depends on the wallet's finalizer,\n // so we cannot reliably pick the depositor's signature by position. Require\n // the non-finalized tapScriptSig path which identifies signatures by pubkey.\n if (input.finalScriptWitness && input.finalScriptWitness.length > 0) {\n throw new Error(\n \"PegIn input PSBT is already finalized. Cannot reliably extract the \" +\n \"depositor signature from the witness stack. Ensure the wallet returns \" +\n \"a non-finalized PSBT with tapScriptSig entries.\",\n );\n }\n\n throw new Error(\n \"No tapScriptSig or finalScriptWitness found in signed PegIn input PSBT\",\n );\n}\n\n/**\n * Finalize a signed PegIn input PSBT and return the depositor-signed transaction hex.\n *\n * The default tapscript finalizer builds the full witness stack [sig, script, controlBlock]\n * that vaultd requires when verifying the depositor signature on-chain.\n *\n * @param signedPsbtHex - Non-finalized signed PSBT hex (returned by wallet with autoFinalized: false)\n * @returns Depositor-signed PegIn transaction hex with full taproot witness stack\n */\nexport function finalizePeginInputPsbt(signedPsbtHex: string): string {\n const psbt = Psbt.fromHex(signedPsbtHex);\n\n // Some wallets (UniSat, OKX) ignore autoFinalized: false and return\n // already-finalized PSBTs. finalizeAllInputs() throws in that case,\n // so fall back to verifying the wallet already finalized all inputs.\n try {\n psbt.finalizeAllInputs();\n } catch (e) {\n const allFinalized = psbt.data.inputs.every(\n (inp) => inp.finalScriptWitness || inp.finalScriptSig,\n );\n if (!allFinalized) {\n throw new Error(\n `PSBT finalization failed and wallet did not auto-finalize: ${e}`,\n );\n }\n }\n\n return psbt.extractTransaction().toHex();\n}\n\n/**\n * Extract and validate a 64-byte Schnorr signature.\n * PegIn input signatures must use implicit Taproot SIGHASH_DEFAULT, which is\n * encoded by omitting the sighash byte. Reject 65-byte signatures instead of\n * stripping the sighash byte because it changes the signed Taproot message.\n * @internal\n */\nexport function extractSchnorrSig(sig: Uint8Array): string {\n if (sig.length === 64) {\n return uint8ArrayToHex(new Uint8Array(sig));\n }\n if (sig.length === 65) {\n throw new Error(\n `Unexpected sighash byte 0x${sig[64].toString(16).padStart(2, \"0\")} in PegIn input signature. ` +\n \"Expected implicit SIGHASH_DEFAULT as a 64-byte signature.\",\n );\n }\n throw new Error(`Unexpected PegIn input signature length: ${sig.length}`);\n}\n"],"names":["buildPeginInputPsbt","params","peginTxHex","stripHexPrefix","fundedPrePeginTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","peginTx","Transaction","prePeginTx","peginInput","prePeginTxid","peginInputTxid","uint8ArrayToHex","htlcOutput","hashlockScript","hexToUint8Array","hashlockControlBlock","assertEccInitialized","htlcTaptree","payments","Buffer","tapInternalPubkey","TAPSCRIPT_LEAF_VERSION","_a","psbt","Psbt","output","extractPeginInputSignature","signedPsbtHex","depositorPubkey","input","depositorPubkeyBytes","sigEntry","extractSchnorrSig","finalizePeginInputPsbt","e","inp","sig"],"mappings":";;;;AA2FA,eAAsBA,EACpBC,GACoC;;AACpC,QAAMC,IAAaC,EAAeF,EAAO,UAAU,GAC7CG,IAAsBD,EAAeF,EAAO,mBAAmB,GAE/DI,IAAgB,MAAMC,EAA6B;AAAA,IACvD,gBAAgBL,EAAO;AAAA,IACvB,iBAAiBA,EAAO;AAAA,IACxB,qBAAqBA,EAAO;AAAA,IAC5B,oBAAoBA,EAAO;AAAA,IAC3B,4BAA4BA,EAAO;AAAA,IACnC,UAAUA,EAAO;AAAA,IACjB,gBAAgBA,EAAO;AAAA,IACvB,SAASA,EAAO;AAAA,EAAA,CACjB,GAEKM,IAAUC,EAAY,QAAQN,CAAU,GACxCO,IAAaD,EAAY,QAAQJ,CAAmB;AAE1D,MAAIG,EAAQ,IAAI,WAAW;AACzB,UAAM,IAAI;AAAA,MACR,oDAAoDA,EAAQ,IAAI,MAAM;AAAA,IAAA;AAI1E,QAAMG,IAAaH,EAAQ,IAAI,CAAC,GAG1BI,IAAeF,EAAW,MAAA,GAC1BG,IAAiBC;AAAA,IACrB,IAAI,WAAWH,EAAW,IAAI,EAAE,MAAA,EAAQ,QAAA;AAAA,EAAQ;AAGlD,MAAIE,MAAmBD;AACrB,UAAM,IAAI;AAAA,MACR,sEACcA,CAAY,SAASC,CAAc;AAAA,IAAA;AAIrD,QAAME,IAAaL,EAAW,KAAKC,EAAW,KAAK;AACnD,MAAI,CAACI;AACH,UAAM,IAAI;AAAA,MACR,oBAAoBJ,EAAW,KAAK,6BAChBD,EAAW,KAAK,MAAM;AAAA,IAAA;AAI9C,QAAMM,IAAiBC,EAAgBX,EAAc,cAAc,GAC7DY,IAAuBD;AAAA,IAC3BX,EAAc;AAAA,EAAA;AAMhB,EAAAa,EAAA;AACA,QAAMC,IAAcC,EAAS,KAAK;AAAA,IAChC,gBAAgBC,EAAO,KAAKC,CAAiB;AAAA,IAC7C,YAAY;AAAA,MACV,EAAE,QAAQD,EAAO,KAAKN,CAAc,GAAG,SAASQ,EAAA;AAAA,MAChD;AAAA,QACE,QAAQF,EAAO,KAAKL,EAAgBX,EAAc,YAAY,CAAC;AAAA,QAC/D,SAASkB;AAAA,MAAA;AAAA,IACX;AAAA,EACF,CACD;AACD,MAAI,GAACC,IAAAL,EAAY,WAAZ,QAAAK,EAAoB,OAAOV,EAAW,YAAW,CAACK,EAAY;AACjE,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAKJ,QAAMM,IAAO,IAAIC,EAAA;AACjB,EAAAD,EAAK,WAAWlB,EAAQ,OAAO,GAC/BkB,EAAK,YAAYlB,EAAQ,QAAQ,GAMjCkB,EAAK,SAAS;AAAA,IACZ,MAAMf,EAAW;AAAA,IACjB,OAAOA,EAAW;AAAA,IAClB,UAAUA,EAAW;AAAA,IACrB,aAAa;AAAA,MACX,QAAQI,EAAW;AAAA,MACnB,OAAOA,EAAW;AAAA,IAAA;AAAA,IAEpB,eAAe;AAAA,MACb;AAAA,QACE,aAAaS;AAAA,QACb,QAAQF,EAAO,KAAKN,CAAc;AAAA,QAClC,cAAcM,EAAO,KAAKJ,CAAoB;AAAA,MAAA;AAAA,IAChD;AAAA,IAEF,gBAAgBI,EAAO,KAAKC,CAAiB;AAAA,IAC7C,eAAeH,EAAY;AAAA;AAAA,EAAA,CAE5B;AAED,aAAWQ,KAAUpB,EAAQ;AAC3B,IAAAkB,EAAK,UAAU;AAAA,MACb,QAAQE,EAAO;AAAA,MACf,OAAOA,EAAO;AAAA,IAAA,CACf;AAGH,SAAO,EAAE,SAASF,EAAK,QAAM;AAC/B;AAkBO,SAASG,EACdC,GACAC,GACQ;AAER,QAAMC,IADaL,EAAK,QAAQG,CAAa,EACpB,KAAK,OAAO,CAAC;AAEtC,MAAI,CAACE;AACH,UAAM,IAAI,MAAM,0BAA0B;AAI5C,MAAIA,EAAM,gBAAgBA,EAAM,aAAa,SAAS,GAAG;AACvD,UAAMC,IAAuBX,EAAO,KAAKL,EAAgBc,CAAe,CAAC;AAEzE,eAAWG,KAAYF,EAAM;AAC3B,UAAIE,EAAS,OAAO,OAAOD,CAAoB;AAC7C,eAAOE,EAAkBD,EAAS,SAAS;AAI/C,UAAM,IAAI;AAAA,MACR,wDAAwDH,CAAe;AAAA,IAAA;AAAA,EAE3E;AAKA,QAAIC,EAAM,sBAAsBA,EAAM,mBAAmB,SAAS,IAC1D,IAAI;AAAA,IACR;AAAA,EAAA,IAME,IAAI;AAAA,IACR;AAAA,EAAA;AAEJ;AAWO,SAASI,EAAuBN,GAA+B;AACpE,QAAMJ,IAAOC,EAAK,QAAQG,CAAa;AAKvC,MAAI;AACF,IAAAJ,EAAK,kBAAA;AAAA,EACP,SAASW,GAAG;AAIV,QAAI,CAHiBX,EAAK,KAAK,OAAO;AAAA,MACpC,CAACY,MAAQA,EAAI,sBAAsBA,EAAI;AAAA,IAAA;AAGvC,YAAM,IAAI;AAAA,QACR,8DAA8DD,CAAC;AAAA,MAAA;AAAA,EAGrE;AAEA,SAAOX,EAAK,mBAAA,EAAqB,MAAA;AACnC;AASO,SAASS,EAAkBI,GAAyB;AACzD,MAAIA,EAAI,WAAW;AACjB,WAAOzB,EAAgB,IAAI,WAAWyB,CAAG,CAAC;AAE5C,QAAIA,EAAI,WAAW,KACX,IAAI;AAAA,IACR,6BAA6BA,EAAI,EAAE,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,EAAA,IAIhE,IAAI,MAAM,4CAA4CA,EAAI,MAAM,EAAE;AAC1E;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signPsbtsWithFallback-Bb66DfY5.js","sources":["../src/tbv/core/managers/pegin/assertAuthAnchorOpReturn.ts","../src/tbv/core/services/htlc/index.ts","../src/tbv/core/deposit-terms/depositTerms.ts","../src/tbv/core/managers/PayoutManager.ts","../src/tbv/core/managers/pegin/signPsbtsWithFallback.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","import type { BitcoinWallet } from \"../../../shared/wallets/interfaces\";\n\n// Field docs use /** */ so they survive into the emitted .d.ts — the published\n// package is the only contract the external provider author (#2109) sees.\n\nexport interface DepositTermsVaultGroup {\n /** 0-based; equals the group's position (groups are ascending by vout). */\n readonly htlcVout: number;\n /** x-only hex (64 chars), as validated on-chain upstream. */\n readonly vaultProviderBtcPubkey: string;\n /** sats */\n readonly peginAmount: bigint;\n /**\n * sats; the MAXIMUM commission the depositor accepts —\n * floor(peginAmount * maxAcceptableCommissionBps / 10_000), the same\n * ceiling the registration calldata carries. An approving wallet MUST\n * enforce the VP payout commission output `<= commissionFee` (e.g. the\n * Ledger vault app does, firmware >= c8db53e), and every commission the\n * contract admits stays under this ceiling (floor is monotonic in bps),\n * so no contract-admitted deposit can be refused at payout. The actual\n * stamped commission may be lower. Display the quoted value in UI, not this.\n */\n readonly commissionFee: bigint;\n /** sats; the same value for every vault. */\n readonly depositorClaimValue: bigint;\n /**\n * sats; the cap an approving wallet enforces on the PegIn tx fee. Equals\n * the graph's exact (minimum) PegIn fee, which is deterministic — so the\n * cap is satisfied exact-by-construction.\n */\n readonly peginMaxFee: bigint;\n}\n\n/**\n * Field names follow btc-vault vocabulary (the protocol source of truth);\n * a device-wire encoder maps them to its intent fields (e.g. the Ledger TLV:\n * protocolFeeRate -> base_fee_rate, timelockPegin -> pegin_csv_timelock,\n * timelockAssert -> payout_timelock, peginAmount -> vault_amount).\n */\nexport interface DepositTerms {\n /**\n * btc-vault tx-graph version (`vaultCoreVersion`) these terms describe —\n * the vault's stamped on-chain version for resumes, the chain's\n * `activeVaultCoreVersion` for fresh deposits. It selects the PegIn shape\n * an approving wallet must expect: v1 = 2 outputs, no anchor; v2/v3 = TRUC\n * nVersion 3, 3 outputs with a 240-sat P2A anchor at vout 2, and an\n * Assert OP_RETURN marker that raises the claim value\n * (btc-vault `transactions/pegin.rs`, `assert_marker.rs`). A provider that\n * supports only one shape MUST reject the others here rather than\n * mis-validating the PSBTs later.\n */\n vaultCoreVersion: number;\n /**\n * sat/vB; the tx-graph fee rate (protocolFeeRate), NOT the mempool funding\n * rate. Approving wallets bound each payout's fee against this rate —\n * pass the exact graph rate, not an inflated ceiling.\n */\n protocolFeeRate: bigint;\n /** Vault-UTXO CSV timelock (blocks). */\n timelockPegin: number;\n /**\n * btc-vault `timelock_assert` (t2) — the CSV on Assert output 0. Its own\n * param, though production derives it and `timelockPegin` from one value.\n */\n timelockAssert: number;\n /** HTLC refund CSV timelock (blocks). */\n timelockRefund: number;\n /**\n * 64-char hex in display order. A device-wire encoder may need the\n * little-endian form — some hardware byte-compares it against\n * PSBT_IN_PREVIOUS_TXID rather than recomputing the txid.\n */\n prepeginTxid: string;\n /** sats; the funded Pre-PegIn fee (an approving wallet caps the signed fee at this). */\n prepeginMaxFee: bigint;\n /**\n * x-only hex. Sorted ascending by the upstream on-chain validation\n * (validateOnChainParticipantKeys); the builder passes them through\n * unasserted — approving devices may reject unsorted lists at load.\n */\n vaultKeeperBtcPubkeys: readonly string[];\n /**\n * x-only hex, sorted ascending upstream independently of vaultKeeperBtcPubkeys (same\n * pass-through contract). Universal challengers only — the full graph\n * challenger set is vaultKeeperBtcPubkeys ∪ universalChallengerBtcPubkeys (vault keepers are the local\n * challengers).\n */\n universalChallengerBtcPubkeys: readonly string[];\n /** Per-vault groups, ordered by ascending htlcVout. */\n vaults: readonly DepositTermsVaultGroup[];\n}\n\n/**\n * Implemented only by depositor-approval wallets (e.g. a Ledger vault\n * provider). Provider obligations:\n *\n * - Envelope: validate terms against the device's envelope BEFORE the\n * ceremony, rejecting with the shape `{ name: \"DepositTermsRejectedError\",\n * reason: \"device-envelope\", message }` (matched structurally, not by class).\n * - Idempotence: a byte-equal re-approval MUST be a no-op while the\n * device-side approval is live; anything that invalidates it (a later\n * `deriveContextHash`, a signing failure) MUST clear the memo.\n *\n * Seam invariant: any derive invalidates a prior approval, so the SDK\n * re-approves after every derive and before the next terms-bound signature.\n * The re-approval sites are `PeginManager.preparePegin`,\n * `runDepositorPresignFlow`, and `signAndBroadcast` (the Pre-PegIn broadcast,\n * which derives immediately before approving — see `ensurePrePeginTermsApproval`).\n */\nexport interface DepositTermsApprover {\n approveDepositTerms(terms: DepositTerms): Promise<void>;\n}\n\n/** True when the wallet implements {@link DepositTermsApprover.approveDepositTerms}. */\nexport function supportsDepositApproval(\n wallet: BitcoinWallet,\n): wallet is BitcoinWallet & DepositTermsApprover {\n return (\n typeof (wallet as Partial<DepositTermsApprover>).approveDepositTerms ===\n \"function\"\n );\n}\n\n/**\n * Spreadable forward of `approveDepositTerms` for wallet-wrapper objects.\n * Object spread drops prototype methods, so every `{...wallet}` wrapper site\n * must re-attach the capability explicitly: `...forwardDepositApproval(wallet)`.\n */\nexport function forwardDepositApproval(\n wallet: BitcoinWallet,\n): Partial<DepositTermsApprover> {\n return supportsDepositApproval(wallet)\n ? { approveDepositTerms: (terms) => wallet.approveDepositTerms(terms) }\n : {};\n}\n\nexport interface BuildDepositTermsInputs {\n /** btc-vault tx-graph version the graph is built under. */\n vaultCoreVersion: number;\n protocolFeeRate: bigint;\n timelockPegin: number;\n /** btc-vault `timelock_assert` (t2) — its own param; NOT derived from timelockPegin here. */\n timelockAssert: number;\n timelockRefund: number;\n prepeginTxid: string;\n prepeginMaxFee: bigint;\n vaultProviderBtcPubkey: string;\n vaultKeeperBtcPubkeys: readonly string[];\n universalChallengerBtcPubkeys: readonly string[];\n /** Ceiling bps, not the quote — see {@link DepositTermsVaultGroup.commissionFee}. */\n maxAcceptableCommissionBps: number;\n peginAmounts: readonly bigint[];\n depositorClaimValue: bigint;\n peginMaxFee: bigint;\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 { BitcoinWallet, SignPsbtOptions } from \"../../../shared/wallets\";\nimport {\n assertPsbtUnsignedTxMatches,\n assertScriptPathSchnorrSignature,\n buildPayoutPsbt,\n extractPayoutSignature,\n validateWalletPubkey,\n type Network,\n} from \"../primitives\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\n\n/** Payout PSBTs are signed by the depositor on input 0 (Taproot script-path). */\nconst PAYOUT_SIGNED_INPUT_INDEX = 0;\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 * Vault core (tx-graph) version the vault was registered under — the\n * vault's stamped on-chain `vaultCoreVersion`. Forwarded to\n * {@link buildPayoutPsbt} to derive the matching graph's payout scripts.\n */\n vaultCoreVersion: number;\n\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 /** btc-vault `timelock_assert`; payout input 1's sequence. */\n timelockAssert: 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 * Version-locked tx-graph fee rate (sat/vB) the graph was built with.\n * Forwarded to {@link buildPayoutPsbt} for the fee band.\n */\n protocolFeeRate: bigint;\n\n /** Security council member count; forwarded to the fee floor (see PayoutParams). */\n councilSize: number;\n\n /**\n * RFC-006 resolved payout destinations, keyed by lowercased x-only operation\n * pubkey. Forwarded verbatim to {@link buildPayoutPsbt}; every VK claimer\n * must be present.\n */\n vkClaimerPayoutScriptPubKeys: Readonly<Record<string, string>>;\n /** RFC-006 VP commission destination. Forwarded to {@link buildPayoutPsbt}. */\n vpCommissionScriptPubKey: string;\n}\n\n/**\n * Parameters for signing a Payout transaction.\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface SignPayoutParams extends SignPayoutBaseParams {\n /**\n * Payout transaction hex (unsigned).\n * This is the transaction from the vault provider that needs depositor signature.\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex.\n * Payout input 1 references Assert output 0.\n */\n assertTxHex: string;\n}\n\n/**\n * Result of signing a payout transaction.\n */\nexport interface PayoutSignatureResult {\n /**\n * 64-byte Schnorr signature (128 hex characters).\n */\n signature: string;\n\n /**\n * Depositor's BTC public key used for signing.\n */\n depositorBtcPubkey: string;\n}\n\n/**\n * High-level manager for payout transaction signing.\n *\n * @remarks\n * After registering your peg-in on Ethereum (Step 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 vaultCoreVersion: params.vaultCoreVersion,\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 timelockAssert: params.timelockAssert,\n network: this.config.network,\n claimerBtcPubkey: params.claimerBtcPubkey,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n protocolFeeRate: params.protocolFeeRate,\n councilSize: params.councilSize,\n vkClaimerPayoutScriptPubKeys: params.vkClaimerPayoutScriptPubKeys,\n vpCommissionScriptPubKey: params.vpCommissionScriptPubKey,\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 // Critical Path #7: verify the signature against a sighash recomputed from\n // the PSBT we built, not the wallet-returned one.\n assertScriptPathSchnorrSignature({\n requestedPsbtHex: payoutPsbt.psbtHex,\n signatureHex: signature,\n signerXOnlyPubkeyHex: depositorPubkey,\n inputIndex: PAYOUT_SIGNED_INPUT_INDEX,\n });\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(transactions: SignPayoutParams[]): 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 vaultCoreVersion: tx.vaultCoreVersion,\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 timelockAssert: tx.timelockAssert,\n network: this.config.network,\n claimerBtcPubkey: tx.claimerBtcPubkey,\n registeredPayoutScriptPubKey: tx.registeredPayoutScriptPubKey,\n commissionBps: tx.commissionBps,\n protocolFeeRate: tx.protocolFeeRate,\n councilSize: tx.councilSize,\n vkClaimerPayoutScriptPubKeys: tx.vkClaimerPayoutScriptPubKeys,\n vpCommissionScriptPubKey: tx.vpCommissionScriptPubKey,\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 assertScriptPathSchnorrSignature({\n requestedPsbtHex: psbtsToSign[i],\n signatureHex: payoutSignature,\n signerXOnlyPubkeyHex: depositorPubkey,\n inputIndex: PAYOUT_SIGNED_INPUT_INDEX,\n });\n\n results.push({\n payoutSignature,\n depositorBtcPubkey: depositorPubkey,\n });\n }\n\n return results;\n }\n}\n","/**\n * Wallet-signing helper that routes a lone PSBT to `signPsbt`, prefers native\n * `signPsbts` for real batches, and falls back to sequential `signPsbt` for\n * wallets that don't implement batch signing.\n *\n * @module managers/pegin/signPsbtsWithFallback\n */\n\nimport type {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../../shared/wallets\";\n\n/**\n * Sign one or more PSBTs against a wallet.\n *\n * A single PSBT is always signed via `signPsbt`, never the batch endpoint: it's\n * one wallet interaction either way, and `signPsbt` is the universally-required\n * wallet method (batch `signPsbts` is optional), so single-sign is the portable\n * choice — some integrations (notably MPC / institutional wallets) prefer it.\n * For a real batch (>1), wallets exposing native `signPsbts` (e.g. UniSat) sign\n * in one interaction; others loop `signPsbt`.\n *\n * @throws If native `signPsbts` returns a different number of signed PSBTs\n * than were submitted.\n */\nexport async function signPsbtsWithFallback(\n wallet: BitcoinWallet,\n psbtsHexes: string[],\n options?: SignPsbtOptions[],\n): Promise<string[]> {\n if (psbtsHexes.length === 1) {\n return [await wallet.signPsbt(psbtsHexes[0], options?.[0])];\n }\n\n if (typeof wallet.signPsbts === \"function\") {\n const signedPsbts = await wallet.signPsbts(psbtsHexes, options);\n if (signedPsbts.length !== psbtsHexes.length) {\n throw new Error(\n `Expected ${psbtsHexes.length} signed PSBTs but received ${signedPsbts.length}`,\n );\n }\n return signedPsbts;\n }\n\n const signedPsbts: string[] = [];\n for (let i = 0; i < psbtsHexes.length; i++) {\n signedPsbts.push(await wallet.signPsbt(psbtsHexes[i], options?.[i]));\n }\n return signedPsbts;\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","supportsDepositApproval","wallet","forwardDepositApproval","terms","PAYOUT_SIGNED_INPUT_INDEX","PayoutManager","config","__publicField","params","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","signedPsbtHex","createTaprootScriptPathSignOptions","assertPsbtUnsignedTxMatches","signature","extractPayoutSignature","assertScriptPathSchnorrSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature","signPsbtsWithFallback","psbtsHexes","options"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";var H=Object.defineProperty;var m=(e,t,r)=>t in e?H(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var b=(e,t,r)=>m(e,typeof t!="symbol"?t+"":t,r);const B=require("bitcoinjs-lib"),g=require("./bitcoin-m84N5a8o.cjs"),R=require("./sha2-DsrLC4NM.cjs");require("@babylonlabs-io/babylon-tbv-rust-wasm");const u=require("./verifyScriptPathSchnorrSignature-DPAd_qke.cjs"),y=require("./signing-Bnsro0hE.cjs");function E(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const f=E(B),k=106,S=32,p=34;function O(e,t,r){const o=g.stripHexPrefix(e),s=f.Transaction.fromHex(o);if(s.outs.length<=t)throw new Error(`Pre-PegIn auth-anchor OP_RETURN missing: tx has ${s.outs.length} outputs, expected at least ${t+1} (vault outputs + OP_RETURN)`);const c=s.outs[t],i=c.script;if(i.length!==p||i[0]!==k||i[1]!==S)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 ${p}-byte OP_RETURN + PUSH32 layout)`);const l=i.slice(2).toString("hex").toLowerCase();if(l!==r.toLowerCase())throw new Error(`Pre-PegIn auth-anchor OP_RETURN payload mismatch at vout ${t}: tx pushes ${l}, expected ${r}`);if(c.value!==0)throw new Error(`Pre-PegIn auth-anchor OP_RETURN at vout ${t} has non-zero value ${c.value}; OP_RETURN outputs must be 0-value`)}function $(e){let t;try{t=f.Transaction.fromHex(g.stripHexPrefix(e))}catch{return}const r=[];for(let o=0;o<t.outs.length;o++){const s=t.outs[o],c=s.script;c.length===p&&c[0]===k&&c[1]===S&&s.value===0&&r.push({vout:o,hash:c.slice(2).toString("hex").toLowerCase()})}return r.length===1?r[0]:void 0}const x=66;function v(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 r=new Uint8Array(t.length/2);for(let o=0;o<r.length;o++)r[o]=parseInt(t.slice(o*2,o*2+2),16);return r}function _(e){return`0x${Array.from(e).map(t=>t.toString(16).padStart(2,"0")).join("")}`}function h(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 w(e){h(e,"Secret");const t=v(e),r=R.sha256(t);return _(r)}function A(e,t){return h(e,"Secret"),h(t,"Hashlock"),v(t),w(e).toLowerCase()===t.toLowerCase()}function T(e){return typeof e.approveDepositTerms=="function"}function K(e){return T(e)?{approveDepositTerms:t=>e.approveDepositTerms(t)}:{}}const d=0;class C{constructor(t){b(this,"config");this.config=t}async signPayoutTransaction(t){const r=await this.config.btcWallet.getPublicKeyHex(),{depositorPubkey:o}=g.validateWalletPubkey(r,t.depositorBtcPubkey),s=await u.buildPayoutPsbt({vaultCoreVersion:t.vaultCoreVersion,payoutTxHex:t.payoutTxHex,peginTxHex:t.peginTxHex,assertTxHex:t.assertTxHex,depositorBtcPubkey:o,vaultProviderBtcPubkey:t.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:t.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:t.universalChallengerBtcPubkeys,timelockPegin:t.timelockPegin,timelockAssert:t.timelockAssert,network:this.config.network,claimerBtcPubkey:t.claimerBtcPubkey,registeredPayoutScriptPubKey:t.registeredPayoutScriptPubKey,commissionBps:t.commissionBps,protocolFeeRate:t.protocolFeeRate,councilSize:t.councilSize,vkClaimerPayoutScriptPubKeys:t.vkClaimerPayoutScriptPubKeys,vpCommissionScriptPubKey:t.vpCommissionScriptPubKey}),c=await this.config.btcWallet.signPsbt(s.psbtHex,y.createTaprootScriptPathSignOptions(r,1));u.assertPsbtUnsignedTxMatches({requestedPsbtHex:s.psbtHex,returnedPsbtHex:c});const i=u.extractPayoutSignature(c,o);return u.assertScriptPathSchnorrSignature({requestedPsbtHex:s.psbtHex,signatureHex:i,signerXOnlyPubkeyHex:o,inputIndex:d}),{signature:i,depositorBtcPubkey:o}}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 r=await this.config.btcWallet.getPublicKeyHex(),o=[],s=[],c=[];for(const n of t){const{depositorPubkey:a}=g.validateWalletPubkey(r,n.depositorBtcPubkey);c.push(a);const P=await u.buildPayoutPsbt({vaultCoreVersion:n.vaultCoreVersion,payoutTxHex:n.payoutTxHex,peginTxHex:n.peginTxHex,assertTxHex:n.assertTxHex,depositorBtcPubkey:a,vaultProviderBtcPubkey:n.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:n.vaultKeeperBtcPubkeys,universalChallengerBtcPubkeys:n.universalChallengerBtcPubkeys,timelockPegin:n.timelockPegin,timelockAssert:n.timelockAssert,network:this.config.network,claimerBtcPubkey:n.claimerBtcPubkey,registeredPayoutScriptPubKey:n.registeredPayoutScriptPubKey,commissionBps:n.commissionBps,protocolFeeRate:n.protocolFeeRate,councilSize:n.councilSize,vkClaimerPayoutScriptPubKeys:n.vkClaimerPayoutScriptPubKeys,vpCommissionScriptPubKey:n.vpCommissionScriptPubKey});o.push(P.psbtHex),s.push(y.createTaprootScriptPathSignOptions(r,1))}const i=await this.config.btcWallet.signPsbts(o,s);if(i.length!==t.length)throw new Error(`Expected ${t.length} signed PSBTs but received ${i.length}`);const l=[];for(let n=0;n<t.length;n++){const a=c[n];u.assertPsbtUnsignedTxMatches({requestedPsbtHex:o[n],returnedPsbtHex:i[n]});const P=u.extractPayoutSignature(i[n],a);u.assertScriptPathSchnorrSignature({requestedPsbtHex:o[n],signatureHex:P,signerXOnlyPubkeyHex:a,inputIndex:d}),l.push({payoutSignature:P,depositorBtcPubkey:a})}return l}}async function U(e,t,r){if(t.length===1)return[await e.signPsbt(t[0],r==null?void 0:r[0])];if(typeof e.signPsbts=="function"){const s=await e.signPsbts(t,r);if(s.length!==t.length)throw new Error(`Expected ${t.length} signed PSBTs but received ${s.length}`);return s}const o=[];for(let s=0;s<t.length;s++)o.push(await e.signPsbt(t[s],r==null?void 0:r[s]));return o}exports.PayoutManager=C;exports.assertAuthAnchorOpReturn=O;exports.computeHashlock=w;exports.findAuthAnchorOpReturn=$;exports.forwardDepositApproval=K;exports.signPsbtsWithFallback=U;exports.supportsDepositApproval=T;exports.validateSecretAgainstHashlock=A;
|
|
2
|
-
//# sourceMappingURL=signPsbtsWithFallback-PTgWxsG3.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"signPsbtsWithFallback-PTgWxsG3.cjs","sources":["../src/tbv/core/managers/pegin/assertAuthAnchorOpReturn.ts","../src/tbv/core/services/htlc/index.ts","../src/tbv/core/deposit-terms/depositTerms.ts","../src/tbv/core/managers/PayoutManager.ts","../src/tbv/core/managers/pegin/signPsbtsWithFallback.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","import type { BitcoinWallet } from \"../../../shared/wallets/interfaces\";\n\n// Field docs use /** */ so they survive into the emitted .d.ts — the published\n// package is the only contract the external provider author (#2109) sees.\n\nexport interface DepositTermsVaultGroup {\n /** 0-based; equals the group's position (groups are ascending by vout). */\n readonly htlcVout: number;\n /** x-only hex (64 chars), as validated on-chain upstream. */\n readonly vaultProviderBtcPubkey: string;\n /** sats */\n readonly peginAmount: bigint;\n /**\n * sats; the MAXIMUM commission the depositor accepts —\n * floor(peginAmount * maxAcceptableCommissionBps / 10_000), the same\n * ceiling the registration calldata carries. An approving wallet MUST\n * enforce the VP payout commission output `<= commissionFee` (e.g. the\n * Ledger vault app does, firmware >= c8db53e), and every commission the\n * contract admits stays under this ceiling (floor is monotonic in bps),\n * so no contract-admitted deposit can be refused at payout. The actual\n * stamped commission may be lower. Display the quoted value in UI, not this.\n */\n readonly commissionFee: bigint;\n /** sats; the same value for every vault. */\n readonly depositorClaimValue: bigint;\n /**\n * sats; the cap an approving wallet enforces on the PegIn tx fee. Equals\n * the graph's exact (minimum) PegIn fee, which is deterministic — so the\n * cap is satisfied exact-by-construction.\n */\n readonly peginMaxFee: bigint;\n}\n\n/**\n * Field names follow btc-vault vocabulary (the protocol source of truth);\n * a device-wire encoder maps them to its intent fields (e.g. the Ledger TLV:\n * protocolFeeRate -> base_fee_rate, timelockPegin -> pegin_csv_timelock,\n * timelockAssert -> payout_timelock, peginAmount -> vault_amount).\n */\nexport interface DepositTerms {\n /**\n * btc-vault tx-graph version (`vaultCoreVersion`) these terms describe —\n * the vault's stamped on-chain version for resumes, the chain's\n * `activeVaultCoreVersion` for fresh deposits. It selects the PegIn shape\n * an approving wallet must expect: v1 = 2 outputs, no anchor; v2/v3 = TRUC\n * nVersion 3, 3 outputs with a 240-sat P2A anchor at vout 2, and an\n * Assert OP_RETURN marker that raises the claim value\n * (btc-vault `transactions/pegin.rs`, `assert_marker.rs`). A provider that\n * supports only one shape MUST reject the others here rather than\n * mis-validating the PSBTs later.\n */\n vaultCoreVersion: number;\n /**\n * sat/vB; the tx-graph fee rate (protocolFeeRate), NOT the mempool funding\n * rate. Approving wallets bound each payout's fee against this rate —\n * pass the exact graph rate, not an inflated ceiling.\n */\n protocolFeeRate: bigint;\n /** Vault-UTXO CSV timelock (blocks). */\n timelockPegin: number;\n /**\n * btc-vault `timelock_assert` (t2) — the CSV on Assert output 0. Its own\n * param, though production derives it and `timelockPegin` from one value.\n */\n timelockAssert: number;\n /** HTLC refund CSV timelock (blocks). */\n timelockRefund: number;\n /**\n * 64-char hex in display order. A device-wire encoder may need the\n * little-endian form — some hardware byte-compares it against\n * PSBT_IN_PREVIOUS_TXID rather than recomputing the txid.\n */\n prepeginTxid: string;\n /** sats; the funded Pre-PegIn fee (an approving wallet caps the signed fee at this). */\n prepeginMaxFee: bigint;\n /**\n * x-only hex. Sorted ascending by the upstream on-chain validation\n * (validateOnChainParticipantKeys); the builder passes them through\n * unasserted — approving devices may reject unsorted lists at load.\n */\n vaultKeeperBtcPubkeys: readonly string[];\n /**\n * x-only hex, sorted ascending upstream independently of vaultKeeperBtcPubkeys (same\n * pass-through contract). Universal challengers only — the full graph\n * challenger set is vaultKeeperBtcPubkeys ∪ universalChallengerBtcPubkeys (vault keepers are the local\n * challengers).\n */\n universalChallengerBtcPubkeys: readonly string[];\n /** Per-vault groups, ordered by ascending htlcVout. */\n vaults: readonly DepositTermsVaultGroup[];\n}\n\n/**\n * Implemented only by depositor-approval wallets (e.g. a Ledger vault\n * provider). Provider obligations:\n *\n * - Envelope: validate terms against the device's envelope BEFORE the\n * ceremony, rejecting with the shape `{ name: \"DepositTermsRejectedError\",\n * reason: \"device-envelope\", message }` (matched structurally, not by class).\n * - Idempotence: a byte-equal re-approval MUST be a no-op while the\n * device-side approval is live; anything that invalidates it (a later\n * `deriveContextHash`, a signing failure) MUST clear the memo.\n *\n * Seam invariant: any derive invalidates a prior approval, so the SDK\n * re-approves after every derive and before the next terms-bound signature.\n * The re-approval sites are `PeginManager.preparePegin`,\n * `runDepositorPresignFlow`, and `signAndBroadcast` (the Pre-PegIn broadcast,\n * which derives immediately before approving — see `ensurePrePeginTermsApproval`).\n */\nexport interface DepositTermsApprover {\n approveDepositTerms(terms: DepositTerms): Promise<void>;\n}\n\n/** True when the wallet implements {@link DepositTermsApprover.approveDepositTerms}. */\nexport function supportsDepositApproval(\n wallet: BitcoinWallet,\n): wallet is BitcoinWallet & DepositTermsApprover {\n return (\n typeof (wallet as Partial<DepositTermsApprover>).approveDepositTerms ===\n \"function\"\n );\n}\n\n/**\n * Spreadable forward of `approveDepositTerms` for wallet-wrapper objects.\n * Object spread drops prototype methods, so every `{...wallet}` wrapper site\n * must re-attach the capability explicitly: `...forwardDepositApproval(wallet)`.\n */\nexport function forwardDepositApproval(\n wallet: BitcoinWallet,\n): Partial<DepositTermsApprover> {\n return supportsDepositApproval(wallet)\n ? { approveDepositTerms: (terms) => wallet.approveDepositTerms(terms) }\n : {};\n}\n\nexport interface BuildDepositTermsInputs {\n /** btc-vault tx-graph version the graph is built under. */\n vaultCoreVersion: number;\n protocolFeeRate: bigint;\n timelockPegin: number;\n /** btc-vault `timelock_assert` (t2) — its own param; NOT derived from timelockPegin here. */\n timelockAssert: number;\n timelockRefund: number;\n prepeginTxid: string;\n prepeginMaxFee: bigint;\n vaultProviderBtcPubkey: string;\n vaultKeeperBtcPubkeys: readonly string[];\n universalChallengerBtcPubkeys: readonly string[];\n /** Ceiling bps, not the quote — see {@link DepositTermsVaultGroup.commissionFee}. */\n maxAcceptableCommissionBps: number;\n peginAmounts: readonly bigint[];\n depositorClaimValue: bigint;\n peginMaxFee: bigint;\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 { BitcoinWallet, SignPsbtOptions } from \"../../../shared/wallets\";\nimport {\n assertPsbtUnsignedTxMatches,\n assertScriptPathSchnorrSignature,\n buildPayoutPsbt,\n extractPayoutSignature,\n validateWalletPubkey,\n type Network,\n} from \"../primitives\";\nimport { createTaprootScriptPathSignOptions } from \"../utils/signing\";\n\n/** Payout PSBTs are signed by the depositor on input 0 (Taproot script-path). */\nconst PAYOUT_SIGNED_INPUT_INDEX = 0;\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 * Vault core (tx-graph) version the vault was registered under — the\n * vault's stamped on-chain `vaultCoreVersion`. Forwarded to\n * {@link buildPayoutPsbt} to derive the matching graph's payout scripts.\n */\n vaultCoreVersion: number;\n\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 /** btc-vault `timelock_assert`; payout input 1's sequence. */\n timelockAssert: 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 * Version-locked tx-graph fee rate (sat/vB) the graph was built with.\n * Forwarded to {@link buildPayoutPsbt} for the fee band.\n */\n protocolFeeRate: bigint;\n\n /** Security council member count; forwarded to the fee floor (see PayoutParams). */\n councilSize: number;\n\n /**\n * RFC-006 resolved payout destinations, keyed by lowercased x-only operation\n * pubkey. Forwarded verbatim to {@link buildPayoutPsbt}; every VK claimer\n * must be present.\n */\n vkClaimerPayoutScriptPubKeys: Readonly<Record<string, string>>;\n /** RFC-006 VP commission destination. Forwarded to {@link buildPayoutPsbt}. */\n vpCommissionScriptPubKey: string;\n}\n\n/**\n * Parameters for signing a Payout transaction.\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface SignPayoutParams extends SignPayoutBaseParams {\n /**\n * Payout transaction hex (unsigned).\n * This is the transaction from the vault provider that needs depositor signature.\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex.\n * Payout input 1 references Assert output 0.\n */\n assertTxHex: string;\n}\n\n/**\n * Result of signing a payout transaction.\n */\nexport interface PayoutSignatureResult {\n /**\n * 64-byte Schnorr signature (128 hex characters).\n */\n signature: string;\n\n /**\n * Depositor's BTC public key used for signing.\n */\n depositorBtcPubkey: string;\n}\n\n/**\n * High-level manager for payout transaction signing.\n *\n * @remarks\n * After registering your peg-in on Ethereum (Step 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 vaultCoreVersion: params.vaultCoreVersion,\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 timelockAssert: params.timelockAssert,\n network: this.config.network,\n claimerBtcPubkey: params.claimerBtcPubkey,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n protocolFeeRate: params.protocolFeeRate,\n councilSize: params.councilSize,\n vkClaimerPayoutScriptPubKeys: params.vkClaimerPayoutScriptPubKeys,\n vpCommissionScriptPubKey: params.vpCommissionScriptPubKey,\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 // Critical Path #7: verify the signature against a sighash recomputed from\n // the PSBT we built, not the wallet-returned one.\n assertScriptPathSchnorrSignature({\n requestedPsbtHex: payoutPsbt.psbtHex,\n signatureHex: signature,\n signerXOnlyPubkeyHex: depositorPubkey,\n inputIndex: PAYOUT_SIGNED_INPUT_INDEX,\n });\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(transactions: SignPayoutParams[]): 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 vaultCoreVersion: tx.vaultCoreVersion,\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 timelockAssert: tx.timelockAssert,\n network: this.config.network,\n claimerBtcPubkey: tx.claimerBtcPubkey,\n registeredPayoutScriptPubKey: tx.registeredPayoutScriptPubKey,\n commissionBps: tx.commissionBps,\n protocolFeeRate: tx.protocolFeeRate,\n councilSize: tx.councilSize,\n vkClaimerPayoutScriptPubKeys: tx.vkClaimerPayoutScriptPubKeys,\n vpCommissionScriptPubKey: tx.vpCommissionScriptPubKey,\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 assertScriptPathSchnorrSignature({\n requestedPsbtHex: psbtsToSign[i],\n signatureHex: payoutSignature,\n signerXOnlyPubkeyHex: depositorPubkey,\n inputIndex: PAYOUT_SIGNED_INPUT_INDEX,\n });\n\n results.push({\n payoutSignature,\n depositorBtcPubkey: depositorPubkey,\n });\n }\n\n return results;\n }\n}\n","/**\n * Wallet-signing helper that routes a lone PSBT to `signPsbt`, prefers native\n * `signPsbts` for real batches, and falls back to sequential `signPsbt` for\n * wallets that don't implement batch signing.\n *\n * @module managers/pegin/signPsbtsWithFallback\n */\n\nimport type {\n BitcoinWallet,\n SignPsbtOptions,\n} from \"../../../../shared/wallets\";\n\n/**\n * Sign one or more PSBTs against a wallet.\n *\n * A single PSBT is always signed via `signPsbt`, never the batch endpoint: it's\n * one wallet interaction either way, and `signPsbt` is the universally-required\n * wallet method (batch `signPsbts` is optional), so single-sign is the portable\n * choice — some integrations (notably MPC / institutional wallets) prefer it.\n * For a real batch (>1), wallets exposing native `signPsbts` (e.g. UniSat) sign\n * in one interaction; others loop `signPsbt`.\n *\n * @throws If native `signPsbts` returns a different number of signed PSBTs\n * than were submitted.\n */\nexport async function signPsbtsWithFallback(\n wallet: BitcoinWallet,\n psbtsHexes: string[],\n options?: SignPsbtOptions[],\n): Promise<string[]> {\n if (psbtsHexes.length === 1) {\n return [await wallet.signPsbt(psbtsHexes[0], options?.[0])];\n }\n\n if (typeof wallet.signPsbts === \"function\") {\n const signedPsbts = await wallet.signPsbts(psbtsHexes, options);\n if (signedPsbts.length !== psbtsHexes.length) {\n throw new Error(\n `Expected ${psbtsHexes.length} signed PSBTs but received ${signedPsbts.length}`,\n );\n }\n return signedPsbts;\n }\n\n const signedPsbts: string[] = [];\n for (let i = 0; i < psbtsHexes.length; i++) {\n signedPsbts.push(await wallet.signPsbt(psbtsHexes[i], options?.[i]));\n }\n return signedPsbts;\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","supportsDepositApproval","wallet","forwardDepositApproval","terms","PAYOUT_SIGNED_INPUT_INDEX","PayoutManager","config","__publicField","params","walletPubkeyRaw","depositorPubkey","validateWalletPubkey","payoutPsbt","buildPayoutPsbt","signedPsbtHex","createTaprootScriptPathSignOptions","assertPsbtUnsignedTxMatches","signature","extractPayoutSignature","assertScriptPathSchnorrSignature","transactions","psbtsToSign","signOptions","depositorPubkeys","signedPsbts","results","payoutSignature","signPsbtsWithFallback","psbtsHexes","options"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const v=require("@babylonlabs-io/babylon-tbv-rust-wasm"),p=require("buffer"),w=require("bitcoinjs-lib"),b=require("./fundPeginTransaction-BLD8FRL9.cjs"),c=require("./bitcoin-m84N5a8o.cjs"),g=require("./constants-DU5CGcqO.cjs"),Y=require("@bitcoin-js/tiny-secp256k1-asmjs");function D(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:()=>e[n]})}}return t.default=e,Object.freeze(t)}const G=D(Y);async function Q(e,t){const n=t.pegInAmounts.length;if(e.htlcValues.length!==n)throw new Error(`WASM Pre-PegIn returned ${e.htlcValues.length} HTLC value(s), expected ${n} (one per requested deposit).`);if(e.peginAmounts.length!==n||e.htlcScriptPubKeys.length!==n||e.htlcAddresses.length!==n)throw new Error(`WASM Pre-PegIn returned mismatched array lengths (htlcValues=${e.htlcValues.length}, peginAmounts=${e.peginAmounts.length}, htlcScriptPubKeys=${e.htlcScriptPubKeys.length}, htlcAddresses=${e.htlcAddresses.length}); expected ${n} each.`);if(e.depositorClaimValue<=0n)throw new Error(`WASM Pre-PegIn returned non-positive depositorClaimValue ${e.depositorClaimValue}; expected > 0.`);const r=await v.computeMinClaimValue(t.vaultCoreVersion,t.numLocalChallengers,t.universalChallengerPubkeys.length,t.councilQuorum,t.councilSize,t.feeRate);if(e.depositorClaimValue!==r)throw new Error(`WASM Pre-PegIn depositorClaimValue ${e.depositorClaimValue} does not match the independently computed minimum claim value ${r} (vaultCoreVersion=${t.vaultCoreVersion}, numLocalChallengers=${t.numLocalChallengers}, numUniversalChallengers=${t.universalChallengerPubkeys.length}, councilQuorum=${t.councilQuorum}, councilSize=${t.councilSize}, feeRate=${t.feeRate}).`);const o=await v.peginP2aAnchorOutput(t.vaultCoreVersion),i=(o==null?void 0:o.value)??0n,s=await v.computeMinPeginFee(t.vaultCoreVersion,t.vaultKeeperPubkeys.length,t.universalChallengerPubkeys.length,t.minPeginFeeRate),u=s+i,P=t.minPeginFeeRate*b.MAX_REASONABLE_PEGIN_VBYTES;for(let a=0;a<n;a++){const h=t.pegInAmounts[a],l=e.peginAmounts[a],x=e.htlcValues[a];if(l!==h)throw new Error(`WASM Pre-PegIn peginAmount[${a}] ${l} does not match the requested amount ${h}; refusing to build a tx whose recorded amount differs from the depositor's request.`);if(l<=0n)throw new Error(`WASM Pre-PegIn peginAmount[${a}] is non-positive (${l}); expected > 0.`);if(x<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${a}] is non-positive (${x}); expected > 0.`);const d=x-l-e.depositorClaimValue;if(d<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${a}] ${x} does not strictly cover peginAmount ${l} + depositorClaimValue ${e.depositorClaimValue} + a PegIn reserve (implied reserve ${d}).`);if(d>P)throw new Error(`WASM Pre-PegIn implied reserve for HTLC[${a}] (${d} sat) exceeds the plausibility cap ${P} sat (minPeginFeeRate=${t.minPeginFeeRate} × ${b.MAX_REASONABLE_PEGIN_VBYTES} vbytes); htlcValue ${x} appears grossly inflated.`);if(d!==u)throw new Error(`WASM Pre-PegIn htlcValue[${a}] ${x} implies a PegIn fee+anchor reserve of ${d} sat, expected exactly ${u} sat (minPeginFee ${s} + p2aAnchor ${i} for vaultCoreVersion ${t.vaultCoreVersion}, vaultKeepers=${t.vaultKeeperPubkeys.length}, universalChallengers=${t.universalChallengerPubkeys.length}, minPeginFeeRate=${t.minPeginFeeRate}).`)}return s}class _ extends Error{constructor(t){super(t),this.name="HtlcOutputMismatchError"}}function W(e,t,n){if(e.length<t.length)throw new _(`Encoded Pre-PegIn tx has ${e.length} output(s), fewer than the ${t.length} HTLC output(s) the cross-check validated.`);for(let r=0;r<t.length;r++){const o=BigInt(e[r].value);if(o!==t[r])throw new _(`Encoded Pre-PegIn HTLC output[${r}] value ${o} does not match the cross-checked htlcValue ${t[r]}; the funded/signed tx would not pay the validated amount.`);const i=e[r].script.toString("hex").toLowerCase(),s=n[r].toLowerCase();if(i!==s)throw new _(`Encoded Pre-PegIn HTLC output[${r}] scriptPubKey ${i} does not match the cross-checked htlcScriptPubKey ${s}.`)}}const H=64,Z=/^[0-9a-fA-F]+$/;async function j(e){const t=I(e.authAnchorHash),n=await v.createPrePeginTransaction({txGraphVersion:e.vaultCoreVersion,depositorPubkey:e.depositorPubkey,vaultProviderPubkey:e.vaultProviderPubkey,vaultKeeperPubkeys:e.vaultKeeperPubkeys,universalChallengerPubkeys:e.universalChallengerPubkeys,hashlocks:[...e.hashlocks],timelockRefund:e.timelockRefund,pegInAmounts:[...e.pegInAmounts],feeRate:e.feeRate,minPeginFeeRate:e.minPeginFeeRate,numLocalChallengers:e.numLocalChallengers,councilQuorum:e.councilQuorum,councilSize:e.councilSize,network:e.network,authAnchorHash:t}),r=await Q(n,e),o=b.parseUnfundedWasmTransaction(n.txHex);W(o.outputs,n.htlcValues,n.htlcScriptPubKeys);const i=o.outputs.reduce((u,P)=>u+BigInt(P.value),0n),s=t!==void 0?n.htlcValues.length:null;return{psbtHex:n.txHex,totalOutputValue:i,htlcValues:n.htlcValues,htlcScriptPubKeys:n.htlcScriptPubKeys,htlcAddresses:n.htlcAddresses,peginAmounts:n.peginAmounts,depositorClaimValue:n.depositorClaimValue,authAnchorVout:s,minPeginFee:r}}function I(e){if(e===void 0)return;const t=e.startsWith("0x")||e.startsWith("0X")?e.slice(2):e;if(t.length!==H||!Z.test(t))throw new Error(`authAnchorHash must be 32-byte hex (${H} chars, no 0x prefix); got length ${t.length}`);return t.toLowerCase()}async function J(e){const t=await v.buildPeginTxFromPrePegin({txGraphVersion:e.prePeginParams.vaultCoreVersion,depositorPubkey:e.prePeginParams.depositorPubkey,vaultProviderPubkey:e.prePeginParams.vaultProviderPubkey,vaultKeeperPubkeys:e.prePeginParams.vaultKeeperPubkeys,universalChallengerPubkeys:e.prePeginParams.universalChallengerPubkeys,hashlocks:[...e.prePeginParams.hashlocks],timelockRefund:e.prePeginParams.timelockRefund,pegInAmounts:[...e.prePeginParams.pegInAmounts],feeRate:e.prePeginParams.feeRate,minPeginFeeRate:e.prePeginParams.minPeginFeeRate,numLocalChallengers:e.prePeginParams.numLocalChallengers,councilQuorum:e.prePeginParams.councilQuorum,councilSize:e.prePeginParams.councilSize,network:e.prePeginParams.network,authAnchorHash:I(e.prePeginParams.authAnchorHash)},e.timelockPegin,e.fundedPrePeginTxHex,e.htlcVout);return await ne(t,e),{txHex:t.txHex,txid:t.txid,vaultScriptPubKey:t.vaultScriptPubKey,vaultValue:t.vaultValue}}const ee=2,te=1;async function ne(e,t){const n=t.prePeginParams.vaultCoreVersion;await v.validatePeginP2aAnchor(n,e.txHex);const r=await v.peginP2aAnchorOutput(n),o=ee+(r?1:0),i=w.Transaction.fromHex(c.stripHexPrefix(e.txHex));if(i.ins.length!==1)throw new Error(`PegIn tx has ${i.ins.length} input(s), expected exactly 1 (the Pre-PegIn HTLC outpoint).`);const s=w.Transaction.fromHex(c.stripHexPrefix(t.fundedPrePeginTxHex)).getId(),u=c.uint8ArrayToHex(new Uint8Array(i.ins[0].hash).slice().reverse());if(u!==s)throw new Error(`PegIn input spends txid ${u}, expected the funded Pre-PegIn ${s}.`);if(i.ins[0].index!==t.htlcVout)throw new Error(`PegIn input spends Pre-PegIn output ${i.ins[0].index}, expected the requested HTLC vout ${t.htlcVout}.`);if(i.outs.length!==o)throw new Error(`PegIn tx has ${i.outs.length} output(s), expected exactly ${o} for vaultCoreVersion ${n} (vault + depositor claim${r?" + P2A anchor":""}).`);const P=t.prePeginParams.pegInAmounts[t.htlcVout];if(e.vaultValue!==P)throw new Error(`PegIn vault output value ${e.vaultValue} does not match the requested peg-in amount ${P} for HTLC ${t.htlcVout}; refusing to sign a vault that locks a different amount than requested.`);const a=i.outs[0];if(BigInt(a.value)!==e.vaultValue)throw new Error(`Encoded PegIn vault output value ${a.value} does not match the WASM-reported vaultValue ${e.vaultValue}.`);const h=a.script.toString("hex"),l=c.stripHexPrefix(e.vaultScriptPubKey).toLowerCase();if(h.toLowerCase()!==l)throw new Error(`Encoded PegIn vault output scriptPubKey ${h} does not match the WASM-reported vaultScriptPubKey ${e.vaultScriptPubKey}.`);const x=i.getId();if(x!==c.stripHexPrefix(e.txid).toLowerCase())throw new Error(`Encoded PegIn txid ${x} does not match the WASM-reported txid ${e.txid}.`);const d=await v.computeMinClaimValue(n,t.prePeginParams.numLocalChallengers,t.prePeginParams.universalChallengerPubkeys.length,t.prePeginParams.councilQuorum,t.prePeginParams.councilSize,t.prePeginParams.feeRate),y=i.outs[te];if(BigInt(y.value)!==d)throw new Error(`Encoded PegIn depositor-claim output value ${y.value} does not match the independently computed claim value ${d} for vaultCoreVersion ${n}.`);const $=re(t.prePeginParams.depositorPubkey);if(!y.script.equals($))throw new Error(`Encoded PegIn depositor-claim output scriptPubKey ${y.script.toString("hex")} does not pay to the depositor's claim script (expected ${$.toString("hex")}).`)}function re(e){const t=w.script.compile([p.Buffer.from(c.hexToUint8Array(e)),w.opcodes.OP_CHECKSIG]),{output:n}=w.payments.p2tr({internalPubkey:p.Buffer.from(v.tapInternalPubkey),scriptTree:{output:t}});if(!n)throw new Error("Failed to derive the depositor-claim P2TR scriptPubKey for PegIn output validation");return n}async function X(e){const t=await v.createPayoutConnector({txGraphVersion:e.vaultCoreVersion,depositor:e.depositor,vaultProvider:e.vaultProvider,vaultKeepers:e.vaultKeepers,universalChallengers:e.universalChallengers,timelockPegin:e.timelockPegin},e.network);return{payoutScript:t.payoutScript,taprootScriptHash:t.taprootScriptHash,scriptPubKey:t.scriptPubKey,address:t.address,payoutControlBlock:t.payoutControlBlock}}const oe=256,ie=1500,V=256,k=0xffffffffn,se=500,ue=55,ce=34;function ae(e){if(typeof e.protocolFeeRate!="bigint"||e.protocolFeeRate<=0n||e.protocolFeeRate>k)throw new Error(`protocolFeeRate must be in [1, ${k}] sat/vB, got ${e.protocolFeeRate}`);for(const[t,n,r,o]of[["keepers",e.numVaultKeepers,oe,"fee-floor model limit"],["challengers",e.numUniversalChallengers,ie,"protocol maximum"]])if(!Number.isInteger(n)||n<1||n>r)throw new Error(`Participant count for ${t} (${n}) is outside the supported range [1, ${r}]${n>r?` (${o})`:""}.`);if(!Number.isInteger(e.councilSize)||e.councilSize<1||e.councilSize>V)throw new Error(`councilSize must be an integer in [1, ${V}], got ${e.councilSize}`)}async function le(e,t){const{implicitFeeSats:n,out0Len:r,out1Len:o}=t,i=e.numVaultKeepers+e.numUniversalChallengers,s=BigInt(n),u=Math.max(0,r-ce),P=se+ue*i+u,a=e.protocolFeeRate*BigInt(P);if(s>a)throw new Error(`Payout implicit fee ${n} sats exceeds the safety cap of ${a} sats (${e.protocolFeeRate} sat/vB x ${P} vB for ${i} participants); refusing to sign payout.`);const h=await v.computePayoutFeeFloor(e.vaultCoreVersion,e.numVaultKeepers,e.numUniversalChallengers,e.numVaultKeepers,e.councilSize,r,o,e.protocolFeeRate);if(s<h)throw new Error(`Payout implicit fee ${n} sats is below the floor of ${h} sats (the smallest fee any known vault-provider build produces for this shape); refusing to sign payout.`)}const he=22,Pe=34,de=34,pe=25,fe=23;function ge(e){return e.length===he*2&&e.startsWith("0014")}function xe(e){return e.length===Pe*2&&e.startsWith("0020")}function we(e){return e.length===de*2&&e.startsWith("5120")}function ve(e){return e.length===pe*2&&e.startsWith("76a914")&&e.endsWith("88ac")}function $e(e){return e.length===fe*2&&e.startsWith("a914")&&e.endsWith("87")}function L(e,t){const n=c.stripHexPrefix(e).toLowerCase();if(n.length===0)throw new Error(`${t} is empty`);if(!/^[0-9a-f]+$/.test(n)||n.length%2!==0)throw new Error(`${t} is not valid hex`);if(n.startsWith("6a"))throw new Error(`${t} is an OP_RETURN output, which is provably unspendable`);if(!we(n)&&!ge(n)&&!xe(n)&&!ve(n)&&!$e(n))throw new Error(`${t} is not a standard scriptPubKey (expected P2TR, P2WPKH, P2WSH, P2PKH, or P2SH; got ${n.length/2} bytes: ${n})`)}const R=3;async function Se(e){const t={vaultCoreVersion:e.vaultCoreVersion,numVaultKeepers:e.vaultKeeperBtcPubkeys.length,numUniversalChallengers:e.universalChallengerBtcPubkeys.length,councilSize:e.councilSize,protocolFeeRate:e.protocolFeeRate};ae(t);const n=w.Transaction.fromHex(c.stripHexPrefix(e.payoutTxHex)),r=w.Transaction.fromHex(c.stripHexPrefix(e.peginTxHex)),o=w.Transaction.fromHex(c.stripHexPrefix(e.assertTxHex));if(n.ins.length!==g.DEPOSITOR_PAYOUT_INPUT_COUNT)throw new Error(`Payout transaction must have exactly ${g.DEPOSITOR_PAYOUT_INPUT_COUNT} inputs, got ${n.ins.length}`);if(n.version!==g.PAYOUT_TX_VERSION)throw new Error(`Payout transaction version ${n.version} must be ${g.PAYOUT_TX_VERSION}; refusing to sign payout.`);if(n.locktime!==g.PAYOUT_TX_LOCKTIME)throw new Error(`Payout transaction locktime ${n.locktime} must be ${g.PAYOUT_TX_LOCKTIME}; refusing to sign payout.`);const i=U(n.ins[0],0,r,"PegIn",g.PEGIN_VAULT_OUTPUT_INDEX);if(n.ins[0].sequence!==e.timelockPegin)throw new Error(`Payout input 0 sequence ${n.ins[0].sequence} must equal the PegIn CSV timelock ${e.timelockPegin}; refusing to sign payout.`);const s=U(n.ins[1],1,o,"Assert",g.ASSERT_PAYOUT_OUTPUT_INDEX);if(n.ins[1].sequence!==e.timelockAssert)throw new Error(`Payout input 1 sequence ${n.ins[1].sequence} must equal the Assert CSV timelock ${e.timelockAssert}; refusing to sign payout.`);const{out0Len:u,out1Len:P}=ye(n,i.value,e),a=i.value+s.value;let h=0;for(const d of n.outs)h+=d.value;if(h>a)throw new Error(`Payout outputs (${h} sats) exceed inputs (${a} sats); invalid transaction.`);const l=a-h;await le(t,{implicitFeeSats:l,out0Len:u,out1Len:P});const x=await X({vaultCoreVersion:e.vaultCoreVersion,depositor:e.depositorBtcPubkey,vaultProvider:e.vaultProviderBtcPubkey,vaultKeepers:e.vaultKeeperBtcPubkeys,universalChallengers:e.universalChallengerBtcPubkeys,timelockPegin:e.timelockPegin,network:e.network});return{psbtHex:Ee(n,i,s,x)}}function U(e,t,n,r,o){const i=c.uint8ArrayToHex(new Uint8Array(e.hash).slice().reverse()),s=n.getId();if(i!==s||e.index!==o)throw new Error(`Input ${t} must spend ${r}:${o}. Expected ${s}:${o}, got ${i}:${e.index}`);const u=n.outs[e.index];if(!u)throw new Error(`Previous output not found for input ${t} (txid: ${i}, index: ${e.index})`);return u}function Ee(e,t,n,r){const o=new w.Psbt;o.setVersion(e.version),o.setLocktime(e.locktime);const[i,s]=e.ins;o.addInput({hash:i.hash,index:i.index,sequence:i.sequence,witnessUtxo:{script:t.script,value:t.value},tapLeafScript:[{leafVersion:c.TAPSCRIPT_LEAF_VERSION,script:p.Buffer.from(c.hexToUint8Array(r.payoutScript)),controlBlock:p.Buffer.from(c.hexToUint8Array(r.payoutControlBlock))}],tapInternalKey:p.Buffer.from(v.tapInternalPubkey)}),o.addInput({hash:s.hash,index:s.index,sequence:s.sequence,witnessUtxo:{script:n.script,value:n.value}});for(const u of e.outs)o.addOutput({script:u.script,value:u.value});return o.toHex()}function N(e,t){const n=c.stripHexPrefix(e).toLowerCase(),r=c.stripHexPrefix(c.deriveBip86ScriptPubKeyHex(t)).toLowerCase();return n===r?[n]:[n,r]}function B(e,t){return t.some(n=>e.equals(p.Buffer.from(n,"hex")))}function ye(e,t,n){const{claimerBtcPubkey:r,vaultProviderBtcPubkey:o,depositorBtcPubkey:i,vaultKeeperBtcPubkeys:s,registeredPayoutScriptPubKey:u,commissionBps:P,vkClaimerPayoutScriptPubKeys:a,vpCommissionScriptPubKey:h}=n;if(!c.isValidHex(u))throw new Error("Invalid registeredPayoutScriptPubKey: not valid hex");const l=c.stripHexPrefix(r).toLowerCase(),x=c.stripHexPrefix(o).toLowerCase(),d=c.stripHexPrefix(i).toLowerCase(),y=s.map(m=>c.stripHexPrefix(m).toLowerCase());let $,f,E;if(l===x)$="vp-claimer",f=g.VP_CLAIMER_PAYOUT_OUTPUT_COUNT,E=[c.stripHexPrefix(u)];else if(l===d)$="depositor-as-claimer",f=g.NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT,E=[c.stripHexPrefix(u)];else if(y.includes(l)){$="vk-claimer",f=g.NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT;const m=a[l];if(m===void 0)throw new Error(`No registered payout script resolved for vault keeper claimer ${l}`);L(m,`Vault keeper payout script for claimer ${l}`),E=N(m,l)}else throw new Error(`Unknown claimer pubkey ${l}: not VP, depositor, or a registered vault keeper`);if(e.outs.length!==f)throw new Error(`Payout transaction has ${e.outs.length} output(s), expected exactly ${f} for role ${$}.`);if(!B(e.outs[0].script,E))throw new Error(`Payout transaction output 0 does not pay the expected scriptPubKey for role ${$}. Accepted: ${E.join(" or ")}; got ${e.outs[0].script.toString("hex")}`);const C=f-1;if(e.outs[C].value!==g.PAYOUT_ANCHOR_DUST_SATS)throw new Error(`Payout CPFP anchor (out ${C}) value ${e.outs[C].value} sats must equal ${g.PAYOUT_ANCHOR_DUST_SATS} sats`);if($==="vp-claimer"){L(h,"Vault provider commission payout script");const m=N(h,x);if(!B(e.outs[1].script,m))throw new Error(`Payout transaction output 1 does not pay the vault provider's commission scriptPubKey. Accepted: ${m.join(" or ")}; got ${e.outs[1].script.toString("hex")}`);if(!Number.isInteger(P)||P<0||P>=g.MAX_VP_COMMISSION_BPS_EXCLUSIVE)throw new Error(`commissionBps must be an integer in [0, ${g.MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${P}`);const O=Math.floor(t*P/g.BPS_DENOMINATOR);if(e.outs[1].value>O)throw new Error(`Payout VP commission (out 1) value ${e.outs[1].value} sats exceeds cap ${O} sats (${P} bps of peginValue=${t})`)}const A=e.outs[0].script.length;if(A===0||A>g.MAX_PAYOUT_SCRIPT_LEN)throw new Error(`Payout receiver scriptPubKey length ${A} is outside the contract's registration cap [1, ${g.MAX_PAYOUT_SCRIPT_LEN}]; refusing to sign payout.`);const z=$==="vp-claimer"?e.outs[1].script.length:void 0;return{out0Len:A,out1Len:z}}function me(e,t,n=0){const r=w.Psbt.fromHex(e);if(n>=r.data.inputs.length)throw new Error(`Input index ${n} out of range (${r.data.inputs.length} inputs)`);const o=r.data.inputs[n];if(o.tapScriptSig&&o.tapScriptSig.length>0){const i=c.hexToUint8Array(t);for(const s of o.tapScriptSig)if(s.pubkey.equals(p.Buffer.from(i)))return M(s.signature,n);throw new Error(`No signature found for depositor pubkey: ${t} at input ${n}`)}if(o.finalScriptWitness&&o.finalScriptWitness.length>0){const i=Ae(o.finalScriptWitness);if(i.length!==R)throw new Error(`Unexpected finalized witness stack size at input ${n}: expected ${R} items (signature, script, controlBlock), got ${i.length}`);return M(i[0],n)}throw new Error(`No tapScriptSig or finalScriptWitness found in signed PSBT at input ${n}`)}function M(e,t){if(e.length===64)return c.uint8ArrayToHex(new Uint8Array(e));throw e.length===65?new Error(`Unexpected sighash byte 0x${e[64].toString(16).padStart(2,"0")} at input ${t}. Expected implicit SIGHASH_DEFAULT as a 64-byte signature.`):new Error(`Unexpected signature length at input ${t}: ${e.length}`)}function Ae(e){const t=[];let n=0;const r=s=>{if(n+s>e.length)throw new Error(`Malformed witness data: need ${s} byte(s) at offset ${n}, only ${e.length-n} remaining`)},o=()=>{r(1);const s=e[n++];if(s<253)return s;if(s===253){r(2);const u=(e[n]|e[n+1]<<8)>>>0;return n+=2,u}if(s===254){r(4);const u=(e[n]|e[n+1]<<8|e[n+2]<<16|e[n+3]<<24)>>>0;return n+=4,u}throw new Error(`Malformed witness data: 8-byte varint (0xff) not supported at offset ${n-1}`)},i=o();for(let s=0;s<i;s++){const u=o();r(u),t.push(p.Buffer.from(e.subarray(n,n+u))),n+=u}if(n!==e.length)throw new Error(`Malformed witness data: ${e.length-n} trailing byte(s) after parsing ${i} item(s)`);return t}class S extends Error{constructor(t){super(`Wallet returned a PSBT for a different transaction: ${t}`),this.name="PsbtSubstitutionError"}}function K(e,t){try{return w.Psbt.fromHex(t)}catch(n){const r=n instanceof Error?n.message:String(n);throw new Error(`Failed to parse ${e} PSBT: ${r}`)}}const _e=8;function T(e){return`${e.toString("hex").slice(0,_e)}…`}function q(e){const t=p.Buffer.from(e).reverse();return T(t)}function Ce(e){const t=K("requested",e.requestedPsbtHex),n=K("returned",e.returnedPsbtHex);if(t.version!==n.version)throw new S(`tx version differs (requested=${t.version}, returned=${n.version})`);if(t.locktime!==n.locktime)throw new S(`tx locktime differs (requested=${t.locktime}, returned=${n.locktime})`);if(t.txInputs.length!==n.txInputs.length)throw new S(`input count differs (requested=${t.txInputs.length}, returned=${n.txInputs.length})`);if(t.txOutputs.length!==n.txOutputs.length)throw new S(`output count differs (requested=${t.txOutputs.length}, returned=${n.txOutputs.length})`);for(let r=0;r<t.txInputs.length;r++){const o=t.txInputs[r],i=n.txInputs[r];if(!o.hash.equals(i.hash))throw new S(`input ${r} prevout txid differs (requested=${q(o.hash)}, returned=${q(i.hash)})`);if(o.index!==i.index)throw new S(`input ${r} prevout vout differs (requested=${o.index}, returned=${i.index})`);if(o.sequence!==i.sequence)throw new S(`input ${r} sequence differs (requested=${o.sequence}, returned=${i.sequence})`)}for(let r=0;r<t.txOutputs.length;r++){const o=t.txOutputs[r],i=n.txOutputs[r];if(!o.script.equals(i.script))throw new S(`output ${r} scriptPubKey differs (requested=${T(o.script)}, returned=${T(i.script)})`);if(o.value!==i.value)throw new S(`output ${r} value differs (requested=${o.value}, returned=${i.value})`)}}const F=253,be=254,Te=65535,Ie=4294967295;function Oe(e){if(e<F)return p.Buffer.from([e]);if(e<=Te){const t=p.Buffer.alloc(2);return t.writeUInt16LE(e),p.Buffer.concat([p.Buffer.from([F]),t])}if(e<=Ie){const t=p.Buffer.alloc(4);return t.writeUInt32LE(e),p.Buffer.concat([p.Buffer.from([be]),t])}throw new Error(`Script too large to encode as CompactSize: ${e} bytes`)}const He="TapLeaf";function Ve(e,t){const n=p.Buffer.concat([p.Buffer.from([e]),Oe(t.length),p.Buffer.from(t)]);return w.crypto.taggedHash(He,n)}function ke(e){const{requestedPsbtHex:t,signatureHex:n,signerXOnlyPubkeyHex:r,inputIndex:o}=e,i=c.stripHexPrefix(n);if(i.length!==c.SCHNORR_SIG_HEX_LEN)throw new Error(`Schnorr signature for input ${o} must be ${c.SCHNORR_SIG_HEX_LEN} hex chars (64 bytes), got ${i.length}.`);const s=c.stripHexPrefix(r);if(s.length!==c.X_ONLY_PUBKEY_HEX_LEN)throw new Error(`Signer x-only pubkey for input ${o} must be ${c.X_ONLY_PUBKEY_HEX_LEN} hex chars (32 bytes), got ${s.length}.`);const u=w.Psbt.fromHex(t);if(o<0||o>=u.data.inputs.length)throw new Error(`Input index ${o} out of range (${u.data.inputs.length} inputs).`);const P=[],a=[];for(let f=0;f<u.data.inputs.length;f++){const E=u.data.inputs[f].witnessUtxo;if(!E)throw new Error(`Cannot verify signature: input ${f} of the requested PSBT has no witnessUtxo (required to recompute the Taproot sighash).`);P.push(E.script),a.push(E.value)}const h=u.data.inputs[o].tapLeafScript;if(!h||h.length!==1)throw new Error(`Cannot verify signature: input ${o} of the requested PSBT must have exactly one tapLeafScript, got ${(h==null?void 0:h.length)??0}.`);const l=h[0];if(l.leafVersion!==c.TAPSCRIPT_LEAF_VERSION)throw new Error(`Cannot verify signature: input ${o} tapLeafScript has leaf version 0x${l.leafVersion.toString(16)}, expected 0x${c.TAPSCRIPT_LEAF_VERSION.toString(16)}.`);const x=Ve(l.leafVersion,l.script),d=new w.Transaction;d.version=u.version,d.locktime=u.locktime;for(const f of u.txInputs)d.addInput(f.hash,f.index,f.sequence);for(const f of u.txOutputs)d.addOutput(f.script,f.value);const y=d.hashForWitnessV1(o,P,a,w.Transaction.SIGHASH_DEFAULT,x);if(!G.verifySchnorr(y,c.hexToUint8Array(s),c.hexToUint8Array(i)))throw new Error(`Schnorr signature for input ${o} (signer ${s}) does not verify against the expected Taproot script-path sighash. The wallet may have signed with the tweaked key, signed a different transaction, or returned an invalid signature.`)}exports.HtlcOutputMismatchError=_;exports.PsbtSubstitutionError=S;exports.assertEncodedHtlcOutputsMatch=W;exports.assertPsbtUnsignedTxMatches=Ce;exports.assertScriptPathSchnorrSignature=ke;exports.buildPayoutPsbt=Se;exports.buildPeginTxFromFundedPrePegin=J;exports.buildPrePeginPsbt=j;exports.createPayoutScript=X;exports.extractPayoutSignature=me;exports.normalizeAuthAnchorHash=I;
|
|
2
|
-
//# sourceMappingURL=verifyScriptPathSchnorrSignature-DPAd_qke.cjs.map
|