@babylonlabs-io/ts-sdk 0.56.0 → 0.57.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/README.md +1 -1
- package/dist/BTCVaultRegistry.abi-AUAyCHal.cjs +2 -0
- package/dist/BTCVaultRegistry.abi-AUAyCHal.cjs.map +1 -0
- package/dist/{BTCVaultRegistry.abi-Chs4AFBj.js → BTCVaultRegistry.abi-CixOlp3B.js} +73 -14
- package/dist/BTCVaultRegistry.abi-CixOlp3B.js.map +1 -0
- package/dist/BTCVaultRegistryKeyEpochs.abi-CXjhRZbm.js +111 -0
- package/dist/BTCVaultRegistryKeyEpochs.abi-CXjhRZbm.js.map +1 -0
- package/dist/BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs +2 -0
- package/dist/BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs.map +1 -0
- package/dist/{PeginManager-aYBkb-Qx.js → PeginManager-CnX3uFb0.js} +6 -6
- package/dist/{PeginManager-aYBkb-Qx.js.map → PeginManager-CnX3uFb0.js.map} +1 -1
- package/dist/PeginManager-iDbqXsKD.cjs +2 -0
- package/dist/{PeginManager-BkWdZI7P.cjs.map → PeginManager-iDbqXsKD.cjs.map} +1 -1
- package/dist/ProtocolParams.abi-C8U7BHCS.cjs +2 -0
- package/dist/ProtocolParams.abi-C8U7BHCS.cjs.map +1 -0
- package/dist/{ApplicationRegistry.abi-w5prf7Ig.js → ProtocolParams.abi-CV938AYZ.js} +150 -80
- package/dist/ProtocolParams.abi-CV938AYZ.js.map +1 -0
- package/dist/{buildAndBroadcastRefund-BtXUqBkb.js → buildAndBroadcastRefund-CCb1_z24.js} +627 -452
- package/dist/buildAndBroadcastRefund-CCb1_z24.js.map +1 -0
- package/dist/buildAndBroadcastRefund-CDzzTZ2U.cjs +2 -0
- package/dist/buildAndBroadcastRefund-CDzzTZ2U.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +186 -175
- package/dist/index.js.map +1 -1
- package/dist/{types-CQDRQvV-.js → json-rpc-client-Ehjthcd7.js} +61 -61
- package/dist/json-rpc-client-Ehjthcd7.js.map +1 -0
- package/dist/{types-WA0LrDk1.cjs → json-rpc-client-fUoK-TzT.cjs} +2 -2
- package/dist/json-rpc-client-fUoK-TzT.cjs.map +1 -0
- package/dist/mempoolApi-C0olk43O.js +536 -0
- package/dist/mempoolApi-C0olk43O.js.map +1 -0
- package/dist/mempoolApi-Dsm2VPXp.cjs +2 -0
- package/dist/mempoolApi-Dsm2VPXp.cjs.map +1 -0
- package/dist/{noPayout-CihCk1HE.js → noPayout-CI4l1qu2.js} +2 -2
- package/dist/{noPayout-CihCk1HE.js.map → noPayout-CI4l1qu2.js.map} +1 -1
- package/dist/{noPayout-Cb8vFrkY.cjs → noPayout-Djrv31V5.cjs} +2 -2
- package/dist/{noPayout-Cb8vFrkY.cjs.map → noPayout-Djrv31V5.cjs.map} +1 -1
- package/dist/onChainBtcPubkey-Cd9kpz-S.cjs +2 -0
- package/dist/onChainBtcPubkey-Cd9kpz-S.cjs.map +1 -0
- package/dist/onChainBtcPubkey-aPY5ib3Q.js +19 -0
- package/dist/onChainBtcPubkey-aPY5ib3Q.js.map +1 -0
- package/dist/primeVpAuth-BlxUcdBf.cjs +2 -0
- package/dist/primeVpAuth-BlxUcdBf.cjs.map +1 -0
- package/dist/{primeVpAuth-DZOaC_Ui.js → primeVpAuth-DkJbvywo.js} +479 -367
- package/dist/primeVpAuth-DkJbvywo.js.map +1 -0
- package/dist/signPsbtsWithFallback-C01N6Kdo.cjs +2 -0
- package/dist/signPsbtsWithFallback-C01N6Kdo.cjs.map +1 -0
- package/dist/{PayoutManager-BVgmuKuK.js → signPsbtsWithFallback-CzZFZf0I.js} +105 -101
- package/dist/signPsbtsWithFallback-CzZFZf0I.js.map +1 -0
- package/dist/tbv/core/clients/eth/index.d.ts +5 -3
- package/dist/tbv/core/clients/eth/index.d.ts.map +1 -1
- package/dist/tbv/core/clients/eth/onChainBtcPubkey.d.ts +16 -0
- package/dist/tbv/core/clients/eth/onChainBtcPubkey.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/operation-key-reader.d.ts +33 -0
- package/dist/tbv/core/clients/eth/operation-key-reader.d.ts.map +1 -0
- package/dist/tbv/core/clients/eth/types.d.ts +122 -3
- package/dist/tbv/core/clients/eth/types.d.ts.map +1 -1
- package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts +25 -1
- package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts.map +1 -1
- package/dist/tbv/core/clients/index.cjs +1 -1
- package/dist/tbv/core/clients/index.js +35 -32
- package/dist/tbv/core/clients/index.js.map +1 -1
- package/dist/tbv/core/clients/mempool/mempoolApi.d.ts.map +1 -1
- package/dist/tbv/core/contracts/__tests__/BTCVaultRegistryKeyEpochs.abi.test.d.ts +2 -0
- package/dist/tbv/core/contracts/__tests__/BTCVaultRegistryKeyEpochs.abi.test.d.ts.map +1 -0
- package/dist/tbv/core/contracts/abis/ApplicationRegistry.abi.d.ts +66 -0
- package/dist/tbv/core/contracts/abis/ApplicationRegistry.abi.d.ts.map +1 -1
- package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts +50 -0
- package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts.map +1 -1
- package/dist/tbv/core/contracts/abis/BTCVaultRegistryKeyEpochs.abi.d.ts +111 -0
- package/dist/tbv/core/contracts/abis/BTCVaultRegistryKeyEpochs.abi.d.ts.map +1 -0
- package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts +36 -0
- package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts.map +1 -1
- package/dist/tbv/core/contracts/index.cjs +1 -1
- package/dist/tbv/core/contracts/index.d.ts +2 -1
- package/dist/tbv/core/contracts/index.d.ts.map +1 -1
- package/dist/tbv/core/contracts/index.js +8 -6
- package/dist/tbv/core/contracts/index.js.map +1 -1
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.js +183 -172
- package/dist/tbv/core/index.js.map +1 -1
- package/dist/tbv/core/managers/PayoutManager.d.ts +8 -0
- package/dist/tbv/core/managers/PayoutManager.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/primitives/index.cjs +1 -1
- package/dist/tbv/core/primitives/index.js +2 -2
- package/dist/tbv/core/primitives/psbt/__tests__/standardPayoutScript.test.d.ts +2 -0
- package/dist/tbv/core/primitives/psbt/__tests__/standardPayoutScript.test.d.ts.map +1 -0
- package/dist/tbv/core/primitives/psbt/assertPayoutFeeBand.d.ts +5 -5
- package/dist/tbv/core/primitives/psbt/assertPayoutFeeBand.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/payout.d.ts +23 -0
- package/dist/tbv/core/primitives/psbt/payout.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/standardPayoutScript.d.ts +41 -0
- package/dist/tbv/core/primitives/psbt/standardPayoutScript.d.ts.map +1 -0
- package/dist/tbv/core/services/deposit/__tests__/verifyRegisteredParticipantKeys.test.d.ts +2 -0
- package/dist/tbv/core/services/deposit/__tests__/verifyRegisteredParticipantKeys.test.d.ts.map +1 -0
- package/dist/tbv/core/services/deposit/index.d.ts +7 -6
- package/dist/tbv/core/services/deposit/index.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts +10 -0
- package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts +9 -0
- package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/validateOnChainParticipantKeys.d.ts +38 -1
- package/dist/tbv/core/services/deposit/validateOnChainParticipantKeys.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/verifyRegisteredParticipantKeys.d.ts +42 -0
- package/dist/tbv/core/services/deposit/verifyRegisteredParticipantKeys.d.ts.map +1 -0
- package/dist/tbv/core/services/index.cjs +1 -1
- package/dist/tbv/core/services/index.d.ts +1 -0
- package/dist/tbv/core/services/index.d.ts.map +1 -1
- package/dist/tbv/core/services/index.js +36 -31
- package/dist/tbv/core/services/participants/__tests__/fixtures/rotation.d.ts +55 -0
- package/dist/tbv/core/services/participants/__tests__/fixtures/rotation.d.ts.map +1 -0
- package/dist/tbv/core/services/participants/__tests__/resolveParticipantKeys.test.d.ts +2 -0
- package/dist/tbv/core/services/participants/__tests__/resolveParticipantKeys.test.d.ts.map +1 -0
- package/dist/tbv/core/services/participants/index.d.ts +8 -0
- package/dist/tbv/core/services/participants/index.d.ts.map +1 -0
- package/dist/tbv/core/services/participants/resolveParticipantKeys.d.ts +26 -0
- package/dist/tbv/core/services/participants/resolveParticipantKeys.d.ts.map +1 -0
- package/dist/tbv/core/services/participants/types.d.ts +62 -0
- package/dist/tbv/core/services/participants/types.d.ts.map +1 -0
- package/dist/tbv/core/utils/__tests__/abortSignals.test.d.ts +11 -0
- package/dist/tbv/core/utils/__tests__/abortSignals.test.d.ts.map +1 -0
- package/dist/tbv/core/utils/abortSignals.d.ts +23 -0
- package/dist/tbv/core/utils/abortSignals.d.ts.map +1 -0
- package/dist/tbv/core/utils/index.cjs +1 -1
- package/dist/tbv/core/utils/index.d.ts +1 -0
- package/dist/tbv/core/utils/index.d.ts.map +1 -1
- package/dist/tbv/core/utils/index.js +44 -43
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +183 -172
- package/dist/tbv/index.js.map +1 -1
- package/dist/validation-CDbOaDj7.cjs +2 -0
- package/dist/validation-CDbOaDj7.cjs.map +1 -0
- package/dist/validation-Dj3dqYtl.js +30 -0
- package/dist/validation-Dj3dqYtl.js.map +1 -0
- package/dist/verifyScriptPathSchnorrSignature-C-84KJ6U.cjs +2 -0
- package/dist/verifyScriptPathSchnorrSignature-C-84KJ6U.cjs.map +1 -0
- package/dist/{verifyScriptPathSchnorrSignature-CgrnAjMW.js → verifyScriptPathSchnorrSignature-Xoo9DOHW.js} +359 -301
- package/dist/verifyScriptPathSchnorrSignature-Xoo9DOHW.js.map +1 -0
- package/package.json +3 -3
- package/dist/ApplicationRegistry.abi-CLaa6E99.cjs +0 -2
- package/dist/ApplicationRegistry.abi-CLaa6E99.cjs.map +0 -1
- package/dist/ApplicationRegistry.abi-w5prf7Ig.js.map +0 -1
- package/dist/BTCVaultRegistry.abi-Chs4AFBj.js.map +0 -1
- package/dist/BTCVaultRegistry.abi-JdeqLz4x.cjs +0 -2
- package/dist/BTCVaultRegistry.abi-JdeqLz4x.cjs.map +0 -1
- package/dist/PayoutManager-BVgmuKuK.js.map +0 -1
- package/dist/PayoutManager-Cu4_l-_Y.cjs +0 -2
- package/dist/PayoutManager-Cu4_l-_Y.cjs.map +0 -1
- package/dist/PeginManager-BkWdZI7P.cjs +0 -2
- package/dist/buildAndBroadcastRefund-BtXUqBkb.js.map +0 -1
- package/dist/buildAndBroadcastRefund-Cq01wyZX.cjs +0 -2
- package/dist/buildAndBroadcastRefund-Cq01wyZX.cjs.map +0 -1
- package/dist/mempoolApi-P_ApODLd.js +0 -483
- package/dist/mempoolApi-P_ApODLd.js.map +0 -1
- package/dist/mempoolApi-emec8bHK.cjs +0 -2
- package/dist/mempoolApi-emec8bHK.cjs.map +0 -1
- package/dist/primeVpAuth-DZOaC_Ui.js.map +0 -1
- package/dist/primeVpAuth-j2getl3f.cjs +0 -2
- package/dist/primeVpAuth-j2getl3f.cjs.map +0 -1
- package/dist/types-CQDRQvV-.js.map +0 -1
- package/dist/types-WA0LrDk1.cjs.map +0 -1
- package/dist/validation-CxqROCno.js +0 -15
- package/dist/validation-CxqROCno.js.map +0 -1
- package/dist/validation-u8W7Lp2x.cjs +0 -2
- package/dist/validation-u8W7Lp2x.cjs.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-BZhX-SOd.cjs +0 -2
- package/dist/verifyScriptPathSchnorrSignature-BZhX-SOd.cjs.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-CgrnAjMW.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const a=require("./BTCVaultRegistry.abi-AUAyCHal.cjs"),b=require("./BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs"),I=require("./onChainBtcPubkey-Cd9kpz-S.cjs"),k=require("./constants-BqU1Uz15.cjs"),u=require("./validation-CDbOaDj7.cjs"),g=65535,P=1e4,f=4294967295,y=255;function p(t){if(!Number.isInteger(t)||t<0||t>f)throw new Error(`Invalid offchainParamsVersion from contract: must be a uint32, got ${t}`)}function A(t){const e=[];if(t.timelockAssert<=0n&&e.push(`timelockAssert must be positive, got ${t.timelockAssert}`),t.timelockAssert>BigInt(g)&&e.push(`timelockAssert ${t.timelockAssert} exceeds uint16 max (${g})`),t.timelockChallengeAssert<=0n&&e.push(`timelockChallengeAssert must be positive, got ${t.timelockChallengeAssert}`),t.tRefund<=0&&e.push(`tRefund must be positive, got ${t.tRefund}`),t.tStale<=0&&e.push(`tStale must be positive, got ${t.tStale}`),t.securityCouncilKeys.length===0&&e.push("securityCouncilKeys must not be empty"),t.councilQuorum<=0&&e.push(`councilQuorum must be positive, got ${t.councilQuorum}`),t.councilQuorum>t.securityCouncilKeys.length&&e.push(`councilQuorum (${t.councilQuorum}) exceeds securityCouncilKeys count (${t.securityCouncilKeys.length})`),t.feeRate<=0n&&e.push(`feeRate must be positive, got ${t.feeRate}`),t.minPeginFeeRate<=0n&&e.push(`minPeginFeeRate must be positive, got ${t.minPeginFeeRate}`),(!Number.isInteger(t.proverCircuitVersion)||t.proverCircuitVersion<0||t.proverCircuitVersion>g)&&e.push(`proverCircuitVersion must be a uint16, got ${t.proverCircuitVersion}`),(!Number.isInteger(t.minPrepeginDepth)||t.minPrepeginDepth<=0||t.minPrepeginDepth>f)&&e.push(`minPrepeginDepth must be a uint32 in [1, ${f}], got ${t.minPrepeginDepth}`),t.babeTotalInstances<=0&&e.push(`babeTotalInstances must be positive, got ${t.babeTotalInstances}`),t.babeInstancesToFinalize<=0&&e.push(`babeInstancesToFinalize must be positive, got ${t.babeInstancesToFinalize}`),t.babeInstancesToFinalize>t.babeTotalInstances&&e.push(`babeInstancesToFinalize (${t.babeInstancesToFinalize}) exceeds babeTotalInstances (${t.babeTotalInstances})`),(t.minVpCommissionBps<0||t.minVpCommissionBps>P)&&e.push(`minVpCommissionBps must be in [0, ${P}], got ${t.minVpCommissionBps}`),e.length>0)throw new Error(`Invalid offchain protocol parameters: ${e.join("; ")}`)}function E(t){const e=[];if(t.minimumPegInAmount<=0n&&e.push(`minimumPegInAmount must be positive, got ${t.minimumPegInAmount}`),t.maxPegInAmount<t.minimumPegInAmount&&e.push(`maxPegInAmount (${t.maxPegInAmount}) must be >= minimumPegInAmount (${t.minimumPegInAmount})`),t.pegInAckTimeout<=0n&&e.push(`pegInAckTimeout must be positive, got ${t.pegInAckTimeout}`),t.pegInActivationTimeout<=0n&&e.push(`pegInActivationTimeout must be positive, got ${t.pegInActivationTimeout}`),(!Number.isInteger(t.maxHtlcOutputCount)||t.maxHtlcOutputCount<=0||t.maxHtlcOutputCount>y)&&e.push(`maxHtlcOutputCount must be an integer in [1, ${y}], got ${t.maxHtlcOutputCount}`),(typeof t.expiredPegInGraceBlocks!="bigint"||t.expiredPegInGraceBlocks<=0n)&&e.push(`expiredPegInGraceBlocks must be a positive bigint, got ${t.expiredPegInGraceBlocks}`),e.length>0)throw new Error(`Invalid TBV protocol parameters: ${e.join("; ")}`)}function O(t){if(E(t),A(t.offchainParams),!Number.isInteger(t.offchainParamsVersion)||t.offchainParamsVersion<0||t.offchainParamsVersion>f)throw new Error(`Invalid peg-in configuration: offchainParamsVersion must be a uint32, got ${t.offchainParamsVersion}`);k.assertValidVaultCoreVersion(t.activeVaultCoreVersion,"ProtocolParams.activeVaultCoreVersion()")}const $=9999;function V(t){return{depositor:t.depositor,depositorBtcPubKey:t.depositorBtcPubKey,amount:t.amount,vaultProvider:t.vaultProvider,status:t.status,applicationEntryPoint:t.applicationEntryPoint,createdAt:t.createdAt}}function m(t){const e=Number(t.offchainParamsVersion);return p(e),{depositorSignedPeginTx:t.depositorSignedPeginTx,universalChallengersVersion:t.universalChallengersVersion,appVaultKeepersVersion:t.appVaultKeepersVersion,offchainParamsVersion:e,verifiedAt:t.verifiedAt,depositorWotsPkHash:t.depositorWotsPkHash,hashlock:t.hashlock,htlcVout:t.htlcVout,depositorPopSignature:t.depositorPopSignature,prePeginTxHash:t.prePeginTxHash,vaultProviderCommissionBps:t.vaultProviderCommissionBps,claimExpiredUntil:t.claimExpiredUntil,vaultCoreVersion:t.vaultCoreVersion}}const N=1n<<64n;function d(t,e,o){if(t<0n||t>=N)throw new Error(`getBtcVaultProtocolInfo returned ${e}=${t} for vault ${o}, outside the uint64 range — the registry may predate RFC-006`);return t}function T(t,e){return{vpKeyEpoch:d(t.vpKeyEpoch,"vpKeyEpoch",e),appKeeperKeyEpoch:d(t.appKeeperKeyEpoch,"appKeeperKeyEpoch",e),ucKeyEpoch:d(t.ucKeyEpoch,"ucKeyEpoch",e)}}class S{constructor(e,o){this.publicClient=e,this.contractAddress=o}async getVaultProviderBtcPubKey(e){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getVaultProviderBTCKey",args:[e]});return I.assertOnChainBtcPubkey(o,`getVaultProviderBTCKey (vp=${e})`)}async getCurrentVaultProviderOperationBtcKey(e){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getCurrentOperationBtcKey",args:[e]});return I.assertOnChainBtcPubkey(o,`getCurrentOperationBtcKey (vp=${e})`)}async getVaultKeyEpochs(e){const o=await this.publicClient.readContract({address:this.contractAddress,abi:b.BTCVaultRegistryKeyEpochsABI,functionName:"getBtcVaultProtocolInfo",args:[e]});return T(o,e)}async getVaultKeyEpochsBatch(e){return e.length===0?[]:(await this.publicClient.multicall({contracts:e.map(n=>({address:this.contractAddress,abi:b.BTCVaultRegistryKeyEpochsABI,functionName:"getBtcVaultProtocolInfo",args:[n]})),allowFailure:!1})).map((n,i)=>T(n,e[i]))}async getVaultBasicInfo(e){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[e]});return V(o)}async getVaultProtocolInfo(e){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[e]});return m(o)}async getProtocolInfoBatch(e){return e.length===0?[]:(await this.publicClient.multicall({contracts:e.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 ${e[i]} not found on-chain or has no pegin transaction`);return m(r)})}async getPegInFee(e){return await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getPegInFee",args:[e]})}async getVaultProviderCommission(e){const o=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getVaultProviderCommission",args:[e]});if(!Number.isInteger(o)||o<0||o>$)throw new Error(`getVaultProviderCommission returned ${o} bps for ${e}, outside the protocol range [0, ${$}]`);return o}async getVaultData(e){const[o,n]=await this.publicClient.multicall({contracts:[{address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[e]},{address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[e]}],allowFailure:!1}),i=V(o),r=m(n);if(!r.depositorSignedPeginTx||r.depositorSignedPeginTx==="0x")throw new Error(`Vault ${e} not found on-chain or has no pegin transaction`);return{basic:i,protocol:r}}async getOffchainParamsVersionsByVaultIds(e){return e.length===0?[]:(await this.publicClient.multicall({contracts:e.map(n=>({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[n]})),allowFailure:!1})).map(n=>{const i=n;if(!i.depositorSignedPeginTx||i.depositorSignedPeginTx==="0x")throw new Error("Vault not found on-chain or has no pegin transaction while reading offchain params version");const r=Number(i.offchainParamsVersion);return p(r),r})}}const U=21e6*1e8,C=3e4;async function h(t,e){const o=new AbortController,n=setTimeout(()=>o.abort(),C),i=[o.signal,e==null?void 0:e.signal].filter(Boolean),r=u.combineAbortSignals(i);try{return await fetch(t,{...e,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 ${C}ms: ${t}`):s}}const B=1e4;function v(t){return Number.isInteger(t)&&t>0&&t<=U}function _(t){return Number.isInteger(t)&&t>0&&t<=B}function w(t,e){return!Number.isInteger(t)||t<0?!1:e===void 0||t<e}function l(t){if(!u.TXID_RE.test(t))throw new Error(`Invalid transaction ID format: ${t}`)}function x(t){if(!u.BITCOIN_ADDRESS_RE.test(t))throw new Error(`Invalid Bitcoin address format: ${t}`)}function F(t,e){if(!u.HEX_RE.test(t))throw new Error(`Invalid scriptPubKey: not valid hex for ${e}`);if(!u.KNOWN_SCRIPT_PREFIXES.some(n=>t.toLowerCase().startsWith(n)))throw new Error(`Unrecognized scriptPubKey type for ${e}: prefix ${t.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(t,e){try{const o=await h(t,e);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 M(t,e){try{const o=await h(`${e}/tx`,{method:"POST",body:t,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 K(t,e){return l(t),c(`${e}/tx/${t}`)}async function H(t){const e=await c(`${t}/blocks/tip/height`),o=e.trim();if(!/^\d+$/.test(o))throw new Error(`Mempool API returned an invalid block tip height: "${e}"`);return Number.parseInt(o,10)}async function X(t,e,o){if(l(t),!w(e))throw new Error(`Invalid vout ${e} for transaction ${t}`);return c(`${o}/tx/${t}/outspend/${e}`)}async function D(t,e){l(t);try{const o=await h(`${e}/tx/${t}/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 ${t}: ${o.message}`):new Error(`Failed to get transaction hex for ${t}: Unknown error`)}}async function z(t,e,o){l(t);const n=await K(t,o);if(!w(e,n.vout.length))throw new Error(`Invalid vout ${e} for transaction ${t} (has ${n.vout.length} outputs)`);const i=n.vout[e];if(!v(i.value))throw new Error(`Invalid UTXO value ${i.value} for ${t}:${e}`);return F(i.scriptpubkey,`${t}:${e}`),{txid:t,vout:e,value:i.value,scriptPubKey:i.scriptpubkey}}async function L(t,e){x(t);try{const o=await c(`${e}/address/${t}/utxo`),n=await c(`${e}/v1/validate-address/${t}`);if(!n.isvalid)throw new Error(`Invalid Bitcoin address: ${t}. Mempool API validation failed.`);F(n.scriptPubKey,t);for(const r of o){if(l(r.txid),!w(r.vout))throw new Error(`Invalid vout ${r.vout} for ${r.txid}`);if(!v(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 ${t}: ${o.message}`):new Error(`Failed to get UTXOs for address ${t}: Unknown error`)}}function Q(t){return R[t]}async function j(t,e){return x(t),c(`${e}/address/${t}/txs`)}async function q(t){const e=await h(`${t}/v1/fees/recommended`);if(!e.ok)throw new Error(`Failed to fetch network fees: ${e.status} ${e.statusText}`);const o=await e.json(),n=["fastestFee","halfHourFee","hourFee","economyFee","minimumFee"];for(const i of n)if(!_(o[i]))throw new Error(`Invalid fee rate ${i}=${o[i]} from mempool API: expected a positive number ≤ ${B}`);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=S;exports.assertValidOffchainParamsVersion=p;exports.getAddressTxs=j;exports.getAddressUtxos=L;exports.getMempoolApiUrl=Q;exports.getNetworkFees=q;exports.getOutspend=X;exports.getTipHeight=H;exports.getTxHex=D;exports.getTxInfo=K;exports.getUtxoInfo=z;exports.pushTx=M;exports.validateOffchainParams=A;exports.validatePegInConfiguration=O;exports.validateTBVProtocolParams=E;
|
|
2
|
+
//# sourceMappingURL=mempoolApi-Dsm2VPXp.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mempoolApi-Dsm2VPXp.cjs","sources":["../src/tbv/core/clients/eth/protocol-params-validation.ts","../src/tbv/core/clients/eth/vault-registry-reader.ts","../src/tbv/core/clients/mempool/mempoolApi.ts"],"sourcesContent":["/**\n * Validation for protocol parameters fetched from the ProtocolParams contract.\n *\n * These values feed Bitcoin script construction and deposit validation.\n * Invalid params must be caught before they reach transaction-building code,\n * since errors after wallet signing prompts are unrecoverable.\n *\n * The {@link ViemProtocolParamsReader} runs these on every read; consumers\n * implementing their own reader against the same `ProtocolParamsReader`\n * interface should call them too.\n */\n\nimport { assertValidVaultCoreVersion } from \"../../primitives/vaultCoreVersion\";\n\nimport type {\n PegInConfiguration,\n TBVProtocolParams,\n VersionedOffchainParams,\n} from \"./types\";\n\n/**\n * Maximum value for a Solidity uint16.\n * PeginLogic.sol casts timelockAssert to uint16, so values above this are invalid.\n */\nconst UINT16_MAX = 65535;\n\n/** Maximum valid value for basis points (100%) */\nconst MAX_BASIS_POINTS = 10000;\n\n/** Maximum value for a Solidity uint32. */\nconst UINT32_MAX = 4_294_967_295;\n\n/** Maximum valid value for a uint8 (e.g. maxHtlcOutputCount). */\nconst UINT8_MAX = 255;\n\n/**\n * Validate an `offchainParamsVersion` value sourced from a contract read.\n * `Number()` on a malformed payload yields `NaN` or a non-integer; both\n * silently break consumers that loop `1..version` or use the value as a\n * map key. Used by reader entry points that surface the version to JS.\n */\nexport function assertValidOffchainParamsVersion(version: number): void {\n if (\n !Number.isInteger(version) ||\n version < 0 ||\n version > UINT32_MAX\n ) {\n throw new Error(\n `Invalid offchainParamsVersion from contract: must be a uint32, got ${version}`,\n );\n }\n}\n\n/**\n * Validate offchain params consistency and bounds.\n * @throws Error on invalid values to prevent constructing invalid Bitcoin scripts.\n */\nexport function validateOffchainParams(params: VersionedOffchainParams): void {\n const errors: string[] = [];\n\n if (params.timelockAssert <= 0n) {\n errors.push(\n `timelockAssert must be positive, got ${params.timelockAssert}`,\n );\n }\n if (params.timelockAssert > BigInt(UINT16_MAX)) {\n errors.push(\n `timelockAssert ${params.timelockAssert} exceeds uint16 max (${UINT16_MAX})`,\n );\n }\n\n if (params.timelockChallengeAssert <= 0n) {\n errors.push(\n `timelockChallengeAssert must be positive, got ${params.timelockChallengeAssert}`,\n );\n }\n\n if (params.tRefund <= 0) {\n errors.push(`tRefund must be positive, got ${params.tRefund}`);\n }\n\n if (params.tStale <= 0) {\n errors.push(`tStale must be positive, got ${params.tStale}`);\n }\n\n if (params.securityCouncilKeys.length === 0) {\n errors.push(\"securityCouncilKeys must not be empty\");\n }\n\n if (params.councilQuorum <= 0) {\n errors.push(`councilQuorum must be positive, got ${params.councilQuorum}`);\n }\n if (params.councilQuorum > params.securityCouncilKeys.length) {\n errors.push(\n `councilQuorum (${params.councilQuorum}) exceeds securityCouncilKeys count (${params.securityCouncilKeys.length})`,\n );\n }\n\n if (params.feeRate <= 0n) {\n errors.push(`feeRate must be positive, got ${params.feeRate}`);\n }\n\n if (params.minPeginFeeRate <= 0n) {\n errors.push(\n `minPeginFeeRate must be positive, got ${params.minPeginFeeRate}`,\n );\n }\n\n if (\n !Number.isInteger(params.proverCircuitVersion) ||\n params.proverCircuitVersion < 0 ||\n params.proverCircuitVersion > UINT16_MAX\n ) {\n errors.push(\n `proverCircuitVersion must be a uint16, got ${params.proverCircuitVersion}`,\n );\n }\n\n if (\n !Number.isInteger(params.minPrepeginDepth) ||\n params.minPrepeginDepth <= 0 ||\n params.minPrepeginDepth > UINT32_MAX\n ) {\n errors.push(\n `minPrepeginDepth must be a uint32 in [1, ${UINT32_MAX}], got ${params.minPrepeginDepth}`,\n );\n }\n\n if (params.babeTotalInstances <= 0) {\n errors.push(\n `babeTotalInstances must be positive, got ${params.babeTotalInstances}`,\n );\n }\n if (params.babeInstancesToFinalize <= 0) {\n errors.push(\n `babeInstancesToFinalize must be positive, got ${params.babeInstancesToFinalize}`,\n );\n }\n if (params.babeInstancesToFinalize > params.babeTotalInstances) {\n errors.push(\n `babeInstancesToFinalize (${params.babeInstancesToFinalize}) exceeds babeTotalInstances (${params.babeTotalInstances})`,\n );\n }\n\n if (\n params.minVpCommissionBps < 0 ||\n params.minVpCommissionBps > MAX_BASIS_POINTS\n ) {\n errors.push(\n `minVpCommissionBps must be in [0, ${MAX_BASIS_POINTS}], got ${params.minVpCommissionBps}`,\n );\n }\n\n if (errors.length > 0) {\n throw new Error(\n `Invalid offchain protocol parameters: ${errors.join(\"; \")}`,\n );\n }\n}\n\n/**\n * Validate TBV protocol params returned from the contract.\n * @throws Error on invalid amounts or out-of-range bounded fields.\n */\nexport function validateTBVProtocolParams(params: TBVProtocolParams): void {\n const errors: string[] = [];\n\n if (params.minimumPegInAmount <= 0n) {\n errors.push(\n `minimumPegInAmount must be positive, got ${params.minimumPegInAmount}`,\n );\n }\n\n if (params.maxPegInAmount < params.minimumPegInAmount) {\n errors.push(\n `maxPegInAmount (${params.maxPegInAmount}) must be >= minimumPegInAmount (${params.minimumPegInAmount})`,\n );\n }\n\n if (params.pegInAckTimeout <= 0n) {\n errors.push(\n `pegInAckTimeout must be positive, got ${params.pegInAckTimeout}`,\n );\n }\n\n if (params.pegInActivationTimeout <= 0n) {\n errors.push(\n `pegInActivationTimeout must be positive, got ${params.pegInActivationTimeout}`,\n );\n }\n\n if (\n !Number.isInteger(params.maxHtlcOutputCount) ||\n params.maxHtlcOutputCount <= 0 ||\n params.maxHtlcOutputCount > UINT8_MAX\n ) {\n errors.push(\n `maxHtlcOutputCount must be an integer in [1, ${UINT8_MAX}], got ${params.maxHtlcOutputCount}`,\n );\n }\n\n if (\n typeof params.expiredPegInGraceBlocks !== \"bigint\" ||\n params.expiredPegInGraceBlocks <= 0n\n ) {\n errors.push(\n `expiredPegInGraceBlocks must be a positive bigint, got ${params.expiredPegInGraceBlocks}`,\n );\n }\n\n if (errors.length > 0) {\n throw new Error(`Invalid TBV protocol parameters: ${errors.join(\"; \")}`);\n }\n}\n\n/**\n * Validate the full peg-in configuration after assembly.\n * Checks both TBV params and offchain params consistency, and the\n * top-level `offchainParamsVersion` (which originates from a separate\n * multicall result and so must be range-checked alongside the params it\n * names).\n */\nexport function validatePegInConfiguration(config: PegInConfiguration): void {\n validateTBVProtocolParams(config);\n validateOffchainParams(config.offchainParams);\n\n if (\n !Number.isInteger(config.offchainParamsVersion) ||\n config.offchainParamsVersion < 0 ||\n config.offchainParamsVersion > UINT32_MAX\n ) {\n throw new Error(\n `Invalid peg-in configuration: offchainParamsVersion must be a uint32, got ${config.offchainParamsVersion}`,\n );\n }\n\n // The contract enforces ≥ 1 (setter rejects 0); a 0 here means a\n // mis-decoded read or a pre-vaultCoreVersion contract — fail closed.\n assertValidVaultCoreVersion(\n config.activeVaultCoreVersion,\n \"ProtocolParams.activeVaultCoreVersion()\",\n );\n}\n","/**\n * Concrete BTCVaultRegistry reader using viem's readContract.\n *\n * This is an optional utility — callers can use their own implementation\n * of the VaultRegistryReader interface.\n */\n\nimport type { Abi, Address, Hex, PublicClient } from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\nimport { BTCVaultRegistryKeyEpochsABI } from \"../../contracts/abis/BTCVaultRegistryKeyEpochs.abi\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\nimport { assertValidOffchainParamsVersion } from \"./protocol-params-validation\";\nimport type {\n KeyEpochs,\n OnChainBtcPubkey,\n VaultBasicInfo,\n VaultData,\n VaultProtocolInfo,\n VaultRegistryReader,\n} from \"./types\";\n\n/**\n * Inclusive upper bound the BTCVaultRegistry contract enforces on a vault\n * provider's commission (the contract check is `< 10000`).\n */\nconst MAX_VP_COMMISSION_BPS = 9999;\n\n/** Raw `getBtcVaultBasicInfo` tuple as decoded by viem. */\ntype RawVaultBasicInfo = {\n depositor: Address;\n depositorBtcPubKey: Hex;\n amount: bigint;\n vaultProvider: Address;\n status: number;\n applicationEntryPoint: Address;\n createdAt: bigint;\n};\n\n/** Raw `getBtcVaultProtocolInfo` tuple as decoded by viem. */\ntype RawVaultProtocolInfo = {\n depositorSignedPeginTx: Hex;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n offchainParamsVersion: number;\n verifiedAt: bigint;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n depositorPopSignature: Hex;\n prePeginTxHash: Hex;\n vaultProviderCommissionBps: number;\n claimExpiredUntil: bigint;\n vaultCoreVersion: number;\n};\n\nfunction mapVaultBasicInfo(result: RawVaultBasicInfo): VaultBasicInfo {\n return {\n depositor: result.depositor,\n depositorBtcPubKey: result.depositorBtcPubKey,\n amount: result.amount,\n vaultProvider: result.vaultProvider,\n status: result.status,\n applicationEntryPoint: result.applicationEntryPoint,\n createdAt: result.createdAt,\n };\n}\n\nfunction mapVaultProtocolInfo(result: RawVaultProtocolInfo): VaultProtocolInfo {\n const offchainParamsVersion = Number(result.offchainParamsVersion);\n assertValidOffchainParamsVersion(offchainParamsVersion);\n return {\n depositorSignedPeginTx: result.depositorSignedPeginTx,\n universalChallengersVersion: result.universalChallengersVersion,\n appVaultKeepersVersion: result.appVaultKeepersVersion,\n offchainParamsVersion,\n verifiedAt: result.verifiedAt,\n depositorWotsPkHash: result.depositorWotsPkHash,\n hashlock: result.hashlock,\n htlcVout: result.htlcVout,\n depositorPopSignature: result.depositorPopSignature,\n prePeginTxHash: result.prePeginTxHash,\n vaultProviderCommissionBps: result.vaultProviderCommissionBps,\n claimExpiredUntil: result.claimExpiredUntil,\n vaultCoreVersion: result.vaultCoreVersion,\n };\n}\n\n/**\n * Exclusive upper bound for a `uint64` epoch.\n *\n * viem does not range-check a decoded `uint64`, so a misaligned decode can\n * hand back a value far larger than the field can hold. Rejecting those is\n * cheap defence in depth against reading the extended ABI on a registry that\n * predates RFC-006 — but it is only a backstop, and a weak one: a misaligned\n * decode can also land on a small, plausible-looking integer that this range\n * accepts. Correctness rests on only ever pointing at an RFC-006 registry.\n * See `BTCVaultRegistryKeyEpochs.abi.ts`.\n */\nconst UINT64_EXCLUSIVE_UPPER_BOUND = 1n << 64n;\n\nfunction assertEpochInRange(\n value: bigint,\n field: string,\n vaultId: Hex,\n): bigint {\n if (value < 0n || value >= UINT64_EXCLUSIVE_UPPER_BOUND) {\n throw new Error(\n `getBtcVaultProtocolInfo returned ${field}=${value} for vault ${vaultId}, ` +\n `outside the uint64 range — the registry may predate RFC-006`,\n );\n }\n return value;\n}\n\nfunction mapKeyEpochs(result: KeyEpochs, vaultId: Hex): KeyEpochs {\n return {\n vpKeyEpoch: assertEpochInRange(result.vpKeyEpoch, \"vpKeyEpoch\", vaultId),\n appKeeperKeyEpoch: assertEpochInRange(\n result.appKeeperKeyEpoch,\n \"appKeeperKeyEpoch\",\n vaultId,\n ),\n ucKeyEpoch: assertEpochInRange(result.ucKeyEpoch, \"ucKeyEpoch\", vaultId),\n };\n}\n\n/**\n * Concrete vault registry reader using viem.\n *\n * Usage:\n * ```ts\n * const reader = new ViemVaultRegistryReader(publicClient, registryAddress);\n * const data = await reader.getVaultData(vaultId);\n * ```\n */\nexport class ViemVaultRegistryReader implements VaultRegistryReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n /**\n * Read the VP's persistent x-only BTC pubkey from the on-chain\n * registry. Validates length, hex form, and secp256k1 curve\n * membership before minting the brand. Returns 64-char lowercase\n * hex without the `0x` prefix.\n */\n async getVaultProviderBtcPubKey(\n vpAddress: Address,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderBTCKey\",\n args: [vpAddress],\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getVaultProviderBTCKey (vp=${vpAddress})`,\n );\n }\n\n /**\n * Read a vault provider's *current* RFC-006 operation BTC key.\n *\n * Falls back on-chain to the registration key when the provider has never\n * rotated, so this returns the same value as `getVaultProviderBtcPubKey`\n * until the first rotation.\n *\n * This is the key the VP's server signs its BIP-322 auth tokens with — a\n * live per-operator identity, not a per-vault binding, so the auth pin uses\n * the current key rather than any vault's frozen epoch.\n */\n async getCurrentVaultProviderOperationBtcKey(\n vpAddress: Address,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getCurrentOperationBtcKey\",\n args: [vpAddress],\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getCurrentOperationBtcKey (vp=${vpAddress})`,\n );\n }\n\n /**\n * Read a vault's frozen RFC-006 operation-key epochs.\n *\n * Reads `getBtcVaultProtocolInfo` through the **extended** ABI, which is only\n * valid against an RFC-006 registry: against one that predates RFC-006 this\n * call does not fail for a populated vault, it silently returns three words\n * of tail data as epochs. Nothing here can detect that, so the guarantee is a\n * deployment one — every network this ships to has the RFC-006 getters, and\n * mainnet is a fresh RFC-006 deploy. See `BTCVaultRegistryKeyEpochs.abi.ts`.\n */\n async getVaultKeyEpochs(vaultId: Hex): Promise<KeyEpochs> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as unknown as KeyEpochs;\n\n return mapKeyEpochs(result, vaultId);\n }\n\n async getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) =>\n mapKeyEpochs(info as unknown as KeyEpochs, vaultIds[i]),\n );\n }\n\n async getVaultBasicInfo(vaultId: Hex): Promise<VaultBasicInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as RawVaultBasicInfo;\n\n return mapVaultBasicInfo(result);\n }\n\n async getVaultProtocolInfo(vaultId: Hex): Promise<VaultProtocolInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultProtocolInfo;\n\n return mapVaultProtocolInfo(result);\n }\n\n async getProtocolInfoBatch(\n vaultIds: readonly Hex[],\n ): Promise<VaultProtocolInfo[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) => {\n const result = info as unknown as RawVaultProtocolInfo;\n if (\n !result.depositorSignedPeginTx ||\n result.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(\n `Vault ${vaultIds[i]} not found on-chain or has no pegin transaction`,\n );\n }\n return mapVaultProtocolInfo(result);\n });\n }\n\n /**\n * Read the protocol pegin fee (in wei) for a given vault provider.\n * Mirrors the `getPegInFee(address)` view on BTCVaultRegistry.\n */\n async getPegInFee(vaultProvider: Address): Promise<bigint> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n }\n\n /**\n * Read a vault provider's current commission in basis points from\n * BTCVaultRegistry. The contract enforces `commissionBps < 10000`, so the\n * legitimate range is `[0, 9999]`; anything outside indicates a wrong\n * contract address or ABI drift and is surfaced as an error rather than\n * trusted.\n */\n async getVaultProviderCommission(vaultProvider: Address): Promise<number> {\n // viem infers `number` from the `uint16` return in the `as const` ABI.\n const bps = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderCommission\",\n args: [vaultProvider],\n });\n\n if (!Number.isInteger(bps) || bps < 0 || bps > MAX_VP_COMMISSION_BPS) {\n throw new Error(\n `getVaultProviderCommission returned ${bps} bps for ${vaultProvider}, ` +\n `outside the protocol range [0, ${MAX_VP_COMMISSION_BPS}]`,\n );\n }\n\n return bps;\n }\n\n async getVaultData(vaultId: Hex): Promise<VaultData> {\n // One round-trip for both structs (hard-fail): they feed signing/refund/\n // broadcast rebinds, so reading them in a single multicall also pins both\n // to the same block — no basic/protocol skew across two `eth_call`s.\n const [basicRaw, protocolRaw] = await this.publicClient.multicall({\n contracts: [\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n },\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n },\n ],\n allowFailure: false,\n });\n\n const basic = mapVaultBasicInfo(basicRaw);\n const protocol = mapVaultProtocolInfo(protocolRaw);\n\n if (\n !protocol.depositorSignedPeginTx ||\n protocol.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(\n `Vault ${vaultId} not found on-chain or has no pegin transaction`,\n );\n }\n\n return { basic, protocol };\n }\n\n /**\n * Read `offchainParamsVersion` for many vaults in a single multicall.\n * Reads only `getBtcVaultProtocolInfo` (one read per vault), so an N-vault\n * batch costs one RPC round-trip instead of 2N parallel `eth_call`s.\n */\n async getOffchainParamsVersionsByVaultIds(\n vaultIds: readonly Hex[],\n ): Promise<number[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info) => {\n const protocolInfo = info as unknown as VaultProtocolInfo;\n if (\n !protocolInfo.depositorSignedPeginTx ||\n protocolInfo.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(\n \"Vault not found on-chain or has no pegin transaction while reading offchain params version\",\n );\n }\n const version = Number(protocolInfo.offchainParamsVersion);\n assertValidOffchainParamsVersion(version);\n return version;\n });\n }\n}\n","/**\n * Mempool API Client\n *\n * Client for interacting with mempool.space API for Bitcoin network operations.\n * Used for broadcasting transactions and fetching UTXO data.\n *\n * @module clients/mempool/mempoolApi\n */\n\nimport { combineAbortSignals } from \"../../utils/abortSignals\";\nimport {\n BITCOIN_ADDRESS_RE,\n HEX_RE,\n KNOWN_SCRIPT_PREFIXES,\n TXID_RE,\n} from \"../../utils/validation\";\n\nimport type {\n MempoolUTXO,\n NetworkFees,\n OutspendStatus,\n TxInfo,\n UtxoInfo,\n} from \"./types\";\n\n/** Maximum valid satoshi value: 21 million BTC × 10^8 sats/BTC */\nconst MAX_SATOSHIS = 21_000_000 * 1e8;\n\n/** Timeout for mempool API requests — prevents indefinite hangs from stalled endpoints */\nconst MEMPOOL_REQUEST_TIMEOUT_MS = 30_000;\n\n/**\n * Fetch wrapper with AbortController-based timeout.\n * Ensures all mempool API requests fail bounded rather than hanging indefinitely.\n */\nasync function fetchWithTimeout(\n url: string,\n options?: RequestInit,\n): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(\n () => controller.abort(),\n MEMPOOL_REQUEST_TIMEOUT_MS,\n );\n\n // Compose timeout signal with any caller-supplied signal so both can cancel\n const signals = [controller.signal, options?.signal].filter(\n Boolean,\n ) as AbortSignal[];\n const combined = combineAbortSignals(signals);\n\n try {\n // Don't clear timeout here — let it cover body consumption by callers.\n // For the same reason the composed signal keeps its listeners attached on\n // the success path: detaching them would stop the timeout from aborting a\n // stalled body read.\n return await fetch(url, {\n ...options,\n signal: combined.signal,\n });\n } catch (error) {\n clearTimeout(timeoutId);\n combined.cleanup();\n if (\n error != null &&\n typeof error === \"object\" &&\n \"name\" in error &&\n error.name === \"AbortError\"\n ) {\n throw new Error(\n `Mempool API request timed out after ${MEMPOOL_REQUEST_TIMEOUT_MS}ms: ${url}`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Maximum sane fee rate in sat/vByte.\n * The April 2024 Runes spike peaked around 1,805 sat/vB — 10,000 provides ample headroom.\n */\nconst MAX_FEE_RATE = 10_000;\n\nfunction isValidSatoshiValue(value: number): boolean {\n return Number.isInteger(value) && value > 0 && value <= MAX_SATOSHIS;\n}\n\nfunction isValidFeeRate(value: number): boolean {\n return Number.isInteger(value) && value > 0 && value <= MAX_FEE_RATE;\n}\n\nfunction isValidVout(vout: number, outputCount?: number): boolean {\n if (!Number.isInteger(vout) || vout < 0) return false;\n return outputCount === undefined || vout < outputCount;\n}\n\n\nfunction assertValidTxid(txid: string): void {\n if (!TXID_RE.test(txid)) {\n throw new Error(`Invalid transaction ID format: ${txid}`);\n }\n}\n\nfunction assertValidAddress(address: string): void {\n if (!BITCOIN_ADDRESS_RE.test(address)) {\n throw new Error(`Invalid Bitcoin address format: ${address}`);\n }\n}\n\nfunction assertValidScriptPubKey(scriptPubKey: string, context: string): void {\n if (!HEX_RE.test(scriptPubKey)) {\n throw new Error(\n `Invalid scriptPubKey: not valid hex for ${context}`,\n );\n }\n const matchesKnownType = KNOWN_SCRIPT_PREFIXES.some((prefix) =>\n scriptPubKey.toLowerCase().startsWith(prefix),\n );\n if (!matchesKnownType) {\n throw new Error(\n `Unrecognized scriptPubKey type for ${context}: ` +\n `prefix ${scriptPubKey.slice(0, 6)} does not match any known Bitcoin script type`,\n );\n }\n}\n\n/**\n * Default mempool API URLs by network.\n */\nexport const MEMPOOL_API_URLS = {\n mainnet: \"https://mempool.space/api\",\n testnet: \"https://mempool.space/testnet/api\",\n signet: \"https://mempool.space/signet/api\",\n} as const;\n\n/**\n * Fetch wrapper with error handling.\n */\nasync function fetchApi<T>(\n url: string,\n options?: RequestInit,\n): Promise<T> {\n try {\n const response = await fetchWithTimeout(url, options);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Mempool API error (${response.status}): ${errorText || response.statusText}`,\n );\n }\n\n const contentType = response.headers.get(\"content-type\");\n if (contentType?.includes(\"application/json\")) {\n return (await response.json()) as T;\n } else {\n return (await response.text()) as T;\n }\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to fetch from mempool API: ${error.message}`);\n }\n throw new Error(\"Failed to fetch from mempool API: Unknown error\");\n }\n}\n\n/**\n * Push a signed transaction to the Bitcoin network.\n *\n * @param txHex - The signed transaction hex string\n * @param apiUrl - Mempool API base URL\n * @returns The transaction ID\n * @throws Error if broadcasting fails\n */\nexport async function pushTx(txHex: string, apiUrl: string): Promise<string> {\n try {\n const response = await fetchWithTimeout(`${apiUrl}/tx`, {\n method: \"POST\",\n body: txHex,\n headers: {\n \"Content-Type\": \"text/plain\",\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n // Try to extract error message from response using robust JSON parsing\n let message: string | undefined;\n try {\n const errorJson = JSON.parse(errorText);\n message = errorJson.message ?? errorJson.error;\n } catch {\n // Not JSON, use raw text\n message = errorText;\n }\n throw new Error(\n message || `Failed to broadcast transaction: ${response.statusText}`,\n );\n }\n\n // Response is the transaction ID (plain text)\n const txId = await response.text();\n return txId;\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to broadcast BTC transaction: ${error.message}`);\n }\n throw new Error(\"Failed to broadcast BTC transaction: Unknown error\");\n }\n}\n\n/**\n * Get transaction information from mempool.\n *\n * @param txid - The transaction ID\n * @param apiUrl - Mempool API base URL\n * @returns Transaction information\n */\nexport async function getTxInfo(txid: string, apiUrl: string): Promise<TxInfo> {\n assertValidTxid(txid);\n return fetchApi<TxInfo>(`${apiUrl}/tx/${txid}`);\n}\n\n/**\n * Get the current block tip height.\n *\n * Source: mempool.space API — `GET /api/blocks/tip/height` returns the height\n * of the most recent block as a plain-text integer.\n *\n * @param apiUrl - Mempool API base URL\n * @returns The height of the most recent block\n * @throws Error if the response is not a whole number\n */\nexport async function getTipHeight(apiUrl: string): Promise<number> {\n const raw = await fetchApi<string>(`${apiUrl}/blocks/tip/height`);\n const trimmed = raw.trim();\n if (!/^\\d+$/.test(trimmed)) {\n throw new Error(\n `Mempool API returned an invalid block tip height: \"${raw}\"`,\n );\n }\n return Number.parseInt(trimmed, 10);\n}\n\n/**\n * Get the spend status of a specific transaction output.\n *\n * Calls the esplora-compatible `GET /tx/{txid}/outspend/{vout}` endpoint\n * (mempool.space backend, mempool/electrs `rest.rs`). Returns\n * `{ spent: false }` for an unspent output, or\n * `{ spent: true, txid, vin, status }` when the output has been spent.\n *\n * @param txid - The transaction id whose output is being checked (no 0x prefix)\n * @param vout - The output index\n * @param apiUrl - Mempool API base URL\n * @returns The output's spend status\n */\nexport async function getOutspend(\n txid: string,\n vout: number,\n apiUrl: string,\n): Promise<OutspendStatus> {\n assertValidTxid(txid);\n if (!isValidVout(vout)) {\n throw new Error(`Invalid vout ${vout} for transaction ${txid}`);\n }\n return fetchApi<OutspendStatus>(`${apiUrl}/tx/${txid}/outspend/${vout}`);\n}\n\n/**\n * Get the hex representation of a transaction.\n *\n * @param txid - The transaction ID\n * @param apiUrl - Mempool API base URL\n * @returns The transaction hex string\n * @throws Error if the request fails or transaction is not found\n */\nexport async function getTxHex(txid: string, apiUrl: string): Promise<string> {\n assertValidTxid(txid);\n try {\n const response = await fetchWithTimeout(`${apiUrl}/tx/${txid}/hex`);\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Mempool API error (${response.status}): ${errorText || response.statusText}`,\n );\n }\n\n return await response.text();\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to get transaction hex for ${txid}: ${error.message}`);\n }\n throw new Error(`Failed to get transaction hex for ${txid}: Unknown error`);\n }\n}\n\n/**\n * Get UTXO information for a specific transaction output.\n *\n * This is used for constructing PSBTs where we need the witnessUtxo data.\n * Only supports Taproot (P2TR) and native SegWit (P2WPKH, P2WSH) script types.\n *\n * @param txid - The transaction ID containing the UTXO\n * @param vout - The output index\n * @param apiUrl - Mempool API base URL\n * @returns UTXO information with value and scriptPubKey\n */\nexport async function getUtxoInfo(\n txid: string,\n vout: number,\n apiUrl: string,\n): Promise<UtxoInfo> {\n assertValidTxid(txid);\n const txInfo = await getTxInfo(txid, apiUrl);\n\n if (!isValidVout(vout, txInfo.vout.length)) {\n throw new Error(\n `Invalid vout ${vout} for transaction ${txid} (has ${txInfo.vout.length} outputs)`,\n );\n }\n\n const output = txInfo.vout[vout];\n if (!isValidSatoshiValue(output.value)) {\n throw new Error(`Invalid UTXO value ${output.value} for ${txid}:${vout}`);\n }\n assertValidScriptPubKey(output.scriptpubkey, `${txid}:${vout}`);\n\n return {\n txid,\n vout,\n value: output.value,\n scriptPubKey: output.scriptpubkey,\n };\n}\n\n/**\n * Get all UTXOs for a Bitcoin address.\n *\n * @param address - The Bitcoin address\n * @param apiUrl - Mempool API base URL\n * @returns Array of UTXOs sorted by value (largest first)\n */\nexport async function getAddressUtxos(\n address: string,\n apiUrl: string,\n): Promise<MempoolUTXO[]> {\n assertValidAddress(address);\n try {\n // Fetch UTXOs for the address\n const utxos = await fetchApi<\n {\n txid: string;\n vout: number;\n value: number;\n status: {\n confirmed: boolean;\n };\n }[]\n >(`${apiUrl}/address/${address}/utxo`);\n\n // Fetch scriptPubKey for the address\n const addressInfo = await fetchApi<{\n isvalid: boolean;\n scriptPubKey: string;\n }>(`${apiUrl}/v1/validate-address/${address}`);\n\n if (!addressInfo.isvalid) {\n throw new Error(\n `Invalid Bitcoin address: ${address}. Mempool API validation failed.`,\n );\n }\n assertValidScriptPubKey(addressInfo.scriptPubKey, address);\n\n // Validate UTXO fields from the listing endpoint.\n // Per-UTXO cross-verification against /tx/{txid} is intentionally NOT done\n // here — it would be expensive (N API calls) and redundant: the broadcast\n // path already verifies each selected input via getUtxoInfo before signing.\n // Both endpoints come from the same mempool API, so cross-checking one\n // against the other on the same server does not add real security.\n for (const utxo of utxos) {\n assertValidTxid(utxo.txid);\n if (!isValidVout(utxo.vout)) {\n throw new Error(`Invalid vout ${utxo.vout} for ${utxo.txid}`);\n }\n if (!isValidSatoshiValue(utxo.value)) {\n throw new Error(\n `Invalid UTXO value ${utxo.value} for ${utxo.txid}:${utxo.vout}`,\n );\n }\n }\n\n // Sort by value (largest first) and map to our UTXO format\n const sortedUTXOs = utxos.sort((a, b) => b.value - a.value);\n\n return sortedUTXOs.map((utxo) => ({\n txid: utxo.txid,\n vout: utxo.vout,\n value: utxo.value,\n scriptPubKey: addressInfo.scriptPubKey,\n confirmed: utxo.status.confirmed,\n }));\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(\n `Failed to get UTXOs for address ${address}: ${error.message}`,\n );\n }\n throw new Error(\n `Failed to get UTXOs for address ${address}: Unknown error`,\n );\n }\n}\n\n/**\n * Get the mempool API URL for a given network.\n *\n * @param network - Bitcoin network (mainnet, testnet, signet)\n * @returns The mempool API URL\n */\nexport function getMempoolApiUrl(\n network: \"mainnet\" | \"testnet\" | \"signet\",\n): string {\n return MEMPOOL_API_URLS[network];\n}\n\n/**\n * Transaction summary from address transactions endpoint.\n */\nexport interface AddressTx {\n txid: string;\n status: {\n confirmed: boolean;\n block_height?: number;\n };\n}\n\n/**\n * Get recent transactions for a Bitcoin address.\n *\n * Returns the last 25 confirmed transactions plus any unconfirmed (mempool) transactions.\n * This is useful for checking if a specific transaction has been broadcast.\n *\n * @param address - The Bitcoin address\n * @param apiUrl - Mempool API base URL\n * @returns Array of recent transactions\n */\nexport async function getAddressTxs(\n address: string,\n apiUrl: string,\n): Promise<AddressTx[]> {\n assertValidAddress(address);\n return fetchApi<AddressTx[]>(`${apiUrl}/address/${address}/txs`);\n}\n\n/**\n * Fetches Bitcoin network fee recommendations from mempool.space API.\n *\n * @param apiUrl - Mempool API base URL\n * @returns Fee rates in sat/vbyte for different confirmation times\n * @throws Error if request fails or returns invalid data\n *\n * @see https://mempool.space/docs/api/rest#get-recommended-fees\n */\nexport async function getNetworkFees(apiUrl: string): Promise<NetworkFees> {\n const response = await fetchWithTimeout(`${apiUrl}/v1/fees/recommended`);\n\n if (!response.ok) {\n throw new Error(\n `Failed to fetch network fees: ${response.status} ${response.statusText}`,\n );\n }\n\n const data = await response.json();\n\n const feeFields = [\n \"fastestFee\",\n \"halfHourFee\",\n \"hourFee\",\n \"economyFee\",\n \"minimumFee\",\n ] as const;\n\n for (const field of feeFields) {\n if (!isValidFeeRate(data[field])) {\n throw new Error(\n `Invalid fee rate ${field}=${data[field]} from mempool API: expected a positive number ≤ ${MAX_FEE_RATE}`,\n );\n }\n }\n\n if (\n data.minimumFee > data.economyFee ||\n data.economyFee > data.hourFee ||\n data.hourFee > data.halfHourFee ||\n data.halfHourFee > data.fastestFee\n ) {\n throw new Error(\n `Fee rate ordering violation from mempool API: expected ` +\n `minimumFee (${data.minimumFee}) <= economyFee (${data.economyFee}) <= ` +\n `hourFee (${data.hourFee}) <= halfHourFee (${data.halfHourFee}) <= ` +\n `fastestFee (${data.fastestFee}).`,\n );\n }\n\n return data as NetworkFees;\n}\n\n"],"names":["UINT16_MAX","MAX_BASIS_POINTS","UINT32_MAX","UINT8_MAX","assertValidOffchainParamsVersion","version","validateOffchainParams","params","errors","validateTBVProtocolParams","validatePegInConfiguration","config","assertValidVaultCoreVersion","MAX_VP_COMMISSION_BPS","mapVaultBasicInfo","result","mapVaultProtocolInfo","offchainParamsVersion","UINT64_EXCLUSIVE_UPPER_BOUND","assertEpochInRange","value","field","vaultId","mapKeyEpochs","ViemVaultRegistryReader","publicClient","contractAddress","vpAddress","BTCVaultRegistryABI","assertOnChainBtcPubkey","BTCVaultRegistryKeyEpochsABI","vaultIds","info","vaultProvider","bps","basicRaw","protocolRaw","basic","protocol","protocolInfo","MAX_SATOSHIS","MEMPOOL_REQUEST_TIMEOUT_MS","fetchWithTimeout","url","options","controller","timeoutId","signals","combined","combineAbortSignals","error","MAX_FEE_RATE","isValidSatoshiValue","isValidFeeRate","isValidVout","vout","outputCount","assertValidTxid","txid","TXID_RE","assertValidAddress","address","BITCOIN_ADDRESS_RE","assertValidScriptPubKey","scriptPubKey","context","HEX_RE","KNOWN_SCRIPT_PREFIXES","prefix","MEMPOOL_API_URLS","fetchApi","response","errorText","contentType","pushTx","txHex","apiUrl","message","errorJson","getTxInfo","getTipHeight","raw","trimmed","getOutspend","getTxHex","getUtxoInfo","txInfo","output","getAddressUtxos","utxos","addressInfo","utxo","a","b","getMempoolApiUrl","network","getAddressTxs","getNetworkFees","data","feeFields"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { initWasm as L, WasmPrePeginTx as V, assertPositiveBigintArray as O, get
|
|
|
2
2
|
import { Buffer as a } from "buffer";
|
|
3
3
|
import { Transaction as w, Psbt as E, payments as U } from "bitcoinjs-lib";
|
|
4
4
|
import { u as k, T as K, h as f, s as g, d as F, p as z, j as W } from "./bitcoin-B5aNKtsk.js";
|
|
5
|
-
import { n as _ } from "./verifyScriptPathSchnorrSignature-
|
|
5
|
+
import { n as _ } from "./verifyScriptPathSchnorrSignature-Xoo9DOHW.js";
|
|
6
6
|
async function X(s) {
|
|
7
7
|
await L();
|
|
8
8
|
const { prePeginParams: e, fundedPrePeginTxHex: n, htlcVout: t, refundFee: i, hashlock: c } = s, v = _(
|
|
@@ -175,4 +175,4 @@ export {
|
|
|
175
175
|
X as b,
|
|
176
176
|
Y as c
|
|
177
177
|
};
|
|
178
|
-
//# sourceMappingURL=noPayout-
|
|
178
|
+
//# sourceMappingURL=noPayout-CI4l1qu2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noPayout-CihCk1HE.js","sources":["../src/tbv/core/primitives/psbt/refund.ts","../src/tbv/core/primitives/psbt/noPayout.ts"],"sourcesContent":["/**\n * Refund PSBT Builder Primitive\n *\n * Builds an unsigned refund PSBT for a depositor to reclaim BTC from\n * a timed-out Pre-PegIn HTLC output via the refund script (leaf 1).\n *\n * The refund script enforces a CSV timelock (timelockRefund blocks) and\n * requires only the depositor's Schnorr signature — no vault provider or\n * keeper involvement.\n *\n * @module primitives/psbt/refund\n */\n\nimport {\n assertPositiveBigintArray,\n getPrePeginHtlcConnectorInfo,\n initWasm,\n tapInternalPubkey,\n WasmPrePeginTx,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport { normalizeAuthAnchorHash, type PrePeginParams } from \"./pegin\";\n\n/**\n * Parameters for building a refund PSBT\n */\nexport interface BuildRefundPsbtParams {\n /** Same PrePeginParams used when the original Pre-PegIn tx was created */\n prePeginParams: PrePeginParams;\n /** Funded Pre-PegIn transaction hex (the tx whose HTLC output is being refunded) */\n fundedPrePeginTxHex: string;\n /** Index of the HTLC output in the Pre-PegIn transaction */\n htlcVout: number;\n /** Transaction fee in satoshis for the refund transaction */\n refundFee: bigint;\n /** SHA256 hash commitment for the HTLC (64 hex chars, no 0x prefix) */\n hashlock: string;\n}\n\n/**\n * Result of building a refund PSBT\n */\nexport interface BuildRefundPsbtResult {\n /** PSBT hex ready for depositor signing */\n psbtHex: string;\n}\n\n/**\n * Build a PSBT for signing the refund transaction.\n *\n * The refund transaction spends the Pre-PegIn HTLC output via leaf 1\n * (the refund script: `<timelockRefund> CSV DROP <depositorPubkey> CHECKSIG`).\n * The PSBT includes the tapLeafScript entry so the depositor's wallet can\n * sign using Taproot script-path spending.\n *\n * The input's sequence is set to `timelockRefund` by the WASM, enforcing\n * the Bitcoin CSV timelock. The refund broadcast will be rejected by the\n * network if the timelock has not yet expired.\n *\n * @param params - Refund PSBT parameters\n * @returns PSBT hex for depositor signing\n * @throws If the HTLC output at htlcVout is not found\n * @throws If the refund transaction does not have exactly 1 input\n */\nexport async function buildRefundPsbt(\n params: BuildRefundPsbtParams,\n): Promise<BuildRefundPsbtResult> {\n await initWasm();\n\n const { prePeginParams, fundedPrePeginTxHex, htlcVout, refundFee, hashlock } =\n params;\n\n // The 14th positional arg `auth_anchor_hash` is `Option<String>` in\n // the Rust WASM constructor (the 9th arg `min_pegin_fee_rate` requires\n // the two-rate constructor from btc-vault #1930). Production peg-ins\n // (PeginManager) always commit an OP_RETURN <PUSH32 SHA256(authAnchor)>\n // output at `vout = hashlocks.length`; the unfunded template must\n // include it so `fromFundedTransaction` aligns with the funded tx.\n // Normalize identically to the peg-in primitives (`0x` strip,\n // lowercase, length/charset validation) so a direct primitive caller\n // reusing successful peg-in params doesn't hand unnormalized bytes to\n // WASM. Pass `undefined` for legacy non-auth-anchored Pre-PegIns.\n const normalizedAuthAnchorHash = normalizeAuthAnchorHash(\n prePeginParams.authAnchorHash,\n );\n // Reconstruct the template under the same graph version the Pre-PegIn\n // was originally built with (the vault's stamped vaultCoreVersion).\n const unfundedTx = new WasmPrePeginTx(\n prePeginParams.vaultCoreVersion,\n prePeginParams.depositorPubkey,\n prePeginParams.vaultProviderPubkey,\n prePeginParams.vaultKeeperPubkeys,\n prePeginParams.universalChallengerPubkeys,\n [...prePeginParams.hashlocks],\n new BigUint64Array(\n assertPositiveBigintArray(prePeginParams.pegInAmounts, \"pegInAmounts\"),\n ),\n prePeginParams.timelockRefund,\n prePeginParams.feeRate,\n prePeginParams.minPeginFeeRate,\n prePeginParams.numLocalChallengers,\n prePeginParams.councilQuorum,\n prePeginParams.councilSize,\n prePeginParams.network,\n normalizedAuthAnchorHash,\n );\n\n let fundedTx: WasmPrePeginTx | null = null;\n try {\n // Cross-check the reconstructed unfunded template against the funded\n // transaction: the WASM template's HTLC scriptPubKey at `htlcVout`\n // must equal the bytes the funded tx carries at the same output.\n // If they disagree, the template was reconstructed from the wrong\n // (hashlocks, amounts) vector — signing it would produce a refund\n // that does not spend the on-chain HTLC the depositor expects.\n // This is the explicit invariant the audit recommends: never sign a\n // refund whose template doesn't match the on-chain output bytes.\n const expectedHtlcScriptPubKey = unfundedTx\n .getHtlcScriptPubKey(htlcVout)\n .toLowerCase();\n // The reconstructed template's HTLC output value at `htlcVout`,\n // sized by WASM from the supplied `pegInAmounts` via the protocol\n // formula `htlcValue = peginAmount + depositorClaimValue + minPeginFee`.\n // Captured before `fromFundedTransaction` to bind it to the value the\n // funded tx actually carries (see the cross-check below).\n const expectedHtlcValue = unfundedTx.getHtlcValue(htlcVout);\n\n fundedTx = unfundedTx.fromFundedTransaction(fundedPrePeginTxHex);\n\n const refundTxHex = fundedTx.buildRefundTx(refundFee, htlcVout);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: prePeginParams.vaultCoreVersion,\n depositorPubkey: prePeginParams.depositorPubkey,\n vaultProviderPubkey: prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys: prePeginParams.universalChallengerPubkeys,\n hashlock,\n timelockRefund: prePeginParams.timelockRefund,\n network: prePeginParams.network,\n });\n\n const cleanPrePeginHex = fundedPrePeginTxHex.startsWith(\"0x\")\n ? fundedPrePeginTxHex.slice(2)\n : fundedPrePeginTxHex;\n const prePeginTx = Transaction.fromHex(cleanPrePeginHex);\n\n const htlcOutput = prePeginTx.outs[htlcVout];\n if (!htlcOutput) {\n throw new Error(\n `HTLC output at vout ${htlcVout} not found in funded Pre-PegIn tx ` +\n `(tx has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const actualHtlcScriptPubKey = uint8ArrayToHex(\n new Uint8Array(htlcOutput.script),\n ).toLowerCase();\n if (actualHtlcScriptPubKey !== expectedHtlcScriptPubKey) {\n throw new Error(\n `HTLC scriptPubKey mismatch at vout ${htlcVout}: reconstructed ` +\n `template expects ${expectedHtlcScriptPubKey}, funded tx carries ` +\n `${actualHtlcScriptPubKey}. Refund refused — the (hashlocks, ` +\n `pegInAmounts) vector does not match the on-chain commitment.`,\n );\n }\n\n // Value cross-check (mirrors the script check above): the template's\n // HTLC value — derived by WASM from `pegInAmounts` via the protocol\n // formula — must equal the value the funded tx pays at this output.\n // A caller that hands the full HTLC output value (or any wrong amount)\n // as `pegInAmounts` would inflate the template value and trip this\n // guard, rather than silently signing a refund built from a template\n // that disagrees with the on-chain commitment.\n const actualHtlcValue = BigInt(htlcOutput.value);\n if (actualHtlcValue !== expectedHtlcValue) {\n throw new Error(\n `HTLC value mismatch at vout ${htlcVout}: reconstructed template ` +\n `expects ${expectedHtlcValue} sat, funded tx carries ` +\n `${actualHtlcValue} sat. Refund refused — the pegInAmounts vector ` +\n `does not match the on-chain commitment.`,\n );\n }\n\n const refundTx = Transaction.fromHex(refundTxHex);\n\n if (refundTx.ins.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 input, got ${refundTx.ins.length}`,\n );\n }\n\n const refundInput = refundTx.ins[0];\n\n // Verify the refund input spends the correct Pre-PegIn HTLC output\n const prePeginTxid = prePeginTx.getId();\n const refundInputTxid = uint8ArrayToHex(\n new Uint8Array(refundInput.hash).slice().reverse(),\n );\n if (refundInputTxid !== prePeginTxid) {\n throw new Error(\n `Refund input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${refundInputTxid}`,\n );\n }\n if (refundInput.index !== htlcVout) {\n throw new Error(\n `Refund input index ${refundInput.index} does not match expected htlcVout ${htlcVout}`,\n );\n }\n\n const psbt = new Psbt();\n psbt.setVersion(refundTx.version);\n psbt.setLocktime(refundTx.locktime);\n\n psbt.addInput({\n hash: refundInput.hash,\n index: refundInput.index,\n sequence: refundInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hexToUint8Array(htlcConnector.refundScript)),\n controlBlock: Buffer.from(\n hexToUint8Array(htlcConnector.refundControlBlock),\n ),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n });\n\n // Output side: pin the single refund output to the depositor's own\n // BIP-86 P2TR address, mirroring the input-side pinning above. WASM\n // builds the refund output from the refund leaf's depositor key, so a\n // correct template always pays exactly one output back to the depositor.\n // Asserting it here means a malformed template (or a tampered WASM)\n // cannot redirect the reclaimed funds to a script the depositor does\n // not control.\n if (refundTx.outs.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 output, got ${refundTx.outs.length}`,\n );\n }\n const refundOutput = refundTx.outs[0];\n const expectedDepositorScriptPubKey = stripHexPrefix(\n deriveBip86ScriptPubKeyHex(prePeginParams.depositorPubkey),\n ).toLowerCase();\n const actualRefundOutputScriptPubKey = uint8ArrayToHex(\n new Uint8Array(refundOutput.script),\n ).toLowerCase();\n if (actualRefundOutputScriptPubKey !== expectedDepositorScriptPubKey) {\n throw new Error(\n `Refund output scriptPubKey ${actualRefundOutputScriptPubKey} does not ` +\n `match the depositor's BIP-86 address ${expectedDepositorScriptPubKey}. ` +\n `Refund refused — the reclaimed funds would not return to the depositor.`,\n );\n }\n\n // Value: the single refund output must return the full HTLC value minus\n // exactly the requested fee. The refund is 1-in/1-out (asserted above), so\n // a value below `htlcValue - refundFee` means WASM applied a larger fee\n // than requested — the difference would be burned as miner fee. Pin it so\n // the depositor reclaims the expected amount, not a silently reduced one.\n const expectedRefundOutputValue = actualHtlcValue - refundFee;\n if (BigInt(refundOutput.value) !== expectedRefundOutputValue) {\n throw new Error(\n `Refund output value ${BigInt(refundOutput.value)} sat does not equal ` +\n `the HTLC value ${actualHtlcValue} sat minus the requested fee ` +\n `${refundFee} sat (expected ${expectedRefundOutputValue} sat). ` +\n `Refund refused — the reclaimed amount would be burned as excess fee.`,\n );\n }\n\n psbt.addOutput({\n script: refundOutput.script,\n value: refundOutput.value,\n });\n\n return { psbtHex: psbt.toHex() };\n } finally {\n fundedTx?.free();\n unfundedTx.free();\n }\n}\n","/**\n * NoPayout PSBT Builder\n *\n * Builds unsigned PSBTs for the depositor's NoPayout transaction\n * (depositor-as-claimer path, per challenger). The depositor signs input 0\n * using the NoPayout taproot script from WasmAssertPayoutNoPayoutConnector.\n *\n * @module primitives/psbt/noPayout\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md — Assert output 0 NoPayout connector\n */\n\nimport {\n type AssertPayoutNoPayoutConnectorParams,\n type Network,\n getAssertNoPayoutScriptInfo,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction, payments } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n getNetwork,\n hexToUint8Array,\n processPublicKeyToXOnly,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building a NoPayout PSBT\n */\nexport interface NoPayoutParams {\n /** NoPayout transaction hex (unsigned) from VP */\n noPayoutTxHex: string;\n /** Challenger's x-only public key (hex encoded) */\n challengerPubkey: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Parameters for the Assert Payout/NoPayout connector */\n connectorParams: AssertPayoutNoPayoutConnectorParams;\n}\n\n/**\n * Build unsigned NoPayout PSBT.\n *\n * The NoPayout transaction is specific to each challenger.\n * Input 0 is the one the depositor signs using the NoPayout taproot script path.\n *\n * @param params - NoPayout parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildNoPayoutPsbt(\n params: NoPayoutParams,\n): Promise<string> {\n const noPayoutTxHex = stripHexPrefix(params.noPayoutTxHex);\n const noPayoutTx = Transaction.fromHex(noPayoutTxHex);\n\n // Get NoPayout script and control block for this challenger\n const { noPayoutScript, noPayoutControlBlock } =\n await getAssertNoPayoutScriptInfo(\n params.connectorParams,\n params.challengerPubkey,\n );\n\n const scriptBytes = hexToUint8Array(noPayoutScript);\n const controlBlockBytes = hexToUint8Array(noPayoutControlBlock);\n\n const psbt = new Psbt();\n psbt.setVersion(noPayoutTx.version);\n psbt.setLocktime(noPayoutTx.locktime);\n\n // Add all inputs - depositor signs input 0 only\n for (let i = 0; i < noPayoutTx.ins.length; i++) {\n const input = noPayoutTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const inputData: Parameters<typeof psbt.addInput>[0] = {\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n };\n\n // Input 0: depositor signs using taproot script path\n if (i === 0) {\n inputData.tapLeafScript = [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlockBytes),\n },\n ];\n inputData.tapInternalKey = Buffer.from(tapInternalPubkey);\n }\n\n psbt.addInput(inputData);\n }\n\n // Add outputs\n for (const output of noPayoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n\n/**\n * Validate that a NoPayout transaction pays to the challenger via the\n * protocol-defined output structure: a single BIP-86 P2TR output derived from\n * the challenger's x-only pubkey.\n *\n * Mirrors the per-role payout output validation now inlined in\n * `buildPayoutPsbt` for the NoPayout path, where the sink is fixed by the\n * protocol rather than read from on-chain registration\n * (see `crates/vault/src/transactions/nopayout.rs::NoPayoutTx::new`).\n *\n * @param noPayoutTxHex - Raw NoPayout transaction hex\n * @param challengerPubkey - Challenger's x-only public key (hex)\n * @param network - Bitcoin network used to derive the P2TR scriptPubKey\n * @throws If the transaction does not have exactly one output\n * @throws If the single output's scriptPubKey does not equal the BIP-86 P2TR\n * scriptPubKey for the challenger\n */\nexport function assertNoPayoutOutputMatchesChallenger(\n noPayoutTxHex: string,\n challengerPubkey: string,\n network: Network,\n): void {\n const tx = Transaction.fromHex(stripHexPrefix(noPayoutTxHex));\n\n if (tx.outs.length !== 1) {\n throw new Error(\n `NoPayout transaction must have exactly 1 output, got ${tx.outs.length}`,\n );\n }\n\n const xOnly = hexToUint8Array(processPublicKeyToXOnly(challengerPubkey));\n const { output: expectedScript } = payments.p2tr({\n internalPubkey: Buffer.from(xOnly),\n network: getNetwork(network),\n });\n if (!expectedScript) {\n throw new Error(\n \"Failed to derive challenger BIP-86 P2TR scriptPubKey for NoPayout output validation\",\n );\n }\n\n if (!tx.outs[0].script.equals(expectedScript)) {\n throw new Error(\n \"NoPayout transaction does not pay to the expected challenger BIP-86 P2TR address\",\n );\n }\n}\n"],"names":["buildRefundPsbt","params","initWasm","prePeginParams","fundedPrePeginTxHex","htlcVout","refundFee","hashlock","normalizedAuthAnchorHash","normalizeAuthAnchorHash","unfundedTx","WasmPrePeginTx","assertPositiveBigintArray","fundedTx","expectedHtlcScriptPubKey","expectedHtlcValue","refundTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","cleanPrePeginHex","prePeginTx","Transaction","htlcOutput","actualHtlcScriptPubKey","uint8ArrayToHex","actualHtlcValue","refundTx","refundInput","prePeginTxid","refundInputTxid","psbt","Psbt","TAPSCRIPT_LEAF_VERSION","Buffer","hexToUint8Array","tapInternalPubkey","refundOutput","expectedDepositorScriptPubKey","stripHexPrefix","deriveBip86ScriptPubKeyHex","actualRefundOutputScriptPubKey","expectedRefundOutputValue","buildNoPayoutPsbt","noPayoutTxHex","noPayoutTx","noPayoutScript","noPayoutControlBlock","getAssertNoPayoutScriptInfo","scriptBytes","controlBlockBytes","i","input","prevout","inputData","output","assertNoPayoutOutputMatchesChallenger","challengerPubkey","network","tx","xOnly","processPublicKeyToXOnly","expectedScript","payments","getNetwork"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"noPayout-CI4l1qu2.js","sources":["../src/tbv/core/primitives/psbt/refund.ts","../src/tbv/core/primitives/psbt/noPayout.ts"],"sourcesContent":["/**\n * Refund PSBT Builder Primitive\n *\n * Builds an unsigned refund PSBT for a depositor to reclaim BTC from\n * a timed-out Pre-PegIn HTLC output via the refund script (leaf 1).\n *\n * The refund script enforces a CSV timelock (timelockRefund blocks) and\n * requires only the depositor's Schnorr signature — no vault provider or\n * keeper involvement.\n *\n * @module primitives/psbt/refund\n */\n\nimport {\n assertPositiveBigintArray,\n getPrePeginHtlcConnectorInfo,\n initWasm,\n tapInternalPubkey,\n WasmPrePeginTx,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport { normalizeAuthAnchorHash, type PrePeginParams } from \"./pegin\";\n\n/**\n * Parameters for building a refund PSBT\n */\nexport interface BuildRefundPsbtParams {\n /** Same PrePeginParams used when the original Pre-PegIn tx was created */\n prePeginParams: PrePeginParams;\n /** Funded Pre-PegIn transaction hex (the tx whose HTLC output is being refunded) */\n fundedPrePeginTxHex: string;\n /** Index of the HTLC output in the Pre-PegIn transaction */\n htlcVout: number;\n /** Transaction fee in satoshis for the refund transaction */\n refundFee: bigint;\n /** SHA256 hash commitment for the HTLC (64 hex chars, no 0x prefix) */\n hashlock: string;\n}\n\n/**\n * Result of building a refund PSBT\n */\nexport interface BuildRefundPsbtResult {\n /** PSBT hex ready for depositor signing */\n psbtHex: string;\n}\n\n/**\n * Build a PSBT for signing the refund transaction.\n *\n * The refund transaction spends the Pre-PegIn HTLC output via leaf 1\n * (the refund script: `<timelockRefund> CSV DROP <depositorPubkey> CHECKSIG`).\n * The PSBT includes the tapLeafScript entry so the depositor's wallet can\n * sign using Taproot script-path spending.\n *\n * The input's sequence is set to `timelockRefund` by the WASM, enforcing\n * the Bitcoin CSV timelock. The refund broadcast will be rejected by the\n * network if the timelock has not yet expired.\n *\n * @param params - Refund PSBT parameters\n * @returns PSBT hex for depositor signing\n * @throws If the HTLC output at htlcVout is not found\n * @throws If the refund transaction does not have exactly 1 input\n */\nexport async function buildRefundPsbt(\n params: BuildRefundPsbtParams,\n): Promise<BuildRefundPsbtResult> {\n await initWasm();\n\n const { prePeginParams, fundedPrePeginTxHex, htlcVout, refundFee, hashlock } =\n params;\n\n // The 14th positional arg `auth_anchor_hash` is `Option<String>` in\n // the Rust WASM constructor (the 9th arg `min_pegin_fee_rate` requires\n // the two-rate constructor from btc-vault #1930). Production peg-ins\n // (PeginManager) always commit an OP_RETURN <PUSH32 SHA256(authAnchor)>\n // output at `vout = hashlocks.length`; the unfunded template must\n // include it so `fromFundedTransaction` aligns with the funded tx.\n // Normalize identically to the peg-in primitives (`0x` strip,\n // lowercase, length/charset validation) so a direct primitive caller\n // reusing successful peg-in params doesn't hand unnormalized bytes to\n // WASM. Pass `undefined` for legacy non-auth-anchored Pre-PegIns.\n const normalizedAuthAnchorHash = normalizeAuthAnchorHash(\n prePeginParams.authAnchorHash,\n );\n // Reconstruct the template under the same graph version the Pre-PegIn\n // was originally built with (the vault's stamped vaultCoreVersion).\n const unfundedTx = new WasmPrePeginTx(\n prePeginParams.vaultCoreVersion,\n prePeginParams.depositorPubkey,\n prePeginParams.vaultProviderPubkey,\n prePeginParams.vaultKeeperPubkeys,\n prePeginParams.universalChallengerPubkeys,\n [...prePeginParams.hashlocks],\n new BigUint64Array(\n assertPositiveBigintArray(prePeginParams.pegInAmounts, \"pegInAmounts\"),\n ),\n prePeginParams.timelockRefund,\n prePeginParams.feeRate,\n prePeginParams.minPeginFeeRate,\n prePeginParams.numLocalChallengers,\n prePeginParams.councilQuorum,\n prePeginParams.councilSize,\n prePeginParams.network,\n normalizedAuthAnchorHash,\n );\n\n let fundedTx: WasmPrePeginTx | null = null;\n try {\n // Cross-check the reconstructed unfunded template against the funded\n // transaction: the WASM template's HTLC scriptPubKey at `htlcVout`\n // must equal the bytes the funded tx carries at the same output.\n // If they disagree, the template was reconstructed from the wrong\n // (hashlocks, amounts) vector — signing it would produce a refund\n // that does not spend the on-chain HTLC the depositor expects.\n // This is the explicit invariant the audit recommends: never sign a\n // refund whose template doesn't match the on-chain output bytes.\n const expectedHtlcScriptPubKey = unfundedTx\n .getHtlcScriptPubKey(htlcVout)\n .toLowerCase();\n // The reconstructed template's HTLC output value at `htlcVout`,\n // sized by WASM from the supplied `pegInAmounts` via the protocol\n // formula `htlcValue = peginAmount + depositorClaimValue + minPeginFee`.\n // Captured before `fromFundedTransaction` to bind it to the value the\n // funded tx actually carries (see the cross-check below).\n const expectedHtlcValue = unfundedTx.getHtlcValue(htlcVout);\n\n fundedTx = unfundedTx.fromFundedTransaction(fundedPrePeginTxHex);\n\n const refundTxHex = fundedTx.buildRefundTx(refundFee, htlcVout);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: prePeginParams.vaultCoreVersion,\n depositorPubkey: prePeginParams.depositorPubkey,\n vaultProviderPubkey: prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys: prePeginParams.universalChallengerPubkeys,\n hashlock,\n timelockRefund: prePeginParams.timelockRefund,\n network: prePeginParams.network,\n });\n\n const cleanPrePeginHex = fundedPrePeginTxHex.startsWith(\"0x\")\n ? fundedPrePeginTxHex.slice(2)\n : fundedPrePeginTxHex;\n const prePeginTx = Transaction.fromHex(cleanPrePeginHex);\n\n const htlcOutput = prePeginTx.outs[htlcVout];\n if (!htlcOutput) {\n throw new Error(\n `HTLC output at vout ${htlcVout} not found in funded Pre-PegIn tx ` +\n `(tx has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const actualHtlcScriptPubKey = uint8ArrayToHex(\n new Uint8Array(htlcOutput.script),\n ).toLowerCase();\n if (actualHtlcScriptPubKey !== expectedHtlcScriptPubKey) {\n throw new Error(\n `HTLC scriptPubKey mismatch at vout ${htlcVout}: reconstructed ` +\n `template expects ${expectedHtlcScriptPubKey}, funded tx carries ` +\n `${actualHtlcScriptPubKey}. Refund refused — the (hashlocks, ` +\n `pegInAmounts) vector does not match the on-chain commitment.`,\n );\n }\n\n // Value cross-check (mirrors the script check above): the template's\n // HTLC value — derived by WASM from `pegInAmounts` via the protocol\n // formula — must equal the value the funded tx pays at this output.\n // A caller that hands the full HTLC output value (or any wrong amount)\n // as `pegInAmounts` would inflate the template value and trip this\n // guard, rather than silently signing a refund built from a template\n // that disagrees with the on-chain commitment.\n const actualHtlcValue = BigInt(htlcOutput.value);\n if (actualHtlcValue !== expectedHtlcValue) {\n throw new Error(\n `HTLC value mismatch at vout ${htlcVout}: reconstructed template ` +\n `expects ${expectedHtlcValue} sat, funded tx carries ` +\n `${actualHtlcValue} sat. Refund refused — the pegInAmounts vector ` +\n `does not match the on-chain commitment.`,\n );\n }\n\n const refundTx = Transaction.fromHex(refundTxHex);\n\n if (refundTx.ins.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 input, got ${refundTx.ins.length}`,\n );\n }\n\n const refundInput = refundTx.ins[0];\n\n // Verify the refund input spends the correct Pre-PegIn HTLC output\n const prePeginTxid = prePeginTx.getId();\n const refundInputTxid = uint8ArrayToHex(\n new Uint8Array(refundInput.hash).slice().reverse(),\n );\n if (refundInputTxid !== prePeginTxid) {\n throw new Error(\n `Refund input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${refundInputTxid}`,\n );\n }\n if (refundInput.index !== htlcVout) {\n throw new Error(\n `Refund input index ${refundInput.index} does not match expected htlcVout ${htlcVout}`,\n );\n }\n\n const psbt = new Psbt();\n psbt.setVersion(refundTx.version);\n psbt.setLocktime(refundTx.locktime);\n\n psbt.addInput({\n hash: refundInput.hash,\n index: refundInput.index,\n sequence: refundInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hexToUint8Array(htlcConnector.refundScript)),\n controlBlock: Buffer.from(\n hexToUint8Array(htlcConnector.refundControlBlock),\n ),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n });\n\n // Output side: pin the single refund output to the depositor's own\n // BIP-86 P2TR address, mirroring the input-side pinning above. WASM\n // builds the refund output from the refund leaf's depositor key, so a\n // correct template always pays exactly one output back to the depositor.\n // Asserting it here means a malformed template (or a tampered WASM)\n // cannot redirect the reclaimed funds to a script the depositor does\n // not control.\n if (refundTx.outs.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 output, got ${refundTx.outs.length}`,\n );\n }\n const refundOutput = refundTx.outs[0];\n const expectedDepositorScriptPubKey = stripHexPrefix(\n deriveBip86ScriptPubKeyHex(prePeginParams.depositorPubkey),\n ).toLowerCase();\n const actualRefundOutputScriptPubKey = uint8ArrayToHex(\n new Uint8Array(refundOutput.script),\n ).toLowerCase();\n if (actualRefundOutputScriptPubKey !== expectedDepositorScriptPubKey) {\n throw new Error(\n `Refund output scriptPubKey ${actualRefundOutputScriptPubKey} does not ` +\n `match the depositor's BIP-86 address ${expectedDepositorScriptPubKey}. ` +\n `Refund refused — the reclaimed funds would not return to the depositor.`,\n );\n }\n\n // Value: the single refund output must return the full HTLC value minus\n // exactly the requested fee. The refund is 1-in/1-out (asserted above), so\n // a value below `htlcValue - refundFee` means WASM applied a larger fee\n // than requested — the difference would be burned as miner fee. Pin it so\n // the depositor reclaims the expected amount, not a silently reduced one.\n const expectedRefundOutputValue = actualHtlcValue - refundFee;\n if (BigInt(refundOutput.value) !== expectedRefundOutputValue) {\n throw new Error(\n `Refund output value ${BigInt(refundOutput.value)} sat does not equal ` +\n `the HTLC value ${actualHtlcValue} sat minus the requested fee ` +\n `${refundFee} sat (expected ${expectedRefundOutputValue} sat). ` +\n `Refund refused — the reclaimed amount would be burned as excess fee.`,\n );\n }\n\n psbt.addOutput({\n script: refundOutput.script,\n value: refundOutput.value,\n });\n\n return { psbtHex: psbt.toHex() };\n } finally {\n fundedTx?.free();\n unfundedTx.free();\n }\n}\n","/**\n * NoPayout PSBT Builder\n *\n * Builds unsigned PSBTs for the depositor's NoPayout transaction\n * (depositor-as-claimer path, per challenger). The depositor signs input 0\n * using the NoPayout taproot script from WasmAssertPayoutNoPayoutConnector.\n *\n * @module primitives/psbt/noPayout\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md — Assert output 0 NoPayout connector\n */\n\nimport {\n type AssertPayoutNoPayoutConnectorParams,\n type Network,\n getAssertNoPayoutScriptInfo,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction, payments } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n getNetwork,\n hexToUint8Array,\n processPublicKeyToXOnly,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building a NoPayout PSBT\n */\nexport interface NoPayoutParams {\n /** NoPayout transaction hex (unsigned) from VP */\n noPayoutTxHex: string;\n /** Challenger's x-only public key (hex encoded) */\n challengerPubkey: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Parameters for the Assert Payout/NoPayout connector */\n connectorParams: AssertPayoutNoPayoutConnectorParams;\n}\n\n/**\n * Build unsigned NoPayout PSBT.\n *\n * The NoPayout transaction is specific to each challenger.\n * Input 0 is the one the depositor signs using the NoPayout taproot script path.\n *\n * @param params - NoPayout parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildNoPayoutPsbt(\n params: NoPayoutParams,\n): Promise<string> {\n const noPayoutTxHex = stripHexPrefix(params.noPayoutTxHex);\n const noPayoutTx = Transaction.fromHex(noPayoutTxHex);\n\n // Get NoPayout script and control block for this challenger\n const { noPayoutScript, noPayoutControlBlock } =\n await getAssertNoPayoutScriptInfo(\n params.connectorParams,\n params.challengerPubkey,\n );\n\n const scriptBytes = hexToUint8Array(noPayoutScript);\n const controlBlockBytes = hexToUint8Array(noPayoutControlBlock);\n\n const psbt = new Psbt();\n psbt.setVersion(noPayoutTx.version);\n psbt.setLocktime(noPayoutTx.locktime);\n\n // Add all inputs - depositor signs input 0 only\n for (let i = 0; i < noPayoutTx.ins.length; i++) {\n const input = noPayoutTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const inputData: Parameters<typeof psbt.addInput>[0] = {\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n };\n\n // Input 0: depositor signs using taproot script path\n if (i === 0) {\n inputData.tapLeafScript = [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlockBytes),\n },\n ];\n inputData.tapInternalKey = Buffer.from(tapInternalPubkey);\n }\n\n psbt.addInput(inputData);\n }\n\n // Add outputs\n for (const output of noPayoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n\n/**\n * Validate that a NoPayout transaction pays to the challenger via the\n * protocol-defined output structure: a single BIP-86 P2TR output derived from\n * the challenger's x-only pubkey.\n *\n * Mirrors the per-role payout output validation now inlined in\n * `buildPayoutPsbt` for the NoPayout path, where the sink is fixed by the\n * protocol rather than read from on-chain registration\n * (see `crates/vault/src/transactions/nopayout.rs::NoPayoutTx::new`).\n *\n * @param noPayoutTxHex - Raw NoPayout transaction hex\n * @param challengerPubkey - Challenger's x-only public key (hex)\n * @param network - Bitcoin network used to derive the P2TR scriptPubKey\n * @throws If the transaction does not have exactly one output\n * @throws If the single output's scriptPubKey does not equal the BIP-86 P2TR\n * scriptPubKey for the challenger\n */\nexport function assertNoPayoutOutputMatchesChallenger(\n noPayoutTxHex: string,\n challengerPubkey: string,\n network: Network,\n): void {\n const tx = Transaction.fromHex(stripHexPrefix(noPayoutTxHex));\n\n if (tx.outs.length !== 1) {\n throw new Error(\n `NoPayout transaction must have exactly 1 output, got ${tx.outs.length}`,\n );\n }\n\n const xOnly = hexToUint8Array(processPublicKeyToXOnly(challengerPubkey));\n const { output: expectedScript } = payments.p2tr({\n internalPubkey: Buffer.from(xOnly),\n network: getNetwork(network),\n });\n if (!expectedScript) {\n throw new Error(\n \"Failed to derive challenger BIP-86 P2TR scriptPubKey for NoPayout output validation\",\n );\n }\n\n if (!tx.outs[0].script.equals(expectedScript)) {\n throw new Error(\n \"NoPayout transaction does not pay to the expected challenger BIP-86 P2TR address\",\n );\n }\n}\n"],"names":["buildRefundPsbt","params","initWasm","prePeginParams","fundedPrePeginTxHex","htlcVout","refundFee","hashlock","normalizedAuthAnchorHash","normalizeAuthAnchorHash","unfundedTx","WasmPrePeginTx","assertPositiveBigintArray","fundedTx","expectedHtlcScriptPubKey","expectedHtlcValue","refundTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","cleanPrePeginHex","prePeginTx","Transaction","htlcOutput","actualHtlcScriptPubKey","uint8ArrayToHex","actualHtlcValue","refundTx","refundInput","prePeginTxid","refundInputTxid","psbt","Psbt","TAPSCRIPT_LEAF_VERSION","Buffer","hexToUint8Array","tapInternalPubkey","refundOutput","expectedDepositorScriptPubKey","stripHexPrefix","deriveBip86ScriptPubKeyHex","actualRefundOutputScriptPubKey","expectedRefundOutputValue","buildNoPayoutPsbt","noPayoutTxHex","noPayoutTx","noPayoutScript","noPayoutControlBlock","getAssertNoPayoutScriptInfo","scriptBytes","controlBlockBytes","i","input","prevout","inputData","output","assertNoPayoutOutputMatchesChallenger","challengerPubkey","network","tx","xOnly","processPublicKeyToXOnly","expectedScript","payments","getNetwork"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const l=require("@babylonlabs-io/babylon-tbv-rust-wasm"),a=require("buffer"),d=require("bitcoinjs-lib"),t=require("./bitcoin-CHfKAhcI.cjs"),C=require("./verifyScriptPathSchnorrSignature-
|
|
2
|
-
//# sourceMappingURL=noPayout-
|
|
1
|
+
"use strict";const l=require("@babylonlabs-io/babylon-tbv-rust-wasm"),a=require("buffer"),d=require("bitcoinjs-lib"),t=require("./bitcoin-CHfKAhcI.cjs"),C=require("./verifyScriptPathSchnorrSignature-C-84KJ6U.cjs");async function S(s){await l.initWasm();const{prePeginParams:e,fundedPrePeginTxHex:o,htlcVout:r,refundFee:c,hashlock:f}=s,g=C.normalizeAuthAnchorHash(e.authAnchorHash),u=new l.WasmPrePeginTx(e.vaultCoreVersion,e.depositorPubkey,e.vaultProviderPubkey,e.vaultKeeperPubkeys,e.universalChallengerPubkeys,[...e.hashlocks],new BigUint64Array(l.assertPositiveBigintArray(e.pegInAmounts,"pegInAmounts")),e.timelockRefund,e.feeRate,e.minPeginFeeRate,e.numLocalChallengers,e.councilQuorum,e.councilSize,e.network,g);let n=null;try{const p=u.getHtlcScriptPubKey(r).toLowerCase(),h=u.getHtlcValue(r);n=u.fromFundedTransaction(o);const x=n.buildRefundTx(c,r),k=await l.getPrePeginHtlcConnectorInfo({txGraphVersion:e.vaultCoreVersion,depositorPubkey:e.depositorPubkey,vaultProviderPubkey:e.vaultProviderPubkey,vaultKeeperPubkeys:e.vaultKeeperPubkeys,universalChallengerPubkeys:e.universalChallengerPubkeys,hashlock:f,timelockRefund:e.timelockRefund,network:e.network}),$=o.startsWith("0x")?o.slice(2):o,v=d.Transaction.fromHex($),y=v.outs[r];if(!y)throw new Error(`HTLC output at vout ${r} not found in funded Pre-PegIn tx (tx has ${v.outs.length} outputs)`);const T=t.uint8ArrayToHex(new Uint8Array(y.script)).toLowerCase();if(T!==p)throw new Error(`HTLC scriptPubKey mismatch at vout ${r}: reconstructed template expects ${p}, funded tx carries ${T}. Refund refused — the (hashlocks, pegInAmounts) vector does not match the on-chain commitment.`);const w=BigInt(y.value);if(w!==h)throw new Error(`HTLC value mismatch at vout ${r}: reconstructed template expects ${h} sat, funded tx carries ${w} sat. Refund refused — the pegInAmounts vector does not match the on-chain commitment.`);const i=d.Transaction.fromHex(x);if(i.ins.length!==1)throw new Error(`Refund transaction must have exactly 1 input, got ${i.ins.length}`);const P=i.ins[0],H=v.getId(),A=t.uint8ArrayToHex(new Uint8Array(P.hash).slice().reverse());if(A!==H)throw new Error(`Refund input does not reference the Pre-PegIn transaction. Expected ${H}, got ${A}`);if(P.index!==r)throw new Error(`Refund input index ${P.index} does not match expected htlcVout ${r}`);const m=new d.Psbt;if(m.setVersion(i.version),m.setLocktime(i.locktime),m.addInput({hash:P.hash,index:P.index,sequence:P.sequence,witnessUtxo:{script:y.script,value:y.value},tapLeafScript:[{leafVersion:t.TAPSCRIPT_LEAF_VERSION,script:a.Buffer.from(t.hexToUint8Array(k.refundScript)),controlBlock:a.Buffer.from(t.hexToUint8Array(k.refundControlBlock))}],tapInternalKey:a.Buffer.from(l.tapInternalPubkey)}),i.outs.length!==1)throw new Error(`Refund transaction must have exactly 1 output, got ${i.outs.length}`);const b=i.outs[0],I=t.stripHexPrefix(t.deriveBip86ScriptPubKeyHex(e.depositorPubkey)).toLowerCase(),R=t.uint8ArrayToHex(new Uint8Array(b.script)).toLowerCase();if(R!==I)throw new Error(`Refund output scriptPubKey ${R} does not match the depositor's BIP-86 address ${I}. Refund refused — the reclaimed funds would not return to the depositor.`);const B=w-c;if(BigInt(b.value)!==B)throw new Error(`Refund output value ${BigInt(b.value)} sat does not equal the HTLC value ${w} sat minus the requested fee ${c} sat (expected ${B} sat). Refund refused — the reclaimed amount would be burned as excess fee.`);return m.addOutput({script:b.script,value:b.value}),{psbtHex:m.toHex()}}finally{n==null||n.free(),u.free()}}async function E(s){const e=t.stripHexPrefix(s.noPayoutTxHex),o=d.Transaction.fromHex(e),{noPayoutScript:r,noPayoutControlBlock:c}=await l.getAssertNoPayoutScriptInfo(s.connectorParams,s.challengerPubkey),f=t.hexToUint8Array(r),g=t.hexToUint8Array(c),u=new d.Psbt;u.setVersion(o.version),u.setLocktime(o.locktime);for(let n=0;n<o.ins.length;n++){const p=o.ins[n],h=s.prevouts[n];if(!h)throw new Error(`Missing prevout data for input ${n}`);const x={hash:p.hash,index:p.index,sequence:p.sequence,witnessUtxo:{script:a.Buffer.from(t.hexToUint8Array(t.stripHexPrefix(h.script_pubkey))),value:h.value}};n===0&&(x.tapLeafScript=[{leafVersion:t.TAPSCRIPT_LEAF_VERSION,script:a.Buffer.from(f),controlBlock:a.Buffer.from(g)}],x.tapInternalKey=a.Buffer.from(l.tapInternalPubkey)),u.addInput(x)}for(const n of o.outs)u.addOutput({script:n.script,value:n.value});return u.toHex()}function K(s,e,o){const r=d.Transaction.fromHex(t.stripHexPrefix(s));if(r.outs.length!==1)throw new Error(`NoPayout transaction must have exactly 1 output, got ${r.outs.length}`);const c=t.hexToUint8Array(t.processPublicKeyToXOnly(e)),{output:f}=d.payments.p2tr({internalPubkey:a.Buffer.from(c),network:t.getNetwork(o)});if(!f)throw new Error("Failed to derive challenger BIP-86 P2TR scriptPubKey for NoPayout output validation");if(!r.outs[0].script.equals(f))throw new Error("NoPayout transaction does not pay to the expected challenger BIP-86 P2TR address")}exports.assertNoPayoutOutputMatchesChallenger=K;exports.buildNoPayoutPsbt=E;exports.buildRefundPsbt=S;
|
|
2
|
+
//# sourceMappingURL=noPayout-Djrv31V5.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"noPayout-Cb8vFrkY.cjs","sources":["../src/tbv/core/primitives/psbt/refund.ts","../src/tbv/core/primitives/psbt/noPayout.ts"],"sourcesContent":["/**\n * Refund PSBT Builder Primitive\n *\n * Builds an unsigned refund PSBT for a depositor to reclaim BTC from\n * a timed-out Pre-PegIn HTLC output via the refund script (leaf 1).\n *\n * The refund script enforces a CSV timelock (timelockRefund blocks) and\n * requires only the depositor's Schnorr signature — no vault provider or\n * keeper involvement.\n *\n * @module primitives/psbt/refund\n */\n\nimport {\n assertPositiveBigintArray,\n getPrePeginHtlcConnectorInfo,\n initWasm,\n tapInternalPubkey,\n WasmPrePeginTx,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport { normalizeAuthAnchorHash, type PrePeginParams } from \"./pegin\";\n\n/**\n * Parameters for building a refund PSBT\n */\nexport interface BuildRefundPsbtParams {\n /** Same PrePeginParams used when the original Pre-PegIn tx was created */\n prePeginParams: PrePeginParams;\n /** Funded Pre-PegIn transaction hex (the tx whose HTLC output is being refunded) */\n fundedPrePeginTxHex: string;\n /** Index of the HTLC output in the Pre-PegIn transaction */\n htlcVout: number;\n /** Transaction fee in satoshis for the refund transaction */\n refundFee: bigint;\n /** SHA256 hash commitment for the HTLC (64 hex chars, no 0x prefix) */\n hashlock: string;\n}\n\n/**\n * Result of building a refund PSBT\n */\nexport interface BuildRefundPsbtResult {\n /** PSBT hex ready for depositor signing */\n psbtHex: string;\n}\n\n/**\n * Build a PSBT for signing the refund transaction.\n *\n * The refund transaction spends the Pre-PegIn HTLC output via leaf 1\n * (the refund script: `<timelockRefund> CSV DROP <depositorPubkey> CHECKSIG`).\n * The PSBT includes the tapLeafScript entry so the depositor's wallet can\n * sign using Taproot script-path spending.\n *\n * The input's sequence is set to `timelockRefund` by the WASM, enforcing\n * the Bitcoin CSV timelock. The refund broadcast will be rejected by the\n * network if the timelock has not yet expired.\n *\n * @param params - Refund PSBT parameters\n * @returns PSBT hex for depositor signing\n * @throws If the HTLC output at htlcVout is not found\n * @throws If the refund transaction does not have exactly 1 input\n */\nexport async function buildRefundPsbt(\n params: BuildRefundPsbtParams,\n): Promise<BuildRefundPsbtResult> {\n await initWasm();\n\n const { prePeginParams, fundedPrePeginTxHex, htlcVout, refundFee, hashlock } =\n params;\n\n // The 14th positional arg `auth_anchor_hash` is `Option<String>` in\n // the Rust WASM constructor (the 9th arg `min_pegin_fee_rate` requires\n // the two-rate constructor from btc-vault #1930). Production peg-ins\n // (PeginManager) always commit an OP_RETURN <PUSH32 SHA256(authAnchor)>\n // output at `vout = hashlocks.length`; the unfunded template must\n // include it so `fromFundedTransaction` aligns with the funded tx.\n // Normalize identically to the peg-in primitives (`0x` strip,\n // lowercase, length/charset validation) so a direct primitive caller\n // reusing successful peg-in params doesn't hand unnormalized bytes to\n // WASM. Pass `undefined` for legacy non-auth-anchored Pre-PegIns.\n const normalizedAuthAnchorHash = normalizeAuthAnchorHash(\n prePeginParams.authAnchorHash,\n );\n // Reconstruct the template under the same graph version the Pre-PegIn\n // was originally built with (the vault's stamped vaultCoreVersion).\n const unfundedTx = new WasmPrePeginTx(\n prePeginParams.vaultCoreVersion,\n prePeginParams.depositorPubkey,\n prePeginParams.vaultProviderPubkey,\n prePeginParams.vaultKeeperPubkeys,\n prePeginParams.universalChallengerPubkeys,\n [...prePeginParams.hashlocks],\n new BigUint64Array(\n assertPositiveBigintArray(prePeginParams.pegInAmounts, \"pegInAmounts\"),\n ),\n prePeginParams.timelockRefund,\n prePeginParams.feeRate,\n prePeginParams.minPeginFeeRate,\n prePeginParams.numLocalChallengers,\n prePeginParams.councilQuorum,\n prePeginParams.councilSize,\n prePeginParams.network,\n normalizedAuthAnchorHash,\n );\n\n let fundedTx: WasmPrePeginTx | null = null;\n try {\n // Cross-check the reconstructed unfunded template against the funded\n // transaction: the WASM template's HTLC scriptPubKey at `htlcVout`\n // must equal the bytes the funded tx carries at the same output.\n // If they disagree, the template was reconstructed from the wrong\n // (hashlocks, amounts) vector — signing it would produce a refund\n // that does not spend the on-chain HTLC the depositor expects.\n // This is the explicit invariant the audit recommends: never sign a\n // refund whose template doesn't match the on-chain output bytes.\n const expectedHtlcScriptPubKey = unfundedTx\n .getHtlcScriptPubKey(htlcVout)\n .toLowerCase();\n // The reconstructed template's HTLC output value at `htlcVout`,\n // sized by WASM from the supplied `pegInAmounts` via the protocol\n // formula `htlcValue = peginAmount + depositorClaimValue + minPeginFee`.\n // Captured before `fromFundedTransaction` to bind it to the value the\n // funded tx actually carries (see the cross-check below).\n const expectedHtlcValue = unfundedTx.getHtlcValue(htlcVout);\n\n fundedTx = unfundedTx.fromFundedTransaction(fundedPrePeginTxHex);\n\n const refundTxHex = fundedTx.buildRefundTx(refundFee, htlcVout);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: prePeginParams.vaultCoreVersion,\n depositorPubkey: prePeginParams.depositorPubkey,\n vaultProviderPubkey: prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys: prePeginParams.universalChallengerPubkeys,\n hashlock,\n timelockRefund: prePeginParams.timelockRefund,\n network: prePeginParams.network,\n });\n\n const cleanPrePeginHex = fundedPrePeginTxHex.startsWith(\"0x\")\n ? fundedPrePeginTxHex.slice(2)\n : fundedPrePeginTxHex;\n const prePeginTx = Transaction.fromHex(cleanPrePeginHex);\n\n const htlcOutput = prePeginTx.outs[htlcVout];\n if (!htlcOutput) {\n throw new Error(\n `HTLC output at vout ${htlcVout} not found in funded Pre-PegIn tx ` +\n `(tx has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const actualHtlcScriptPubKey = uint8ArrayToHex(\n new Uint8Array(htlcOutput.script),\n ).toLowerCase();\n if (actualHtlcScriptPubKey !== expectedHtlcScriptPubKey) {\n throw new Error(\n `HTLC scriptPubKey mismatch at vout ${htlcVout}: reconstructed ` +\n `template expects ${expectedHtlcScriptPubKey}, funded tx carries ` +\n `${actualHtlcScriptPubKey}. Refund refused — the (hashlocks, ` +\n `pegInAmounts) vector does not match the on-chain commitment.`,\n );\n }\n\n // Value cross-check (mirrors the script check above): the template's\n // HTLC value — derived by WASM from `pegInAmounts` via the protocol\n // formula — must equal the value the funded tx pays at this output.\n // A caller that hands the full HTLC output value (or any wrong amount)\n // as `pegInAmounts` would inflate the template value and trip this\n // guard, rather than silently signing a refund built from a template\n // that disagrees with the on-chain commitment.\n const actualHtlcValue = BigInt(htlcOutput.value);\n if (actualHtlcValue !== expectedHtlcValue) {\n throw new Error(\n `HTLC value mismatch at vout ${htlcVout}: reconstructed template ` +\n `expects ${expectedHtlcValue} sat, funded tx carries ` +\n `${actualHtlcValue} sat. Refund refused — the pegInAmounts vector ` +\n `does not match the on-chain commitment.`,\n );\n }\n\n const refundTx = Transaction.fromHex(refundTxHex);\n\n if (refundTx.ins.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 input, got ${refundTx.ins.length}`,\n );\n }\n\n const refundInput = refundTx.ins[0];\n\n // Verify the refund input spends the correct Pre-PegIn HTLC output\n const prePeginTxid = prePeginTx.getId();\n const refundInputTxid = uint8ArrayToHex(\n new Uint8Array(refundInput.hash).slice().reverse(),\n );\n if (refundInputTxid !== prePeginTxid) {\n throw new Error(\n `Refund input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${refundInputTxid}`,\n );\n }\n if (refundInput.index !== htlcVout) {\n throw new Error(\n `Refund input index ${refundInput.index} does not match expected htlcVout ${htlcVout}`,\n );\n }\n\n const psbt = new Psbt();\n psbt.setVersion(refundTx.version);\n psbt.setLocktime(refundTx.locktime);\n\n psbt.addInput({\n hash: refundInput.hash,\n index: refundInput.index,\n sequence: refundInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hexToUint8Array(htlcConnector.refundScript)),\n controlBlock: Buffer.from(\n hexToUint8Array(htlcConnector.refundControlBlock),\n ),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n });\n\n // Output side: pin the single refund output to the depositor's own\n // BIP-86 P2TR address, mirroring the input-side pinning above. WASM\n // builds the refund output from the refund leaf's depositor key, so a\n // correct template always pays exactly one output back to the depositor.\n // Asserting it here means a malformed template (or a tampered WASM)\n // cannot redirect the reclaimed funds to a script the depositor does\n // not control.\n if (refundTx.outs.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 output, got ${refundTx.outs.length}`,\n );\n }\n const refundOutput = refundTx.outs[0];\n const expectedDepositorScriptPubKey = stripHexPrefix(\n deriveBip86ScriptPubKeyHex(prePeginParams.depositorPubkey),\n ).toLowerCase();\n const actualRefundOutputScriptPubKey = uint8ArrayToHex(\n new Uint8Array(refundOutput.script),\n ).toLowerCase();\n if (actualRefundOutputScriptPubKey !== expectedDepositorScriptPubKey) {\n throw new Error(\n `Refund output scriptPubKey ${actualRefundOutputScriptPubKey} does not ` +\n `match the depositor's BIP-86 address ${expectedDepositorScriptPubKey}. ` +\n `Refund refused — the reclaimed funds would not return to the depositor.`,\n );\n }\n\n // Value: the single refund output must return the full HTLC value minus\n // exactly the requested fee. The refund is 1-in/1-out (asserted above), so\n // a value below `htlcValue - refundFee` means WASM applied a larger fee\n // than requested — the difference would be burned as miner fee. Pin it so\n // the depositor reclaims the expected amount, not a silently reduced one.\n const expectedRefundOutputValue = actualHtlcValue - refundFee;\n if (BigInt(refundOutput.value) !== expectedRefundOutputValue) {\n throw new Error(\n `Refund output value ${BigInt(refundOutput.value)} sat does not equal ` +\n `the HTLC value ${actualHtlcValue} sat minus the requested fee ` +\n `${refundFee} sat (expected ${expectedRefundOutputValue} sat). ` +\n `Refund refused — the reclaimed amount would be burned as excess fee.`,\n );\n }\n\n psbt.addOutput({\n script: refundOutput.script,\n value: refundOutput.value,\n });\n\n return { psbtHex: psbt.toHex() };\n } finally {\n fundedTx?.free();\n unfundedTx.free();\n }\n}\n","/**\n * NoPayout PSBT Builder\n *\n * Builds unsigned PSBTs for the depositor's NoPayout transaction\n * (depositor-as-claimer path, per challenger). The depositor signs input 0\n * using the NoPayout taproot script from WasmAssertPayoutNoPayoutConnector.\n *\n * @module primitives/psbt/noPayout\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md — Assert output 0 NoPayout connector\n */\n\nimport {\n type AssertPayoutNoPayoutConnectorParams,\n type Network,\n getAssertNoPayoutScriptInfo,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction, payments } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n getNetwork,\n hexToUint8Array,\n processPublicKeyToXOnly,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building a NoPayout PSBT\n */\nexport interface NoPayoutParams {\n /** NoPayout transaction hex (unsigned) from VP */\n noPayoutTxHex: string;\n /** Challenger's x-only public key (hex encoded) */\n challengerPubkey: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Parameters for the Assert Payout/NoPayout connector */\n connectorParams: AssertPayoutNoPayoutConnectorParams;\n}\n\n/**\n * Build unsigned NoPayout PSBT.\n *\n * The NoPayout transaction is specific to each challenger.\n * Input 0 is the one the depositor signs using the NoPayout taproot script path.\n *\n * @param params - NoPayout parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildNoPayoutPsbt(\n params: NoPayoutParams,\n): Promise<string> {\n const noPayoutTxHex = stripHexPrefix(params.noPayoutTxHex);\n const noPayoutTx = Transaction.fromHex(noPayoutTxHex);\n\n // Get NoPayout script and control block for this challenger\n const { noPayoutScript, noPayoutControlBlock } =\n await getAssertNoPayoutScriptInfo(\n params.connectorParams,\n params.challengerPubkey,\n );\n\n const scriptBytes = hexToUint8Array(noPayoutScript);\n const controlBlockBytes = hexToUint8Array(noPayoutControlBlock);\n\n const psbt = new Psbt();\n psbt.setVersion(noPayoutTx.version);\n psbt.setLocktime(noPayoutTx.locktime);\n\n // Add all inputs - depositor signs input 0 only\n for (let i = 0; i < noPayoutTx.ins.length; i++) {\n const input = noPayoutTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const inputData: Parameters<typeof psbt.addInput>[0] = {\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n };\n\n // Input 0: depositor signs using taproot script path\n if (i === 0) {\n inputData.tapLeafScript = [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlockBytes),\n },\n ];\n inputData.tapInternalKey = Buffer.from(tapInternalPubkey);\n }\n\n psbt.addInput(inputData);\n }\n\n // Add outputs\n for (const output of noPayoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n\n/**\n * Validate that a NoPayout transaction pays to the challenger via the\n * protocol-defined output structure: a single BIP-86 P2TR output derived from\n * the challenger's x-only pubkey.\n *\n * Mirrors the per-role payout output validation now inlined in\n * `buildPayoutPsbt` for the NoPayout path, where the sink is fixed by the\n * protocol rather than read from on-chain registration\n * (see `crates/vault/src/transactions/nopayout.rs::NoPayoutTx::new`).\n *\n * @param noPayoutTxHex - Raw NoPayout transaction hex\n * @param challengerPubkey - Challenger's x-only public key (hex)\n * @param network - Bitcoin network used to derive the P2TR scriptPubKey\n * @throws If the transaction does not have exactly one output\n * @throws If the single output's scriptPubKey does not equal the BIP-86 P2TR\n * scriptPubKey for the challenger\n */\nexport function assertNoPayoutOutputMatchesChallenger(\n noPayoutTxHex: string,\n challengerPubkey: string,\n network: Network,\n): void {\n const tx = Transaction.fromHex(stripHexPrefix(noPayoutTxHex));\n\n if (tx.outs.length !== 1) {\n throw new Error(\n `NoPayout transaction must have exactly 1 output, got ${tx.outs.length}`,\n );\n }\n\n const xOnly = hexToUint8Array(processPublicKeyToXOnly(challengerPubkey));\n const { output: expectedScript } = payments.p2tr({\n internalPubkey: Buffer.from(xOnly),\n network: getNetwork(network),\n });\n if (!expectedScript) {\n throw new Error(\n \"Failed to derive challenger BIP-86 P2TR scriptPubKey for NoPayout output validation\",\n );\n }\n\n if (!tx.outs[0].script.equals(expectedScript)) {\n throw new Error(\n \"NoPayout transaction does not pay to the expected challenger BIP-86 P2TR address\",\n );\n }\n}\n"],"names":["buildRefundPsbt","params","initWasm","prePeginParams","fundedPrePeginTxHex","htlcVout","refundFee","hashlock","normalizedAuthAnchorHash","normalizeAuthAnchorHash","unfundedTx","WasmPrePeginTx","assertPositiveBigintArray","fundedTx","expectedHtlcScriptPubKey","expectedHtlcValue","refundTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","cleanPrePeginHex","prePeginTx","Transaction","htlcOutput","actualHtlcScriptPubKey","uint8ArrayToHex","actualHtlcValue","refundTx","refundInput","prePeginTxid","refundInputTxid","psbt","Psbt","TAPSCRIPT_LEAF_VERSION","Buffer","hexToUint8Array","tapInternalPubkey","refundOutput","expectedDepositorScriptPubKey","stripHexPrefix","deriveBip86ScriptPubKeyHex","actualRefundOutputScriptPubKey","expectedRefundOutputValue","buildNoPayoutPsbt","noPayoutTxHex","noPayoutTx","noPayoutScript","noPayoutControlBlock","getAssertNoPayoutScriptInfo","scriptBytes","controlBlockBytes","i","input","prevout","inputData","output","assertNoPayoutOutputMatchesChallenger","challengerPubkey","network","tx","xOnly","processPublicKeyToXOnly","expectedScript","payments","getNetwork"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"noPayout-Djrv31V5.cjs","sources":["../src/tbv/core/primitives/psbt/refund.ts","../src/tbv/core/primitives/psbt/noPayout.ts"],"sourcesContent":["/**\n * Refund PSBT Builder Primitive\n *\n * Builds an unsigned refund PSBT for a depositor to reclaim BTC from\n * a timed-out Pre-PegIn HTLC output via the refund script (leaf 1).\n *\n * The refund script enforces a CSV timelock (timelockRefund blocks) and\n * requires only the depositor's Schnorr signature — no vault provider or\n * keeper involvement.\n *\n * @module primitives/psbt/refund\n */\n\nimport {\n assertPositiveBigintArray,\n getPrePeginHtlcConnectorInfo,\n initWasm,\n tapInternalPubkey,\n WasmPrePeginTx,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport { normalizeAuthAnchorHash, type PrePeginParams } from \"./pegin\";\n\n/**\n * Parameters for building a refund PSBT\n */\nexport interface BuildRefundPsbtParams {\n /** Same PrePeginParams used when the original Pre-PegIn tx was created */\n prePeginParams: PrePeginParams;\n /** Funded Pre-PegIn transaction hex (the tx whose HTLC output is being refunded) */\n fundedPrePeginTxHex: string;\n /** Index of the HTLC output in the Pre-PegIn transaction */\n htlcVout: number;\n /** Transaction fee in satoshis for the refund transaction */\n refundFee: bigint;\n /** SHA256 hash commitment for the HTLC (64 hex chars, no 0x prefix) */\n hashlock: string;\n}\n\n/**\n * Result of building a refund PSBT\n */\nexport interface BuildRefundPsbtResult {\n /** PSBT hex ready for depositor signing */\n psbtHex: string;\n}\n\n/**\n * Build a PSBT for signing the refund transaction.\n *\n * The refund transaction spends the Pre-PegIn HTLC output via leaf 1\n * (the refund script: `<timelockRefund> CSV DROP <depositorPubkey> CHECKSIG`).\n * The PSBT includes the tapLeafScript entry so the depositor's wallet can\n * sign using Taproot script-path spending.\n *\n * The input's sequence is set to `timelockRefund` by the WASM, enforcing\n * the Bitcoin CSV timelock. The refund broadcast will be rejected by the\n * network if the timelock has not yet expired.\n *\n * @param params - Refund PSBT parameters\n * @returns PSBT hex for depositor signing\n * @throws If the HTLC output at htlcVout is not found\n * @throws If the refund transaction does not have exactly 1 input\n */\nexport async function buildRefundPsbt(\n params: BuildRefundPsbtParams,\n): Promise<BuildRefundPsbtResult> {\n await initWasm();\n\n const { prePeginParams, fundedPrePeginTxHex, htlcVout, refundFee, hashlock } =\n params;\n\n // The 14th positional arg `auth_anchor_hash` is `Option<String>` in\n // the Rust WASM constructor (the 9th arg `min_pegin_fee_rate` requires\n // the two-rate constructor from btc-vault #1930). Production peg-ins\n // (PeginManager) always commit an OP_RETURN <PUSH32 SHA256(authAnchor)>\n // output at `vout = hashlocks.length`; the unfunded template must\n // include it so `fromFundedTransaction` aligns with the funded tx.\n // Normalize identically to the peg-in primitives (`0x` strip,\n // lowercase, length/charset validation) so a direct primitive caller\n // reusing successful peg-in params doesn't hand unnormalized bytes to\n // WASM. Pass `undefined` for legacy non-auth-anchored Pre-PegIns.\n const normalizedAuthAnchorHash = normalizeAuthAnchorHash(\n prePeginParams.authAnchorHash,\n );\n // Reconstruct the template under the same graph version the Pre-PegIn\n // was originally built with (the vault's stamped vaultCoreVersion).\n const unfundedTx = new WasmPrePeginTx(\n prePeginParams.vaultCoreVersion,\n prePeginParams.depositorPubkey,\n prePeginParams.vaultProviderPubkey,\n prePeginParams.vaultKeeperPubkeys,\n prePeginParams.universalChallengerPubkeys,\n [...prePeginParams.hashlocks],\n new BigUint64Array(\n assertPositiveBigintArray(prePeginParams.pegInAmounts, \"pegInAmounts\"),\n ),\n prePeginParams.timelockRefund,\n prePeginParams.feeRate,\n prePeginParams.minPeginFeeRate,\n prePeginParams.numLocalChallengers,\n prePeginParams.councilQuorum,\n prePeginParams.councilSize,\n prePeginParams.network,\n normalizedAuthAnchorHash,\n );\n\n let fundedTx: WasmPrePeginTx | null = null;\n try {\n // Cross-check the reconstructed unfunded template against the funded\n // transaction: the WASM template's HTLC scriptPubKey at `htlcVout`\n // must equal the bytes the funded tx carries at the same output.\n // If they disagree, the template was reconstructed from the wrong\n // (hashlocks, amounts) vector — signing it would produce a refund\n // that does not spend the on-chain HTLC the depositor expects.\n // This is the explicit invariant the audit recommends: never sign a\n // refund whose template doesn't match the on-chain output bytes.\n const expectedHtlcScriptPubKey = unfundedTx\n .getHtlcScriptPubKey(htlcVout)\n .toLowerCase();\n // The reconstructed template's HTLC output value at `htlcVout`,\n // sized by WASM from the supplied `pegInAmounts` via the protocol\n // formula `htlcValue = peginAmount + depositorClaimValue + minPeginFee`.\n // Captured before `fromFundedTransaction` to bind it to the value the\n // funded tx actually carries (see the cross-check below).\n const expectedHtlcValue = unfundedTx.getHtlcValue(htlcVout);\n\n fundedTx = unfundedTx.fromFundedTransaction(fundedPrePeginTxHex);\n\n const refundTxHex = fundedTx.buildRefundTx(refundFee, htlcVout);\n\n const htlcConnector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: prePeginParams.vaultCoreVersion,\n depositorPubkey: prePeginParams.depositorPubkey,\n vaultProviderPubkey: prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys: prePeginParams.universalChallengerPubkeys,\n hashlock,\n timelockRefund: prePeginParams.timelockRefund,\n network: prePeginParams.network,\n });\n\n const cleanPrePeginHex = fundedPrePeginTxHex.startsWith(\"0x\")\n ? fundedPrePeginTxHex.slice(2)\n : fundedPrePeginTxHex;\n const prePeginTx = Transaction.fromHex(cleanPrePeginHex);\n\n const htlcOutput = prePeginTx.outs[htlcVout];\n if (!htlcOutput) {\n throw new Error(\n `HTLC output at vout ${htlcVout} not found in funded Pre-PegIn tx ` +\n `(tx has ${prePeginTx.outs.length} outputs)`,\n );\n }\n\n const actualHtlcScriptPubKey = uint8ArrayToHex(\n new Uint8Array(htlcOutput.script),\n ).toLowerCase();\n if (actualHtlcScriptPubKey !== expectedHtlcScriptPubKey) {\n throw new Error(\n `HTLC scriptPubKey mismatch at vout ${htlcVout}: reconstructed ` +\n `template expects ${expectedHtlcScriptPubKey}, funded tx carries ` +\n `${actualHtlcScriptPubKey}. Refund refused — the (hashlocks, ` +\n `pegInAmounts) vector does not match the on-chain commitment.`,\n );\n }\n\n // Value cross-check (mirrors the script check above): the template's\n // HTLC value — derived by WASM from `pegInAmounts` via the protocol\n // formula — must equal the value the funded tx pays at this output.\n // A caller that hands the full HTLC output value (or any wrong amount)\n // as `pegInAmounts` would inflate the template value and trip this\n // guard, rather than silently signing a refund built from a template\n // that disagrees with the on-chain commitment.\n const actualHtlcValue = BigInt(htlcOutput.value);\n if (actualHtlcValue !== expectedHtlcValue) {\n throw new Error(\n `HTLC value mismatch at vout ${htlcVout}: reconstructed template ` +\n `expects ${expectedHtlcValue} sat, funded tx carries ` +\n `${actualHtlcValue} sat. Refund refused — the pegInAmounts vector ` +\n `does not match the on-chain commitment.`,\n );\n }\n\n const refundTx = Transaction.fromHex(refundTxHex);\n\n if (refundTx.ins.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 input, got ${refundTx.ins.length}`,\n );\n }\n\n const refundInput = refundTx.ins[0];\n\n // Verify the refund input spends the correct Pre-PegIn HTLC output\n const prePeginTxid = prePeginTx.getId();\n const refundInputTxid = uint8ArrayToHex(\n new Uint8Array(refundInput.hash).slice().reverse(),\n );\n if (refundInputTxid !== prePeginTxid) {\n throw new Error(\n `Refund input does not reference the Pre-PegIn transaction. ` +\n `Expected ${prePeginTxid}, got ${refundInputTxid}`,\n );\n }\n if (refundInput.index !== htlcVout) {\n throw new Error(\n `Refund input index ${refundInput.index} does not match expected htlcVout ${htlcVout}`,\n );\n }\n\n const psbt = new Psbt();\n psbt.setVersion(refundTx.version);\n psbt.setLocktime(refundTx.locktime);\n\n psbt.addInput({\n hash: refundInput.hash,\n index: refundInput.index,\n sequence: refundInput.sequence,\n witnessUtxo: {\n script: htlcOutput.script,\n value: htlcOutput.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hexToUint8Array(htlcConnector.refundScript)),\n controlBlock: Buffer.from(\n hexToUint8Array(htlcConnector.refundControlBlock),\n ),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n });\n\n // Output side: pin the single refund output to the depositor's own\n // BIP-86 P2TR address, mirroring the input-side pinning above. WASM\n // builds the refund output from the refund leaf's depositor key, so a\n // correct template always pays exactly one output back to the depositor.\n // Asserting it here means a malformed template (or a tampered WASM)\n // cannot redirect the reclaimed funds to a script the depositor does\n // not control.\n if (refundTx.outs.length !== 1) {\n throw new Error(\n `Refund transaction must have exactly 1 output, got ${refundTx.outs.length}`,\n );\n }\n const refundOutput = refundTx.outs[0];\n const expectedDepositorScriptPubKey = stripHexPrefix(\n deriveBip86ScriptPubKeyHex(prePeginParams.depositorPubkey),\n ).toLowerCase();\n const actualRefundOutputScriptPubKey = uint8ArrayToHex(\n new Uint8Array(refundOutput.script),\n ).toLowerCase();\n if (actualRefundOutputScriptPubKey !== expectedDepositorScriptPubKey) {\n throw new Error(\n `Refund output scriptPubKey ${actualRefundOutputScriptPubKey} does not ` +\n `match the depositor's BIP-86 address ${expectedDepositorScriptPubKey}. ` +\n `Refund refused — the reclaimed funds would not return to the depositor.`,\n );\n }\n\n // Value: the single refund output must return the full HTLC value minus\n // exactly the requested fee. The refund is 1-in/1-out (asserted above), so\n // a value below `htlcValue - refundFee` means WASM applied a larger fee\n // than requested — the difference would be burned as miner fee. Pin it so\n // the depositor reclaims the expected amount, not a silently reduced one.\n const expectedRefundOutputValue = actualHtlcValue - refundFee;\n if (BigInt(refundOutput.value) !== expectedRefundOutputValue) {\n throw new Error(\n `Refund output value ${BigInt(refundOutput.value)} sat does not equal ` +\n `the HTLC value ${actualHtlcValue} sat minus the requested fee ` +\n `${refundFee} sat (expected ${expectedRefundOutputValue} sat). ` +\n `Refund refused — the reclaimed amount would be burned as excess fee.`,\n );\n }\n\n psbt.addOutput({\n script: refundOutput.script,\n value: refundOutput.value,\n });\n\n return { psbtHex: psbt.toHex() };\n } finally {\n fundedTx?.free();\n unfundedTx.free();\n }\n}\n","/**\n * NoPayout PSBT Builder\n *\n * Builds unsigned PSBTs for the depositor's NoPayout transaction\n * (depositor-as-claimer path, per challenger). The depositor signs input 0\n * using the NoPayout taproot script from WasmAssertPayoutNoPayoutConnector.\n *\n * @module primitives/psbt/noPayout\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md — Assert output 0 NoPayout connector\n */\n\nimport {\n type AssertPayoutNoPayoutConnectorParams,\n type Network,\n getAssertNoPayoutScriptInfo,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction, payments } from \"bitcoinjs-lib\";\n\nimport {\n TAPSCRIPT_LEAF_VERSION,\n getNetwork,\n hexToUint8Array,\n processPublicKeyToXOnly,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n/**\n * Parameters for building a NoPayout PSBT\n */\nexport interface NoPayoutParams {\n /** NoPayout transaction hex (unsigned) from VP */\n noPayoutTxHex: string;\n /** Challenger's x-only public key (hex encoded) */\n challengerPubkey: string;\n /** Prevouts for all inputs [{script_pubkey, value}] from VP */\n prevouts: Array<{ script_pubkey: string; value: number }>;\n /** Parameters for the Assert Payout/NoPayout connector */\n connectorParams: AssertPayoutNoPayoutConnectorParams;\n}\n\n/**\n * Build unsigned NoPayout PSBT.\n *\n * The NoPayout transaction is specific to each challenger.\n * Input 0 is the one the depositor signs using the NoPayout taproot script path.\n *\n * @param params - NoPayout parameters\n * @returns Unsigned PSBT hex ready for signing\n */\nexport async function buildNoPayoutPsbt(\n params: NoPayoutParams,\n): Promise<string> {\n const noPayoutTxHex = stripHexPrefix(params.noPayoutTxHex);\n const noPayoutTx = Transaction.fromHex(noPayoutTxHex);\n\n // Get NoPayout script and control block for this challenger\n const { noPayoutScript, noPayoutControlBlock } =\n await getAssertNoPayoutScriptInfo(\n params.connectorParams,\n params.challengerPubkey,\n );\n\n const scriptBytes = hexToUint8Array(noPayoutScript);\n const controlBlockBytes = hexToUint8Array(noPayoutControlBlock);\n\n const psbt = new Psbt();\n psbt.setVersion(noPayoutTx.version);\n psbt.setLocktime(noPayoutTx.locktime);\n\n // Add all inputs - depositor signs input 0 only\n for (let i = 0; i < noPayoutTx.ins.length; i++) {\n const input = noPayoutTx.ins[i];\n const prevout = params.prevouts[i];\n\n if (!prevout) {\n throw new Error(`Missing prevout data for input ${i}`);\n }\n\n const inputData: Parameters<typeof psbt.addInput>[0] = {\n hash: input.hash,\n index: input.index,\n sequence: input.sequence,\n witnessUtxo: {\n script: Buffer.from(hexToUint8Array(stripHexPrefix(prevout.script_pubkey))),\n value: prevout.value,\n },\n };\n\n // Input 0: depositor signs using taproot script path\n if (i === 0) {\n inputData.tapLeafScript = [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(scriptBytes),\n controlBlock: Buffer.from(controlBlockBytes),\n },\n ];\n inputData.tapInternalKey = Buffer.from(tapInternalPubkey);\n }\n\n psbt.addInput(inputData);\n }\n\n // Add outputs\n for (const output of noPayoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n\n/**\n * Validate that a NoPayout transaction pays to the challenger via the\n * protocol-defined output structure: a single BIP-86 P2TR output derived from\n * the challenger's x-only pubkey.\n *\n * Mirrors the per-role payout output validation now inlined in\n * `buildPayoutPsbt` for the NoPayout path, where the sink is fixed by the\n * protocol rather than read from on-chain registration\n * (see `crates/vault/src/transactions/nopayout.rs::NoPayoutTx::new`).\n *\n * @param noPayoutTxHex - Raw NoPayout transaction hex\n * @param challengerPubkey - Challenger's x-only public key (hex)\n * @param network - Bitcoin network used to derive the P2TR scriptPubKey\n * @throws If the transaction does not have exactly one output\n * @throws If the single output's scriptPubKey does not equal the BIP-86 P2TR\n * scriptPubKey for the challenger\n */\nexport function assertNoPayoutOutputMatchesChallenger(\n noPayoutTxHex: string,\n challengerPubkey: string,\n network: Network,\n): void {\n const tx = Transaction.fromHex(stripHexPrefix(noPayoutTxHex));\n\n if (tx.outs.length !== 1) {\n throw new Error(\n `NoPayout transaction must have exactly 1 output, got ${tx.outs.length}`,\n );\n }\n\n const xOnly = hexToUint8Array(processPublicKeyToXOnly(challengerPubkey));\n const { output: expectedScript } = payments.p2tr({\n internalPubkey: Buffer.from(xOnly),\n network: getNetwork(network),\n });\n if (!expectedScript) {\n throw new Error(\n \"Failed to derive challenger BIP-86 P2TR scriptPubKey for NoPayout output validation\",\n );\n }\n\n if (!tx.outs[0].script.equals(expectedScript)) {\n throw new Error(\n \"NoPayout transaction does not pay to the expected challenger BIP-86 P2TR address\",\n );\n }\n}\n"],"names":["buildRefundPsbt","params","initWasm","prePeginParams","fundedPrePeginTxHex","htlcVout","refundFee","hashlock","normalizedAuthAnchorHash","normalizeAuthAnchorHash","unfundedTx","WasmPrePeginTx","assertPositiveBigintArray","fundedTx","expectedHtlcScriptPubKey","expectedHtlcValue","refundTxHex","htlcConnector","getPrePeginHtlcConnectorInfo","cleanPrePeginHex","prePeginTx","Transaction","htlcOutput","actualHtlcScriptPubKey","uint8ArrayToHex","actualHtlcValue","refundTx","refundInput","prePeginTxid","refundInputTxid","psbt","Psbt","TAPSCRIPT_LEAF_VERSION","Buffer","hexToUint8Array","tapInternalPubkey","refundOutput","expectedDepositorScriptPubKey","stripHexPrefix","deriveBip86ScriptPubKeyHex","actualRefundOutputScriptPubKey","expectedRefundOutputValue","buildNoPayoutPsbt","noPayoutTxHex","noPayoutTx","noPayoutScript","noPayoutControlBlock","getAssertNoPayoutScriptInfo","scriptBytes","controlBlockBytes","i","input","prevout","inputData","output","assertNoPayoutOutputMatchesChallenger","challengerPubkey","network","tx","xOnly","processPublicKeyToXOnly","expectedScript","payments","getNetwork"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const c=require("@bitcoin-js/tiny-secp256k1-asmjs"),o=require("./bitcoin-CHfKAhcI.cjs");function i(t){const r=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const e in t)if(e!=="default"){const n=Object.getOwnPropertyDescriptor(t,e);Object.defineProperty(r,e,n.get?n:{enumerable:!0,get:()=>t[e]})}}return r.default=t,Object.freeze(r)}const s=i(c);function u(t,r){const e=t.toLowerCase();if(!/^0x[0-9a-f]{64}$/.test(e))throw new Error(`${r} returned an unexpected value (length ${e.length}, prefix "${e.slice(0,2)}")`);const n=e.slice(2);if(!s.isXOnlyPoint(o.hexToUint8Array(n)))throw new Error(`${r} returned a value that is not on the secp256k1 curve`);return n}exports.assertOnChainBtcPubkey=u;
|
|
2
|
+
//# sourceMappingURL=onChainBtcPubkey-Cd9kpz-S.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onChainBtcPubkey-Cd9kpz-S.cjs","sources":["../src/tbv/core/clients/eth/onChainBtcPubkey.ts"],"sourcesContent":["/**\n * The single validator that mints {@link OnChainBtcPubkey}.\n *\n * Extracted from `ViemVaultRegistryReader.getVaultProviderBtcPubKey` so that\n * RFC-006 operation-key resolution can produce branded keys through exactly\n * the same checks, rather than casting past the brand. Every producer of an\n * `OnChainBtcPubkey` must go through here.\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport type { Hex } from \"viem\";\n\nimport { hexToUint8Array } from \"../../primitives/utils/bitcoin\";\nimport type { OnChainBtcPubkey } from \"./types\";\n\n/**\n * Validate a registry-returned `bytes32` as an x-only BTC pubkey and mint the\n * brand. Checks length, hex form, and secp256k1 curve membership. Returns\n * 64-char lowercase hex without the `0x` prefix.\n *\n * `label` identifies the read site in error messages (e.g.\n * `getVaultProviderBTCKey (vp=0x…)`), so a failure names which participant and\n * which getter produced it.\n *\n * A zero hash fails the curve check, so an unregistered operator or an epoch\n * with no bonded key surfaces as an error rather than a silent all-zero key.\n */\nexport function assertOnChainBtcPubkey(\n value: Hex,\n label: string,\n): OnChainBtcPubkey {\n const lowered = value.toLowerCase();\n if (!/^0x[0-9a-f]{64}$/.test(lowered)) {\n throw new Error(\n `${label} returned an unexpected value (length ${lowered.length}, prefix \"${lowered.slice(0, 2)}\")`,\n );\n }\n const stripped = lowered.slice(2);\n if (!ecc.isXOnlyPoint(hexToUint8Array(stripped))) {\n throw new Error(\n `${label} returned a value that is not on the secp256k1 curve`,\n );\n }\n return stripped as OnChainBtcPubkey;\n}\n"],"names":["assertOnChainBtcPubkey","value","label","lowered","stripped","ecc","hexToUint8Array"],"mappings":"+XA2BO,SAASA,EACdC,EACAC,EACkB,CAClB,MAAMC,EAAUF,EAAM,YAAA,EACtB,GAAI,CAAC,mBAAmB,KAAKE,CAAO,EAClC,MAAM,IAAI,MACR,GAAGD,CAAK,yCAAyCC,EAAQ,MAAM,aAAaA,EAAQ,MAAM,EAAG,CAAC,CAAC,IAAA,EAGnG,MAAMC,EAAWD,EAAQ,MAAM,CAAC,EAChC,GAAI,CAACE,EAAI,aAAaC,EAAAA,gBAAgBF,CAAQ,CAAC,EAC7C,MAAM,IAAI,MACR,GAAGF,CAAK,sDAAA,EAGZ,OAAOE,CACT"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as o from "@bitcoin-js/tiny-secp256k1-asmjs";
|
|
2
|
+
import { h as s } from "./bitcoin-B5aNKtsk.js";
|
|
3
|
+
function a(n, r) {
|
|
4
|
+
const e = n.toLowerCase();
|
|
5
|
+
if (!/^0x[0-9a-f]{64}$/.test(e))
|
|
6
|
+
throw new Error(
|
|
7
|
+
`${r} returned an unexpected value (length ${e.length}, prefix "${e.slice(0, 2)}")`
|
|
8
|
+
);
|
|
9
|
+
const t = e.slice(2);
|
|
10
|
+
if (!o.isXOnlyPoint(s(t)))
|
|
11
|
+
throw new Error(
|
|
12
|
+
`${r} returned a value that is not on the secp256k1 curve`
|
|
13
|
+
);
|
|
14
|
+
return t;
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
a
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=onChainBtcPubkey-aPY5ib3Q.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"onChainBtcPubkey-aPY5ib3Q.js","sources":["../src/tbv/core/clients/eth/onChainBtcPubkey.ts"],"sourcesContent":["/**\n * The single validator that mints {@link OnChainBtcPubkey}.\n *\n * Extracted from `ViemVaultRegistryReader.getVaultProviderBtcPubKey` so that\n * RFC-006 operation-key resolution can produce branded keys through exactly\n * the same checks, rather than casting past the brand. Every producer of an\n * `OnChainBtcPubkey` must go through here.\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport type { Hex } from \"viem\";\n\nimport { hexToUint8Array } from \"../../primitives/utils/bitcoin\";\nimport type { OnChainBtcPubkey } from \"./types\";\n\n/**\n * Validate a registry-returned `bytes32` as an x-only BTC pubkey and mint the\n * brand. Checks length, hex form, and secp256k1 curve membership. Returns\n * 64-char lowercase hex without the `0x` prefix.\n *\n * `label` identifies the read site in error messages (e.g.\n * `getVaultProviderBTCKey (vp=0x…)`), so a failure names which participant and\n * which getter produced it.\n *\n * A zero hash fails the curve check, so an unregistered operator or an epoch\n * with no bonded key surfaces as an error rather than a silent all-zero key.\n */\nexport function assertOnChainBtcPubkey(\n value: Hex,\n label: string,\n): OnChainBtcPubkey {\n const lowered = value.toLowerCase();\n if (!/^0x[0-9a-f]{64}$/.test(lowered)) {\n throw new Error(\n `${label} returned an unexpected value (length ${lowered.length}, prefix \"${lowered.slice(0, 2)}\")`,\n );\n }\n const stripped = lowered.slice(2);\n if (!ecc.isXOnlyPoint(hexToUint8Array(stripped))) {\n throw new Error(\n `${label} returned a value that is not on the secp256k1 curve`,\n );\n }\n return stripped as OnChainBtcPubkey;\n}\n"],"names":["assertOnChainBtcPubkey","value","label","lowered","stripped","ecc","hexToUint8Array"],"mappings":";;AA2BO,SAASA,EACdC,GACAC,GACkB;AAClB,QAAMC,IAAUF,EAAM,YAAA;AACtB,MAAI,CAAC,mBAAmB,KAAKE,CAAO;AAClC,UAAM,IAAI;AAAA,MACR,GAAGD,CAAK,yCAAyCC,EAAQ,MAAM,aAAaA,EAAQ,MAAM,GAAG,CAAC,CAAC;AAAA,IAAA;AAGnG,QAAMC,IAAWD,EAAQ,MAAM,CAAC;AAChC,MAAI,CAACE,EAAI,aAAaC,EAAgBF,CAAQ,CAAC;AAC7C,UAAM,IAAI;AAAA,MACR,GAAGF,CAAK;AAAA,IAAA;AAGZ,SAAOE;AACT;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var ke=Object.defineProperty;var Te=(r,e,t)=>e in r?ke(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t;var m=(r,e,t)=>Te(r,typeof e!="symbol"?e+"":e,t);const O=require("./BTCVaultRegistry.abi-AUAyCHal.cjs"),f=require("./ProtocolParams.abi-C8U7BHCS.cjs"),I=require("./mempoolApi-Dsm2VPXp.cjs"),X=require("./json-rpc-client-fUoK-TzT.cjs"),_=require("./bitcoin-CHfKAhcI.cjs"),Q=require("./constants-BqU1Uz15.cjs"),k=require("./validation-CDbOaDj7.cjs"),$e=require("@bitcoin-js/tiny-secp256k1-asmjs"),N=require("bitcoinjs-lib"),V=require("buffer"),J=require("./sha2-DsrLC4NM.cjs");function Re(r){const e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const t in r)if(t!=="default"){const n=Object.getOwnPropertyDescriptor(r,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:()=>r[t]})}}return e.default=r,Object.freeze(e)}const j=Re($e);async function Ie(r,e){const[t,n]=await r.multicall({contracts:[{address:e,abi:O.BTCVaultRegistryABI,functionName:"protocolParams"},{address:e,abi:O.BTCVaultRegistryABI,functionName:"applicationRegistry"}],allowFailure:!1});return{protocolParams:t,applicationRegistry:n}}function Ve(r,e){return{vaultProvider:r[0],vaultKeepers:r.slice(1,1+e),universalChallengers:r.slice(1+e)}}class Be{constructor(e,t){this.publicClient=e,this.contracts=t}async readAll(e,t){const n=await this.publicClient.multicall({contracts:e,allowFailure:!1});return Ve(n,t)}async getCurrentOperationKeys(e){const t=[{address:this.contracts.btcVaultRegistry,abi:O.BTCVaultRegistryABI,functionName:"getCurrentOperationBtcKey",args:[e.vaultProviderEthAddress]},...e.vaultKeepers.map(n=>({address:this.contracts.applicationRegistry,abi:f.ApplicationRegistryABI,functionName:"getCurrentOperationBtcKey",args:[e.applicationEntryPoint,n.ethAddress]})),...e.universalChallengers.map(n=>({address:this.contracts.protocolParams,abi:f.ProtocolParamsABI,functionName:"getCurrentOperationBtcKey",args:[n.ethAddress]}))];return this.readAll(t,e.vaultKeepers.length)}async getOperationKeysAtEpochs(e,t){const n=[{address:this.contracts.btcVaultRegistry,abi:O.BTCVaultRegistryABI,functionName:"getOperationBtcKeyAtEpoch",args:[e.vaultProviderEthAddress,t.vpKeyEpoch]},...e.vaultKeepers.map(i=>({address:this.contracts.applicationRegistry,abi:f.ApplicationRegistryABI,functionName:"getOperationBtcKeyAtEpochOrGenesis",args:[e.applicationEntryPoint,i.ethAddress,t.appKeeperKeyEpoch,i.btcPubKey]})),...e.universalChallengers.map(i=>({address:this.contracts.protocolParams,abi:f.ProtocolParamsABI,functionName:"getOperationBtcKeyAtEpochOrGenesis",args:[i.ethAddress,t.ucKeyEpoch,i.btcPubKey]}))];return this.readAll(n,e.vaultKeepers.length)}async getPayoutScriptsAtEpochs(e,t){const n=await this.publicClient.multicall({contracts:[{address:this.contracts.btcVaultRegistry,abi:O.BTCVaultRegistryABI,functionName:"getPayoutScriptAtEpoch",args:[e.vaultProviderEthAddress,t.vpKeyEpoch]},...e.vaultKeepers.map(i=>({address:this.contracts.applicationRegistry,abi:f.ApplicationRegistryABI,functionName:"getPayoutScriptAtEpoch",args:[e.applicationEntryPoint,i.ethAddress,t.appKeeperKeyEpoch]}))],allowFailure:!1});return{vaultProvider:n[0],vaultKeepers:[...n.slice(1)]}}}const ee=65535;function H(r){return{timelockAssert:r.timelockAssert,timelockChallengeAssert:r.timelockChallengeAssert,securityCouncilKeys:[...r.securityCouncilKeys],councilQuorum:r.councilQuorum,feeRate:r.feeRate,babeTotalInstances:r.babeTotalInstances,babeInstancesToFinalize:r.babeInstancesToFinalize,minVpCommissionBps:r.minVpCommissionBps,tRefund:r.tRefund,tStale:r.tStale,minPeginFeeRate:r.minPeginFeeRate,proverCircuitVersion:r.proverCircuitVersion,minPrepeginDepth:r.minPrepeginDepth}}function te(r){return{minimumPegInAmount:r.minimumPegInAmount,maxPegInAmount:r.maxPegInAmount,pegInAckTimeout:r.pegInAckTimeout,pegInActivationTimeout:r.pegInActivationTimeout,maxHtlcOutputCount:r.maxHtlcOutputCount,expiredPegInGraceBlocks:r.expiredPegInGraceBlocks}}function re(r){if(r>BigInt(ee))throw new Error(`timelockAssert value ${r} exceeds uint16 max (${ee})`);return Number(r)}class Oe{constructor(e,t){this.publicClient=e,this.contractAddress=t}async getTBVProtocolParams(){const e=await this.publicClient.readContract({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getTBVProtocolParams"}),t=te(e);return I.validateTBVProtocolParams(t),t}async getLatestOffchainParams(){const e=await this.publicClient.readContract({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getLatestOffchainParams"}),t=H(e);return I.validateOffchainParams(t),t}async getOffchainParamsByVersion(e){const t=await this.publicClient.readContract({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getOffchainParamsByVersion",args:[e]}),n=H(t);return I.validateOffchainParams(n),n}async getLatestOffchainParamsVersion(){const e=await this.publicClient.readContract({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"latestOffchainParamsVersion"}),t=Number(e);return I.assertValidOffchainParamsVersion(t),t}async getTimelockPeginByVersion(e){const t=await this.getOffchainParamsByVersion(e);return re(t.timelockAssert)}async getPegInConfiguration(){const e=await this.publicClient.multicall({contracts:[{address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getTBVProtocolParams"},{address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getLatestOffchainParams"},{address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"latestOffchainParamsVersion"},{address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"activeVaultCoreVersion"}],allowFailure:!1}),t=te(e[0]),n=H(e[1]),i=Number(e[2]),s=Number(e[3]),a={minimumPegInAmount:t.minimumPegInAmount,maxPegInAmount:t.maxPegInAmount,pegInAckTimeout:t.pegInAckTimeout,pegInActivationTimeout:t.pegInActivationTimeout,maxHtlcOutputCount:t.maxHtlcOutputCount,expiredPegInGraceBlocks:t.expiredPegInGraceBlocks,timelockPegin:re(n.timelockAssert),timelockRefund:n.tRefund,minVpCommissionBps:n.minVpCommissionBps,offchainParams:n,offchainParamsVersion:i,activeVaultCoreVersion:s};return I.validatePegInConfiguration(a),a}async fetchAllOffchainParams(e){const t=await this.getLatestOffchainParamsVersion();if(t===0)return{byVersion:new Map,latestVersion:0};const n=Array.from({length:t},(c,d)=>d+1),i=n.map(c=>({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getOffchainParamsByVersion",args:[c]})),s=await this.publicClient.multicall({contracts:i,allowFailure:!1}),a=new Map;for(let c=0;c<n.length;c++){const d=H(s[c]);try{I.validateOffchainParams(d),a.set(n[c],d)}catch(l){e==null||e(n[c],l instanceof Error?l:new Error(String(l)))}}return{byVersion:a,latestVersion:t}}}function G(r){return r.map(e=>({ethAddress:e.ethAddress,btcPubKey:e.btcPubKey}))}class Ne{constructor(e,t){this.publicClient=e,this.contractAddress=t}async getVaultKeepersByVersion(e,t){const n=await this.publicClient.readContract({address:this.contractAddress,abi:f.ApplicationRegistryABI,functionName:"getVaultKeepersByVersion",args:[e,t]});return G(n)}async getCurrentVaultKeepers(e){const t=await this.publicClient.readContract({address:this.contractAddress,abi:f.ApplicationRegistryABI,functionName:"getCurrentVaultKeepers",args:[e]});return G(t)}async getCurrentVaultKeepersVersion(e){return await this.publicClient.readContract({address:this.contractAddress,abi:f.ApplicationRegistryABI,functionName:"getCurrentVaultKeepersVersion",args:[e]})}}class He{constructor(e,t){this.publicClient=e,this.contractAddress=t}async getUniversalChallengersByVersion(e){const t=await this.publicClient.readContract({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getUniversalChallengersByVersion",args:[e]});return G(t)}async getCurrentUniversalChallengers(){const e=await this.publicClient.readContract({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"getCurrentUniversalChallengers"});return G(e)}async getLatestUniversalChallengersVersion(){return await this.publicClient.readContract({address:this.contractAddress,abi:f.ProtocolParamsABI,functionName:"latestUniversalChallengersVersion"})}}var he=(r=>(r[r.PENDING=0]="PENDING",r[r.VERIFIED=1]="VERIFIED",r[r.ACTIVE=2]="ACTIVE",r[r.REDEEMED=3]="REDEEMED",r[r.EXPIRED=4]="EXPIRED",r))(he||{});const ne=new Set(Object.values(X.DaemonStatus)),Le=200;function h(r){var e;return((e=JSON.stringify(r))==null?void 0:e.slice(0,Le))??"undefined"}const De="The vault provider returned an unexpected response. Please try again or contact support.";class o extends Error{constructor(t){super(De);m(this,"detail");this.name="VpResponseValidationError",this.detail=t}}const B=64;function $(r){return typeof r=="string"&&r.length>0&&k.HEX_RE.test(r)}function ge(r){return typeof r=="string"&&r.length>0}function fe(r,e){if(!$(r))throw new o(`VP response validation failed: "${e}" must be a non-empty hex string, got ${h(r)}`)}function P(r,e){if(!ge(r))throw new o(`VP response validation failed: "${e}" must be a non-empty string, got ${h(r)}`)}function z(r,e){if(!$(r)||r.length!==_.X_ONLY_PUBKEY_HEX_LEN&&r.length!==_.COMPRESSED_PUBKEY_HEX_LEN)throw new o(`VP response validation failed: "${e}" must be a ${_.X_ONLY_PUBKEY_HEX_LEN} or ${_.COMPRESSED_PUBKEY_HEX_LEN}-char hex string (BTC pubkey), got ${h(r)}`)}function Ge(r){const e=r.presigning;if(e==null)return;if(typeof e!="object"||Array.isArray(e))throw new o('VP response validation failed: "progress.presigning" must be an object if present');const t=e;if(t.depositor_graph_created!==void 0&&typeof t.depositor_graph_created!="boolean")throw new o(`VP response validation failed: "progress.presigning.depositor_graph_created" must be a boolean if present, got ${h(t.depositor_graph_created)}`);if(t.vk_challenger_presigning_completed!==void 0&&typeof t.vk_challenger_presigning_completed!="number")throw new o(`VP response validation failed: "progress.presigning.vk_challenger_presigning_completed" must be a number if present, got ${h(t.vk_challenger_presigning_completed)}`);if(t.vk_challenger_presigning_total!==void 0&&typeof t.vk_challenger_presigning_total!="number")throw new o(`VP response validation failed: "progress.presigning.vk_challenger_presigning_total" must be a number if present, got ${h(t.vk_challenger_presigning_total)}`)}function _e(r){if(r===null||typeof r!="object")throw new o("VP response validation failed: getPeginStatus response is not an object");const e=r;if(!$(e.pegin_txid)||e.pegin_txid.length!==B)throw new o(`VP response validation failed: "pegin_txid" must be a ${B}-char hex string (txid), got ${h(e.pegin_txid)}`);if(typeof e.status!="string")throw new o('VP response validation failed: "status" must be a string');if(!ne.has(e.status))throw new o(`VP response validation failed: unrecognized status "${e.status}". Expected one of: ${[...ne].join(", ")}`);if(e.progress===null||typeof e.progress!="object"||Array.isArray(e.progress))throw new o('VP response validation failed: "progress" must be an object');if(Ge(e.progress),typeof e.health_info!="string")throw new o('VP response validation failed: "health_info" must be a string');if(e.last_error!==void 0&&typeof e.last_error!="string")throw new o(`VP response validation failed: "last_error" must be a string if present, got ${h(e.last_error)}`)}function Me(r){if(r===null||typeof r!="object")throw new o("VP response validation failed: requestDepositorPresignTransactions response is not an object");const e=r;if(!Array.isArray(e.txs))throw new o('VP response validation failed: "txs" must be an array');for(let t=0;t<e.txs.length;t++)Xe(e.txs[t],`txs[${t}]`);if(e.depositor_graph===null||typeof e.depositor_graph!="object")throw new o('VP response validation failed: "depositor_graph" must be an object');We(e.depositor_graph)}function E(r,e){if(r===null||typeof r!="object")throw new o(`VP response validation failed: "${e}" must be an object`);fe(r.tx_hex,`${e}.tx_hex`)}function Xe(r,e){if(r===null||typeof r!="object")throw new o(`VP response validation failed: "${e}" must be an object`);const t=r;z(t.claimer_pubkey,`${e}.claimer_pubkey`),E(t.claim_tx,`${e}.claim_tx`),E(t.assert_tx,`${e}.assert_tx`),E(t.payout_tx,`${e}.payout_tx`),P(t.payout_psbt,`${e}.payout_psbt`)}function je(r,e){if(r===null||typeof r!="object")throw new o(`VP response validation failed: "${e}" must be an object`);const t=r;P(t.wots_pks_json,`${e}.wots_pks_json`),P(t.gc_wots_keys_json,`${e}.gc_wots_keys_json`)}function Ke(r,e){if(r===null||typeof r!="object")throw new o(`VP response validation failed: "${e}" must be an object`);const t=r;if(z(t.challenger_pubkey,`${e}.challenger_pubkey`),E(t.challenge_assert_x_tx,`${e}.challenge_assert_x_tx`),E(t.challenge_assert_y_tx,`${e}.challenge_assert_y_tx`),E(t.nopayout_tx,`${e}.nopayout_tx`),P(t.nopayout_psbt,`${e}.nopayout_psbt`),!Array.isArray(t.challenge_assert_connectors))throw new o(`VP response validation failed: "${e}.challenge_assert_connectors" must be an array`);if(t.challenge_assert_connectors.length!==Q.CHALLENGE_ASSERT_CONNECTORS_PER_CHALLENGER)throw new o(`VP response validation failed: "${e}.challenge_assert_connectors" must have exactly ${Q.CHALLENGE_ASSERT_CONNECTORS_PER_CHALLENGER} entries, got ${t.challenge_assert_connectors.length}`);for(let n=0;n<t.challenge_assert_connectors.length;n++)je(t.challenge_assert_connectors[n],`${e}.challenge_assert_connectors[${n}]`);if(!Array.isArray(t.output_label_hashes))throw new o(`VP response validation failed: "${e}.output_label_hashes" must be an array`);for(let n=0;n<t.output_label_hashes.length;n++)fe(t.output_label_hashes[n],`${e}.output_label_hashes[${n}]`)}function me(r){if(r===null||typeof r!="object")throw new o("VP response validation failed: requestDepositorClaimerArtifacts response is not an object");const e=r;if(!ge(e.tx_graph_json))throw new o(`VP response validation failed: "tx_graph_json" must be a non-empty string, got ${h(e.tx_graph_json)}`);if(!$(e.verifying_key_hex))throw new o(`VP response validation failed: "verifying_key_hex" must be a non-empty hex string, got ${h(e.verifying_key_hex)}`);if(e.babe_sessions===null||typeof e.babe_sessions!="object"||Array.isArray(e.babe_sessions))throw new o('VP response validation failed: "babe_sessions" must be an object');const t=Object.entries(e.babe_sessions);if(t.length===0)throw new o('VP response validation failed: "babe_sessions" must contain at least one challenger entry');for(const[n,i]of t){if(z(n,`babe_sessions["${n}"]`),i===null||typeof i!="object")throw new o(`VP response validation failed: "babe_sessions.${n}" must be an object`);const s=i;if(!$(s.decryptor_artifacts_hex))throw new o(`VP response validation failed: "babe_sessions.${n}.decryptor_artifacts_hex" must be a non-empty hex string, got ${h(s.decryptor_artifacts_hex)}`)}}function Ue(r){if(r===null||typeof r!="object")throw new o("VP response validation failed: pegout status payload is not an object");const e=r;if(!$(e.pegin_txid)||e.pegin_txid.length!==B)throw new o(`VP response validation failed: "pegin_txid" must be a ${B}-char hex string (txid), got ${h(e.pegin_txid)}`);if(typeof e.found!="boolean")throw new o(`VP response validation failed: "found" must be a boolean, got ${h(e.found)}`);if(e.claimer!==null){if(typeof e.claimer!="object")throw new o(`VP response validation failed: "claimer" must be an object or null, got ${h(e.claimer)}`);Fe(e.claimer)}if(!Array.isArray(e.challengers))throw new o(`VP response validation failed: "challengers" must be an array, got ${h(e.challengers)}`);for(let t=0;t<e.challengers.length;t++)Je(e.challengers[t],t)}function Fe(r){if(P(r.status,"claimer.status"),typeof r.failed!="boolean")throw new o(`VP response validation failed: "claimer.failed" must be a boolean, got ${h(r.failed)}`);if(P(r.claim_txid,"claimer.claim_txid"),P(r.claimer_pubkey,"claimer.claimer_pubkey"),P(r.assert_txid,"claimer.assert_txid"),typeof r.created_at!="number")throw new o(`VP response validation failed: "claimer.created_at" must be a number, got ${h(r.created_at)}`);if(typeof r.updated_at!="number")throw new o(`VP response validation failed: "claimer.updated_at" must be a number, got ${h(r.updated_at)}`)}function Je(r,e){if(r===null||typeof r!="object")throw new o(`VP response validation failed: "challengers[${e}]" must be an object, got ${h(r)}`);const t=r;if(P(t.status,`challengers[${e}].status`),P(t.claim_txid,`challengers[${e}].claim_txid`),P(t.claimer_pubkey,`challengers[${e}].claimer_pubkey`),L(t.assert_txid,`challengers[${e}].assert_txid`),L(t.challenge_assert_x_txid,`challengers[${e}].challenge_assert_x_txid`),L(t.challenge_assert_y_txid,`challengers[${e}].challenge_assert_y_txid`),L(t.nopayout_txid,`challengers[${e}].nopayout_txid`),typeof t.created_at!="number")throw new o(`VP response validation failed: "challengers[${e}].created_at" must be a number, got ${h(t.created_at)}`);if(typeof t.updated_at!="number")throw new o(`VP response validation failed: "challengers[${e}].updated_at" must be a number, got ${h(t.updated_at)}`)}function L(r,e){if(r!==null&&typeof r!="string")throw new o(`VP response validation failed: "${e}" must be a string or null, got ${h(r)}`)}function Ye(r){ye(r,"batchGetPeginStatus",e=>{e.result!==null&&_e(e.result)})}function qe(r){ye(r,"batchGetPegoutStatus",e=>{e.result!==null&&Ue(e.result)})}function ye(r,e,t){if(r===null||typeof r!="object")throw new o(`VP response validation failed: ${e} response is not an object`);const n=r;if(!Array.isArray(n.results))throw new o(`VP response validation failed: "${e}.results" must be an array, got ${h(n.results)}`);for(let i=0;i<n.results.length;i++){const s=n.results[i];if(s===null||typeof s!="object")throw new o(`VP response validation failed: "${e}.results[${i}]" must be an object, got ${h(s)}`);const a=s;if(!$(a.pegin_txid)||a.pegin_txid.length!==B)throw new o(`VP response validation failed: "${e}.results[${i}].pegin_txid" must be a ${B}-char hex string, got ${h(a.pegin_txid)}`);if(a.error!==null&&typeof a.error!="string")throw new o(`VP response validation failed: "${e}.results[${i}].error" must be a string or null, got ${h(a.error)}`);if(a.result===null&&a.error===null)throw new o(`VP response validation failed: "${e}.results[${i}]" has neither "result" nor "error" populated`);if(a.result!==null&&a.error!==null)throw new o(`VP response validation failed: "${e}.results[${i}]" has both "result" and "error" populated`);t(a,i)}}function We(r){if(E(r.claim_tx,"depositor_graph.claim_tx"),E(r.assert_tx,"depositor_graph.assert_tx"),E(r.payout_tx,"depositor_graph.payout_tx"),P(r.payout_psbt,"depositor_graph.payout_psbt"),!Array.isArray(r.challenger_presign_data))throw new o('VP response validation failed: "depositor_graph.challenger_presign_data" must be an array');for(let e=0;e<r.challenger_presign_data.length;e++)Ke(r.challenger_presign_data[e],`depositor_graph.challenger_presign_data[${e}]`);if(typeof r.offchain_params_version!="number")throw new o('VP response validation failed: "depositor_graph.offchain_params_version" must be a number')}const ze=6e4;class be{constructor(e,t){m(this,"client");const n={baseUrl:e,timeout:(t==null?void 0:t.timeout)??ze,retries:t==null?void 0:t.retries,retryDelay:t==null?void 0:t.retryDelay,retryableFor:t==null?void 0:t.retryableFor,headers:t==null?void 0:t.headers,tokenProvider:t==null?void 0:t.tokenProvider,maxResponseBytes:t==null?void 0:t.maxResponseBytes};this.client=new X.JsonRpcClient(n)}async requestDepositorPresignTransactions(e,t){const n=await this.client.call("vaultProvider_requestDepositorPresignTransactions",e,t);return Me(n),n}async submitDepositorPresignatures(e,t){return this.client.call("vaultProvider_submitDepositorPresignatures",e,t)}async submitDepositorWotsKey(e,t){return this.client.call("vaultProvider_submitDepositorWotsKey",e,t)}async requestDepositorClaimerArtifacts(e,t){const n=await this.client.call("vaultProvider_requestDepositorClaimerArtifacts",e,t);return me(n),n}async getPeginStatus(e,t){const n=await this.client.call("vaultProvider_getPeginStatus",e,t);return _e(n),n}async batchGetPeginStatus(e,t){const n=await this.client.call("vaultProvider_batchGetPeginStatus",e,t);return Ye(n),n}async batchGetPegoutStatus(e,t){const n=await this.client.call("vaultProvider_batchGetPegoutStatus",e,t);return qe(n),n}}function Ze(r,e){const t=new Set;for(const d of r)t.add(d.toLowerCase());const n=new Map,i=new Set,s=[],a=[];for(const d of e){const l=d.pegin_txid.toLowerCase();if(!t.has(l)){a.push(l);continue}if(i.has(l)){s.push(l);continue}i.add(l),n.set(l,{result:d.result,error:d.error})}const c=[];for(const d of t)i.has(d)||c.push(d);return{byTxid:n,missing:c,unexpected:a,duplicate:s}}async function Qe(r){const{items:e,getTxid:t,batchCall:n,onItem:i,onMissing:s,onDuplicate:a,onDuplicateBatch:c,onWholeBatchError:d,onUnexpected:l,batchSize:g=X.VP_BATCH_MAX_SIZE}=r;if(!Number.isInteger(g)||g<=0)throw new Error(`batchPollByProvider: batchSize must be a positive integer, got ${g}`);for(let b=0;b<e.length;b+=g){const x=e.slice(b,b+g),S=new Map,T=[];for(const y of x){const u=t(y).toLowerCase();S.set(u,y),T.push(u)}let A;try{const y=await n(T);A=Ze(T,y.results)}catch(y){d(x,y);continue}l&&A.unexpected.length>0&&l(A.unexpected);const R=new Set(A.duplicate);for(const y of R){const u=S.get(y);u&&a(u)}c&&R.size>0&&c(R.size);for(const y of A.missing){const u=S.get(y);u&&s(u)}for(const[y,u]of A.byTxid){if(R.has(y))continue;const C=S.get(y);C&&i(C,{pegin_txid:y,result:u.result,error:u.error})}}}const et="BIP0322-signed-message",tt="TapTweak",we=32,rt=64;function Pe(r,e){const t=new TextEncoder().encode(r),n=J.sha256(t),i=new Uint8Array(n.length*2+e.length);return i.set(n,0),i.set(n,n.length),i.set(e,n.length*2),J.sha256(i)}function nt(r){if(r.length!==we)return null;const e=Pe(tt,r),t=j.xOnlyPointAddTweak(r,e);return t?t.xOnlyPubkey:null}function st(r,e,t){if(e.length!==we||t.length!==rt)return!1;try{const n=Pe(et,r),i=N.payments.p2tr({internalPubkey:V.Buffer.from(e)});if(!i.output)return!1;const s=i.output,a=0,c=new N.Transaction;c.version=0,c.locktime=0;const d=V.Buffer.concat([V.Buffer.from([0,32]),V.Buffer.from(n)]);c.addInput(V.Buffer.alloc(32,0),4294967295,0,d),c.addOutput(s,a);const l=new N.Transaction;l.version=0,l.locktime=0;const g=c.getHash();l.addInput(g,0,0),l.addOutput(V.Buffer.from([106]),a);const b=l.hashForWitnessV1(0,[s],[a],N.Transaction.SIGHASH_DEFAULT),x=nt(e);return x?j.verifySchnorr(b,x,t):!1}catch{return!1}}function M(r,e){const t=(r&7)<<5,n=typeof e=="bigint"?e:BigInt(e);if(n<0n)throw new Error("cborHead: negative argument");if(n<24n)return new Uint8Array([t|Number(n)]);if(n<0x100n)return new Uint8Array([t|24,Number(n)]);if(n<0x10000n){const s=Number(n);return new Uint8Array([t|25,s>>>8&255,s&255])}if(n<0x100000000n){const s=Number(n);return new Uint8Array([t|26,s>>>24&255,s>>>16&255,s>>>8&255,s&255])}const i=new Uint8Array(9);i[0]=t|27;for(let s=7;s>=0;s--)i[1+s]=Number(n>>BigInt((7-s)*8))&255;return i}function xe(...r){const e=r.reduce((i,s)=>i+s.length,0),t=new Uint8Array(e);let n=0;for(const i of r)t.set(i,n),n+=i.length;return t}function se(r){const t=[M(4,r.length)];for(const n of r)t.push(M(0,n));return xe(...t)}function it(r,e,t){if(!Number.isSafeInteger(t)||t<0)throw new Error(`encodeServerIdentityPayload: expires_at must be a non-negative safe integer, got ${t}`);const n=M(4,3),i=se(r),s=se(e),a=M(0,t);return xe(n,i,s,a)}const at=new TextEncoder().encode("btc-auth.server-identity.v1"),ot=2*3600;class w extends Error{constructor(e,t){super(e),this.reason=t,this.name="ServerIdentityError"}}function D(r){const e=new Uint8Array(r.length/2);for(let t=0;t<e.length;t++)e[t]=parseInt(r.slice(t*2,t*2+2),16);return e}function Ae(r){const{proof:e,pinnedServerPubkey:t,now:n}=r,i=r.maxLifetimeSecs??ot,s=_.stripHexPrefix(t).toLowerCase();if(s.length!==_.X_ONLY_PUBKEY_HEX_LEN||!k.HEX_RE.test(s))throw new w(`pinnedServerPubkey must be 32-byte hex; got ${s.length} chars`,"invalid_pubkey_encoding");const a=_.stripHexPrefix(e.server_pubkey).toLowerCase();if(a.length!==_.X_ONLY_PUBKEY_HEX_LEN||!k.HEX_RE.test(a))throw new w(`server_pubkey must be 32-byte hex; got ${a.length} chars`,"invalid_pubkey_encoding");if(a!==s)throw new w(`server_pubkey does not match pinned value: expected ${s}, got ${a}`,"pinned_pubkey_mismatch");if(!Number.isSafeInteger(e.expires_at))throw new w(`expires_at must be a finite integer; got ${JSON.stringify(e.expires_at)}`,"invalid_expires_at");if(!Number.isSafeInteger(n))throw new w(`now must be a finite integer; got ${JSON.stringify(n)}`,"invalid_expires_at");if(e.expires_at<=n)throw new w(`server identity proof expired at ${e.expires_at}, now ${n}`,"expired");if(!Number.isSafeInteger(i)||i<=0)throw new w(`maxLifetimeSecs must be a positive safe integer; got ${JSON.stringify(i)}`,"invalid_max_lifetime");if(e.expires_at-n>i)throw new w(`server identity proof expires too far in the future: expires_at=${e.expires_at}, now=${n}, max lifetime=${i}s`,"expires_too_far");const c=_.stripHexPrefix(e.ephemeral_pubkey).toLowerCase();if(c.length!==_.COMPRESSED_PUBKEY_HEX_LEN||!k.HEX_RE.test(c))throw new w(`ephemeral_pubkey must be 33-byte compressed hex; got ${c.length} chars`,"invalid_ephemeral_pubkey");const d=c.slice(0,2);if(d!=="02"&&d!=="03")throw new w(`ephemeral_pubkey must be compressed (prefix 02/03); got ${d}`,"invalid_ephemeral_pubkey");const l=D(c);if(!j.isPoint(l))throw new w("ephemeral_pubkey is not a valid secp256k1 point","invalid_ephemeral_pubkey");const g=_.stripHexPrefix(e.signature).toLowerCase();if(g.length!==_.SCHNORR_SIG_HEX_LEN||!k.HEX_RE.test(g))throw new w(`signature must be 64-byte Schnorr hex; got ${g.length} chars`,"invalid_signature_encoding");const b=it(at,D(c),e.expires_at);if(!st(b,D(a),D(g)))throw new w("BIP-322 signature verification failed — ephemeral key is not attested by pinned server pubkey","signature_verification_failed")}const ct=new Set(["vaultProvider_submitDepositorWotsKey","vaultProvider_submitDepositorPresignatures","vaultProvider_requestDepositorPresignTransactions"]),lt=new Set(["vaultProvider_requestDepositorClaimerArtifacts"]),ut=6e4,Y="auth_createDepositorToken",q="auth_createDepositorTokenGrpc";function ve(r,e){return new X.JsonRpcClient({baseUrl:r,timeout:ut,headers:e,retryableFor:t=>t===Y||t===q})}const dt=0,pt=1,K=2,ht=3,gt=4,ft=5,_t=6,mt=7,ie=24,yt=28,bt=20,wt=21,Pt=22,ae=256;class v extends Error{constructor(e){super(`CBOR decode: ${e}`),this.name="CborDecodeError"}}class Ee{constructor(e){m(this,"buf");m(this,"pos",0);this.buf=e}nextByte(){if(this.pos>=this.buf.length)throw new v("unexpected end of input");return this.buf[this.pos++]}readHead(){const e=this.nextByte(),t=e>>5,n=e&31;if(n<ie)return{major:t,arg:n};if(n>=yt)throw new v(`unsupported additional info ${n} (indefinite-length or reserved)`);const i=1<<n-ie;let s=0n;for(let a=0;a<i;a++)s=s<<8n|BigInt(this.nextByte());if(s>BigInt(Number.MAX_SAFE_INTEGER))throw new v(`argument ${s} exceeds safe integer range`);return{major:t,arg:Number(s)}}readBytes(e){if(this.pos+e>this.buf.length)throw new v("length overruns end of input");const t=this.buf.subarray(this.pos,this.pos+e);return this.pos+=e,t}readByteString(){const e=this.readHead();if(e.major!==K)throw new v(`expected byte string (major ${K}), got major ${e.major}`);return this.readBytes(e.arg)}readValue(e=0){if(e>ae)throw new v(`nesting exceeds maximum depth ${ae}`);const t=this.readHead();switch(t.major){case dt:return t.arg;case pt:return-1-t.arg;case K:return this.readBytes(t.arg);case ht:return new TextDecoder("utf-8",{fatal:!0}).decode(this.readBytes(t.arg));case gt:{const n=[];for(let i=0;i<t.arg;i++)n.push(this.readValue(e+1));return n}case ft:{const n=new Map;for(let i=0;i<t.arg;i++){const s=this.readValue(e+1),a=this.readValue(e+1);n.set(s,a)}return n}case _t:return{tag:t.arg,value:this.readValue(e+1)};case mt:if(t.arg===bt)return!1;if(t.arg===wt)return!0;if(t.arg===Pt)return null;throw new v(`unsupported simple/float value ${t.arg}`);default:throw new v(`unsupported major type ${t.major}`)}}}function Se(r){const e=new Ee(r),t=e.readValue();if(e.pos!==r.length)throw new v("trailing bytes after top-level item");return t}const xt="vaultd-jsonrpc",At="vaultd-grpc",oe=18,W=4,ce=-47,vt=1,le=64,Et=128,St=96,Ct=64,kt=1,Tt=2,$t=3,Rt=4,It=5,Vt=6,Bt=7,ue=new TextEncoder().encode("Signature1");class p extends Error{constructor(e,t){super(e),this.reason=t,this.name="CwtVerificationError"}}function Ot(r){const e=de(r.expectedIssuerXOnlyPubkey,"expectedIssuerXOnlyPubkey"),t=de(r.expectedAudienceXOnlyPubkey,"expectedAudienceXOnlyPubkey"),n=Gt(r.ephemeralPubkeyHex),i=Xt(r.token),s=new Ee(i),a=s.readHead();if(a.major!==6||a.arg!==oe)throw new p(`token is not a COSE Sign1 tagged value (tag ${oe})`,"invalid_token_structure");const c=s.readHead();if(c.major!==4||c.arg!==W)throw new p(`COSE Sign1 must be a ${W}-element array`,"invalid_token_structure");const d=s.pos,l=s.readByteString(),g=i.subarray(d,s.pos);s.readValue();const b=s.pos,x=s.readByteString(),S=i.subarray(b,s.pos),T=s.readByteString();if(T.length!==le)throw new p(`COSE signature must be ${le} bytes, got ${T.length}`,"invalid_token_structure");if(s.pos!==i.length)throw new p("COSE Sign1 token has trailing bytes after the signature","invalid_token_structure");const A=Nt(l);if(A!==ce)throw new p(`unexpected COSE algorithm ${A} (expected ES256K ${ce})`,"unexpected_algorithm");const R=Ht(g,S),y=J.sha256(R);if(!j.verify(y,n,T,!0))throw new p("COSE signature does not verify against the server's ephemeral key","signature_verification_failed");const u=Lt(x),C=u.audience.toLowerCase();if(C.length!==_.X_ONLY_PUBKEY_HEX_LEN||!k.HEX_RE.test(C))throw new p("token `aud` is not a 32-byte x-only pubkey hex","invalid_claims");if(u.issuedAt>u.expiresAt)throw new p(`token iat (${u.issuedAt}) is after exp (${u.expiresAt})`,"invalid_claims");if(u.issuer.toLowerCase()!==e)throw new p(`token issuer does not match pinned server pubkey: expected ${e}, got ${u.issuer.toLowerCase()}`,"issuer_mismatch");if(u.subject!==r.expectedSubject)throw new p(`token subject mismatch: expected ${r.expectedSubject}, got ${u.subject}`,"subject_mismatch");if(C!==t)throw new p(`token audience does not match depositor pubkey: expected ${t}, got ${C}`,"audience_mismatch");if(u.expiresAt<=r.now)throw new p(`token expired: exp ${u.expiresAt} <= now ${r.now}`,"token_expired");if(r.responseExpiresAt!==u.expiresAt)throw new p(`response expires_at (${r.responseExpiresAt}) does not equal token exp (${u.expiresAt})`,"expiry_mismatch");if(r.serverIdentityExpiresAt<u.expiresAt)throw new p(`server identity expires (${r.serverIdentityExpiresAt}) before token exp (${u.expiresAt})`,"server_identity_expires_before_token");return{issuer:u.issuer,subject:u.subject,audience:C,expiresAt:u.expiresAt,notBefore:u.notBefore,issuedAt:u.issuedAt}}function Nt(r){if(r.length===0)throw new p("empty COSE protected header (no algorithm)","unexpected_algorithm");const e=Se(r);if(!(e instanceof Map))throw new p("COSE protected header is not a map","invalid_token_structure");const t=e.get(vt);if(typeof t!="number")throw new p("COSE protected header missing integer algorithm label","unexpected_algorithm");return t}function Ht(r,e){return jt(Uint8Array.of(Et|W),Uint8Array.of(St|ue.length),ue,r,Uint8Array.of(Ct),e)}function Lt(r){const e=Se(r);if(!(e instanceof Map))throw new p("CWT claims root is not a map","invalid_claims");if(Dt(e,Bt,"cti").length===0)throw new p("token cti is empty","invalid_claims");return{issuer:U(e,kt,"iss"),subject:U(e,Tt,"sub"),audience:U(e,$t,"aud"),expiresAt:F(e,Rt,"exp"),notBefore:F(e,It,"nbf"),issuedAt:F(e,Vt,"iat")}}function U(r,e,t){const n=r.get(e);if(typeof n!="string")throw new p(`token claim ${t} is missing or not a text string`,"invalid_claims");return n}function Dt(r,e,t){const n=r.get(e);if(!(n instanceof Uint8Array))throw new p(`token claim ${t} is missing or not a byte string`,"invalid_claims");return n}function F(r,e,t){const n=r.get(e);if(typeof n!="number"||!Number.isSafeInteger(n)||n<0)throw new p(`token claim ${t} is missing or not a non-negative integer timestamp`,"invalid_claims");return n}function de(r,e){const t=_.stripHexPrefix(r).toLowerCase();if(t.length!==_.X_ONLY_PUBKEY_HEX_LEN||!k.HEX_RE.test(t))throw new p(`${e} must be 32-byte x-only hex; got ${t.length} chars`,"invalid_input");return t}function Gt(r){const e=_.stripHexPrefix(r).toLowerCase(),t=e.slice(0,2);if(e.length!==_.COMPRESSED_PUBKEY_HEX_LEN||!k.HEX_RE.test(e)||t!=="02"&&t!=="03")throw new p("ephemeralPubkeyHex must be 33-byte compressed pubkey hex (prefix 02/03)","invalid_input");return _.hexToUint8Array(e)}const Mt=(()=>{const r=new Int16Array(128).fill(-1),e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";for(let t=0;t<e.length;t++)r[e.charCodeAt(t)]=t;return r})();function Xt(r){const e=r.length,t=Math.floor(e/4),n=e%4;if(n===1)throw new p("invalid base64url length","invalid_token_structure");const i=t*3+(n===0?0:n-1),s=new Uint8Array(i),a=l=>{const g=l<128?Mt[l]:-1;if(g<0)throw new p("invalid base64url character","invalid_token_structure");return g};let c=0,d=0;for(let l=0;l<t;l++){const g=a(r.charCodeAt(c++)),b=a(r.charCodeAt(c++)),x=a(r.charCodeAt(c++)),S=a(r.charCodeAt(c++));s[d++]=g<<2|b>>4,s[d++]=(b&15)<<4|x>>2,s[d++]=(x&3)<<6|S}if(n===2){const l=a(r.charCodeAt(c++)),g=a(r.charCodeAt(c++));s[d++]=l<<2|g>>4}else if(n===3){const l=a(r.charCodeAt(c++)),g=a(r.charCodeAt(c++)),b=a(r.charCodeAt(c++));s[d++]=l<<2|g>>4,s[d++]=(g&15)<<4|b>>2}return s}function jt(...r){const e=r.reduce((i,s)=>i+s.length,0),t=new Uint8Array(e);let n=0;for(const i of r)t.set(i,n),n+=i.length;return t}const pe=4102444800,Kt=30;class Ut{constructor(e){m(this,"client");m(this,"peginTxid");m(this,"authAnchorHex");m(this,"pinnedServerPubkey");m(this,"expectedAudienceXOnlyPubkey");m(this,"authGatedMethods");m(this,"grpcGatedMethods");m(this,"refreshSkewSecs");m(this,"now");m(this,"cachedJsonRpc",null);m(this,"inFlightJsonRpc",null);m(this,"cachedGrpc",null);m(this,"inFlightGrpc",null);this.client=e.client,this.peginTxid=e.peginTxid,this.authAnchorHex=e.authAnchorHex,this.pinnedServerPubkey=e.pinnedServerPubkey,this.expectedAudienceXOnlyPubkey=e.expectedAudienceXOnlyPubkey,this.authGatedMethods=e.authGatedMethods,this.grpcGatedMethods=e.grpcGatedMethods,this.refreshSkewSecs=e.refreshSkewSecs??Kt,this.now=e.now??(()=>Math.floor(Date.now()/1e3))}async getToken(e){return e===Y||e===q?null:this.grpcGatedMethods.has(e)?this.getTokenForSubject("grpc"):this.authGatedMethods.has(e)?this.getTokenForSubject("jsonrpc"):null}invalidate(){this.cachedJsonRpc=null,this.cachedGrpc=null}async getTokenForSubject(e){const t=e==="grpc"?this.cachedGrpc:this.cachedJsonRpc;return t&&this.now()+this.refreshSkewSecs<t.expiresAt?t.token:(await this.acquireSingleFlight(e)).token}setClient(e){this.client=e}acquireSingleFlight(e){const t=e==="grpc"?this.inFlightGrpc:this.inFlightJsonRpc;if(t)return t;const n=e==="grpc"?q:Y,i=(async()=>{try{const s=await this.client.call(n,{pegin_txid:this.peginTxid,auth_anchor:this.authAnchorHex});if(Ae({proof:s.server_identity,pinnedServerPubkey:this.pinnedServerPubkey,now:this.now()}),typeof s.token!="string"||s.token.length===0)throw new Error(`VpTokenProvider: invalid token in acquire response (expected non-empty string, got ${typeof s.token})`);const a=this.now();if(!Number.isSafeInteger(s.expires_at)||s.expires_at<=a||s.expires_at>pe)throw new Error(`VpTokenProvider: invalid expires_at in acquire response (got ${JSON.stringify(s.expires_at)}; must be a safe integer in (${a}, ${pe}])`);Ot({token:s.token,ephemeralPubkeyHex:s.server_identity.ephemeral_pubkey,expectedIssuerXOnlyPubkey:this.pinnedServerPubkey,expectedSubject:e==="grpc"?At:xt,expectedAudienceXOnlyPubkey:this.expectedAudienceXOnlyPubkey,responseExpiresAt:s.expires_at,serverIdentityExpiresAt:s.server_identity.expires_at,now:a});const c={token:s.token,expiresAt:s.expires_at};return e==="grpc"?this.cachedGrpc=c:this.cachedJsonRpc=c,c}finally{e==="grpc"?this.inFlightGrpc=null:this.inFlightJsonRpc=null}})();return e==="grpc"?this.inFlightGrpc=i:this.inFlightJsonRpc=i,i}}class Ce{constructor(){m(this,"entries",new Map)}getOrCreate(e){const t=this.entries.get(e.peginTxid);if(t){if(t.authAnchorHex!==e.authAnchorHex)throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to authAnchorHex ${t.authAnchorHex.slice(0,8)}…; got ${e.authAnchorHex.slice(0,8)}…`);if(t.pinnedServerPubkey!==e.pinnedServerPubkey)throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to pinnedServerPubkey ${t.pinnedServerPubkey.slice(0,8)}…; got ${e.pinnedServerPubkey.slice(0,8)}…`);if(t.expectedAudienceXOnlyPubkey!==e.expectedAudienceXOnlyPubkey)throw new Error(`VpTokenRegistry: peginTxid ${e.peginTxid} already bound to expectedAudienceXOnlyPubkey ${t.expectedAudienceXOnlyPubkey.slice(0,8)}…; got ${e.expectedAudienceXOnlyPubkey.slice(0,8)}…`);return t.provider.setClient(e.client),t.provider}const n=new Ut({client:e.client,peginTxid:e.peginTxid,authAnchorHex:e.authAnchorHex,pinnedServerPubkey:e.pinnedServerPubkey,expectedAudienceXOnlyPubkey:e.expectedAudienceXOnlyPubkey,authGatedMethods:ct,grpcGatedMethods:lt});return this.entries.set(e.peginTxid,{provider:n,authAnchorHex:e.authAnchorHex,pinnedServerPubkey:e.pinnedServerPubkey,expectedAudienceXOnlyPubkey:e.expectedAudienceXOnlyPubkey}),n}peek(e){var t;return(t=this.entries.get(e))==null?void 0:t.provider}release(e){this.entries.delete(e)}clear(){this.entries.clear()}get size(){return this.entries.size}}const Z=new Ce;function Ft(r){var n;const e=ve(r.baseUrl,(n=r.options)==null?void 0:n.headers),t=Z.getOrCreate({client:e,peginTxid:r.peginTxid,authAnchorHex:r.authAnchorHex,pinnedServerPubkey:r.pinnedServerPubkey,expectedAudienceXOnlyPubkey:_.processPublicKeyToXOnly(r.depositorBtcPubkey)});return new be(r.baseUrl,{...r.options,tokenProvider:t})}function Jt(r){Z.getOrCreate({client:ve(r.baseUrl,r.headers),peginTxid:r.peginTxid,authAnchorHex:r.authAnchorHex,pinnedServerPubkey:r.pinnedServerPubkey,expectedAudienceXOnlyPubkey:_.processPublicKeyToXOnly(r.depositorBtcPubkey)})}exports.OnChainBtcVaultStatus=he;exports.ServerIdentityError=w;exports.VaultProviderRpcClient=be;exports.ViemOperationKeyReader=Be;exports.ViemProtocolParamsReader=Oe;exports.ViemUniversalChallengerReader=He;exports.ViemVaultKeeperReader=Ne;exports.VpResponseValidationError=o;exports.VpTokenRegistry=Ce;exports.batchPollByProvider=Qe;exports.createAuthenticatedVpClient=Ft;exports.primeVpTokenRegistry=Jt;exports.resolveProtocolAddresses=Ie;exports.validateRequestDepositorClaimerArtifactsResponse=me;exports.verifyServerIdentity=Ae;exports.vpTokenRegistry=Z;
|
|
2
|
+
//# sourceMappingURL=primeVpAuth-BlxUcdBf.cjs.map
|