@babylonlabs-io/ts-sdk 0.48.2 → 0.48.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{PayoutManager-DD1audlx.cjs → PayoutManager-BZVEyi10.cjs} +2 -2
- package/dist/{PayoutManager-DD1audlx.cjs.map → PayoutManager-BZVEyi10.cjs.map} +1 -1
- package/dist/{PayoutManager-D02AePm4.js → PayoutManager-D26nGR-e.js} +2 -2
- package/dist/{PayoutManager-D02AePm4.js.map → PayoutManager-D26nGR-e.js.map} +1 -1
- package/dist/{PeginManager-6seoi9mV.js → PeginManager-CNhDl1eC.js} +3 -3
- package/dist/{PeginManager-6seoi9mV.js.map → PeginManager-CNhDl1eC.js.map} +1 -1
- package/dist/{PeginManager-CHZieoEQ.cjs → PeginManager-NfDjKQGV.cjs} +2 -2
- package/dist/{PeginManager-CHZieoEQ.cjs.map → PeginManager-NfDjKQGV.cjs.map} +1 -1
- package/dist/{buildAndBroadcastRefund-Bi07LxuY.cjs → buildAndBroadcastRefund-BOtxUi05.cjs} +2 -2
- package/dist/{buildAndBroadcastRefund-Bi07LxuY.cjs.map → buildAndBroadcastRefund-BOtxUi05.cjs.map} +1 -1
- package/dist/{buildAndBroadcastRefund-DXHs6unL.js → buildAndBroadcastRefund-o9Byvkut.js} +4 -4
- package/dist/{buildAndBroadcastRefund-DXHs6unL.js.map → buildAndBroadcastRefund-o9Byvkut.js.map} +1 -1
- package/dist/challengeAssert-HNbugpqL.cjs +2 -0
- package/dist/challengeAssert-HNbugpqL.cjs.map +1 -0
- package/dist/{challengeAssert-ChvLypwc.js → challengeAssert-csvYXBJB.js} +7 -7
- package/dist/challengeAssert-csvYXBJB.js.map +1 -0
- package/dist/constants-CSG2XeD8.cjs +2 -0
- package/dist/constants-CSG2XeD8.cjs.map +1 -0
- package/dist/constants-Cd_fN8VT.js +12 -0
- package/dist/constants-Cd_fN8VT.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +7 -7
- package/dist/{noPayout-CA4-x5vZ.js → noPayout-C1WCsqfd.js} +46 -44
- package/dist/noPayout-C1WCsqfd.js.map +1 -0
- package/dist/noPayout-lyIRiUyG.cjs +2 -0
- package/dist/noPayout-lyIRiUyG.cjs.map +1 -0
- package/dist/{primeVpAuth-rbejoBPu.js → primeVpAuth-Dzxxy0-F.js} +174 -169
- package/dist/primeVpAuth-Dzxxy0-F.js.map +1 -0
- package/dist/primeVpAuth-wKbRw0m4.cjs +2 -0
- package/dist/primeVpAuth-wKbRw0m4.cjs.map +1 -0
- package/dist/tbv/core/clients/index.cjs +1 -1
- package/dist/tbv/core/clients/index.js +1 -1
- package/dist/tbv/core/clients/vault-provider/validators.d.ts.map +1 -1
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.js +7 -7
- 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 +3 -3
- package/dist/tbv/core/primitives/psbt/__tests__/peginAmountsGuard.test.d.ts +8 -0
- package/dist/tbv/core/primitives/psbt/__tests__/peginAmountsGuard.test.d.ts.map +1 -0
- package/dist/tbv/core/primitives/psbt/challengeAssert.d.ts +4 -4
- package/dist/tbv/core/primitives/psbt/challengeAssert.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/constants.d.ts +8 -0
- package/dist/tbv/core/primitives/psbt/constants.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/refund.d.ts.map +1 -1
- package/dist/tbv/core/services/index.cjs +1 -1
- package/dist/tbv/core/services/index.js +2 -2
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +7 -7
- package/dist/{verifyScriptPathSchnorrSignature-DFJAEleY.js → verifyScriptPathSchnorrSignature-CeZp6tMw.js} +77 -79
- package/dist/verifyScriptPathSchnorrSignature-CeZp6tMw.js.map +1 -0
- package/dist/verifyScriptPathSchnorrSignature-Cl7tu77P.cjs +2 -0
- package/dist/verifyScriptPathSchnorrSignature-Cl7tu77P.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/challengeAssert-ChvLypwc.js.map +0 -1
- package/dist/challengeAssert-Culc7DoS.cjs +0 -2
- package/dist/challengeAssert-Culc7DoS.cjs.map +0 -1
- package/dist/noPayout-CA4-x5vZ.js.map +0 -1
- package/dist/noPayout-CJ_Acpl_.cjs +0 -2
- package/dist/noPayout-CJ_Acpl_.cjs.map +0 -1
- package/dist/primeVpAuth-Br6RwE3r.cjs +0 -2
- package/dist/primeVpAuth-Br6RwE3r.cjs.map +0 -1
- package/dist/primeVpAuth-rbejoBPu.js.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-D43cncKJ.cjs +0 -2
- package/dist/verifyScriptPathSchnorrSignature-D43cncKJ.cjs.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-DFJAEleY.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"primeVpAuth-rbejoBPu.js","sources":["../src/tbv/core/clients/eth/contract-address-resolver.ts","../src/tbv/core/clients/eth/protocol-params-reader.ts","../src/tbv/core/clients/eth/signer-set-reader.ts","../src/tbv/core/clients/eth/types.ts","../src/tbv/core/clients/vault-provider/validators.ts","../src/tbv/core/clients/vault-provider/api.ts","../src/tbv/core/clients/vault-provider/batchAttribution.ts","../src/tbv/core/clients/vault-provider/batchPoll.ts","../src/tbv/core/clients/vault-provider/auth/bip322Verify.ts","../src/tbv/core/clients/vault-provider/auth/cbor.ts","../src/tbv/core/clients/vault-provider/auth/serverIdentity.ts","../src/tbv/core/clients/vault-provider/auth/gatedMethods.ts","../src/tbv/core/clients/vault-provider/auth/innerTokenClient.ts","../src/tbv/core/clients/vault-provider/auth/tokenProvider.ts","../src/tbv/core/clients/vault-provider/auth/tokenRegistry.ts","../src/tbv/core/clients/vault-provider/auth/createAuthenticatedVpClient.ts","../src/tbv/core/clients/vault-provider/auth/primeVpAuth.ts"],"sourcesContent":["/**\n * Contract Address Resolver\n *\n * Resolves ProtocolParams and ApplicationRegistry contract addresses\n * from the BTCVaultRegistry contract. These addresses are needed to\n * construct the SDK's contract readers.\n *\n * @module clients/eth/contract-address-resolver\n */\n\nimport type { Address, PublicClient } from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\n\nexport interface ProtocolAddresses {\n /** Address of the ProtocolParams contract */\n protocolParams: Address;\n /** Address of the ApplicationRegistry contract */\n applicationRegistry: Address;\n}\n\n/**\n * Resolve ProtocolParams and ApplicationRegistry addresses from BTCVaultRegistry.\n *\n * Uses a single multicall for atomicity and efficiency.\n *\n * @param publicClient - viem PublicClient instance\n * @param btcVaultRegistryAddress - Address of the BTCVaultRegistry contract\n * @returns Resolved contract addresses\n */\nexport async function resolveProtocolAddresses(\n publicClient: PublicClient,\n btcVaultRegistryAddress: Address,\n): Promise<ProtocolAddresses> {\n const [protocolParams, applicationRegistry] = await publicClient.multicall({\n contracts: [\n {\n address: btcVaultRegistryAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"protocolParams\",\n },\n {\n address: btcVaultRegistryAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"applicationRegistry\",\n },\n ],\n allowFailure: false,\n });\n\n return {\n protocolParams: protocolParams as Address,\n applicationRegistry: applicationRegistry as Address,\n };\n}\n","/**\n * Concrete ProtocolParams reader using viem's readContract and multicall.\n *\n * This is an optional utility — callers can use their own implementation\n * of the ProtocolParamsReader interface.\n */\n\nimport type { Abi, Address, Hex, PublicClient } from \"viem\";\n\nimport { ProtocolParamsABI } from \"../../contracts/abis/ProtocolParams.abi\";\nimport {\n assertValidOffchainParamsVersion,\n validateOffchainParams,\n validatePegInConfiguration,\n validateTBVProtocolParams,\n} from \"./protocol-params-validation\";\nimport type {\n AllOffchainParamsData,\n OnSkippedOffchainParamsVersion,\n PegInConfiguration,\n ProtocolParamsReader,\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\n/**\n * Raw shape viem returns for VersionedOffchainParams struct.\n * viem resolves ABI struct outputs to named objects (not tuples).\n */\ninterface RawOffchainParams {\n timelockAssert: bigint;\n timelockChallengeAssert: bigint;\n securityCouncilKeys: readonly Hex[];\n councilQuorum: number;\n feeRate: bigint;\n babeTotalInstances: number;\n babeInstancesToFinalize: number;\n minVpCommissionBps: number;\n tRefund: number;\n tStale: number;\n minPeginFeeRate: bigint;\n proverCircuitVersion: number;\n minPrepeginDepth: number;\n}\n\n/** Raw shape viem returns for TBVProtocolParams struct. */\ninterface RawTBVParams {\n minimumPegInAmount: bigint;\n maxPegInAmount: bigint;\n pegInAckTimeout: bigint;\n pegInActivationTimeout: bigint;\n maxHtlcOutputCount: number;\n expiredPegInGraceBlocks: bigint;\n}\n\n/** Map viem struct result to VersionedOffchainParams. */\nfunction mapOffchainParams(result: RawOffchainParams): VersionedOffchainParams {\n return {\n timelockAssert: result.timelockAssert,\n timelockChallengeAssert: result.timelockChallengeAssert,\n securityCouncilKeys: [...result.securityCouncilKeys],\n councilQuorum: result.councilQuorum,\n feeRate: result.feeRate,\n babeTotalInstances: result.babeTotalInstances,\n babeInstancesToFinalize: result.babeInstancesToFinalize,\n minVpCommissionBps: result.minVpCommissionBps,\n tRefund: result.tRefund,\n tStale: result.tStale,\n minPeginFeeRate: result.minPeginFeeRate,\n proverCircuitVersion: result.proverCircuitVersion,\n minPrepeginDepth: result.minPrepeginDepth,\n };\n}\n\n/** Map viem struct result to TBVProtocolParams. */\nfunction mapTBVParams(result: RawTBVParams): TBVProtocolParams {\n return {\n minimumPegInAmount: result.minimumPegInAmount,\n maxPegInAmount: result.maxPegInAmount,\n pegInAckTimeout: result.pegInAckTimeout,\n pegInActivationTimeout: result.pegInActivationTimeout,\n maxHtlcOutputCount: result.maxHtlcOutputCount,\n expiredPegInGraceBlocks: result.expiredPegInGraceBlocks,\n };\n}\n\n/**\n * Derive timelockPegin from timelockAssert.\n *\n * Matches PeginLogic.sol: `uint16(timelockAssert)`.\n * The contract validates `timelockAssert <= type(uint16).max` on write,\n * but we enforce the same bound here to reject invalid values early\n * rather than silently truncating.\n *\n * @throws if timelockAssert exceeds uint16 max (65535)\n */\nfunction deriveTimelockPegin(timelockAssert: bigint): number {\n if (timelockAssert > BigInt(UINT16_MAX)) {\n throw new Error(\n `timelockAssert value ${timelockAssert} exceeds uint16 max (${UINT16_MAX})`,\n );\n }\n return Number(timelockAssert);\n}\n\n/**\n * Concrete protocol params reader using viem.\n *\n * Every read method runs the matching validator from\n * `protocol-params-validation` before returning, so callers don't have to\n * remember to validate.\n *\n * Usage:\n * ```ts\n * const reader = new ViemProtocolParamsReader(publicClient, protocolParamsAddress);\n * const config = await reader.getPegInConfiguration();\n * ```\n */\nexport class ViemProtocolParamsReader implements ProtocolParamsReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n async getTBVProtocolParams(): Promise<TBVProtocolParams> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getTBVProtocolParams\",\n })) as RawTBVParams;\n\n const params = mapTBVParams(result);\n validateTBVProtocolParams(params);\n return params;\n }\n\n async getLatestOffchainParams(): Promise<VersionedOffchainParams> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getLatestOffchainParams\",\n })) as RawOffchainParams;\n\n const params = mapOffchainParams(result);\n validateOffchainParams(params);\n return params;\n }\n\n async getOffchainParamsByVersion(\n version: number,\n ): Promise<VersionedOffchainParams> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getOffchainParamsByVersion\",\n args: [version],\n })) as RawOffchainParams;\n\n const params = mapOffchainParams(result);\n validateOffchainParams(params);\n return params;\n }\n\n async getLatestOffchainParamsVersion(): Promise<number> {\n const raw = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"latestOffchainParamsVersion\",\n });\n const version = Number(raw);\n assertValidOffchainParamsVersion(version);\n return version;\n }\n\n async getTimelockPeginByVersion(version: number): Promise<number> {\n const params = await this.getOffchainParamsByVersion(version);\n return deriveTimelockPegin(params.timelockAssert);\n }\n\n /**\n * Read TBV protocol params, latest offchain params, and the latest version\n * label atomically via multicall. The version is paired with the params so\n * that a governance update between separate reads cannot let JS build BTC\n * scripts with version N params while the contract registers the vault\n * under version N+1.\n */\n async getPegInConfiguration(): Promise<PegInConfiguration> {\n const results = await this.publicClient.multicall({\n contracts: [\n {\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getTBVProtocolParams\",\n },\n {\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getLatestOffchainParams\",\n },\n {\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"latestOffchainParamsVersion\",\n },\n ],\n allowFailure: false,\n });\n\n const tbvParams = mapTBVParams(results[0] as RawTBVParams);\n const offchainParams = mapOffchainParams(results[1] as RawOffchainParams);\n const offchainParamsVersion = Number(results[2]);\n\n const config: PegInConfiguration = {\n minimumPegInAmount: tbvParams.minimumPegInAmount,\n maxPegInAmount: tbvParams.maxPegInAmount,\n pegInAckTimeout: tbvParams.pegInAckTimeout,\n pegInActivationTimeout: tbvParams.pegInActivationTimeout,\n maxHtlcOutputCount: tbvParams.maxHtlcOutputCount,\n expiredPegInGraceBlocks: tbvParams.expiredPegInGraceBlocks,\n timelockPegin: deriveTimelockPegin(offchainParams.timelockAssert),\n timelockRefund: offchainParams.tRefund,\n minVpCommissionBps: offchainParams.minVpCommissionBps,\n offchainParams,\n offchainParamsVersion,\n };\n\n validatePegInConfiguration(config);\n return config;\n }\n\n /**\n * Fetch every historical offchain params version in a single multicall.\n * Iterates 1..latestVersion and calls `getOffchainParamsByVersion` for each.\n * Versions whose payload fails validation are skipped (not included in the\n * returned map) so a single bad historical version doesn't block the\n * lookup of the rest.\n *\n * @param onSkippedVersion - optional observer invoked once per skipped\n * version. Use to log/telemeter without coupling the SDK to a logger.\n */\n async fetchAllOffchainParams(\n onSkippedVersion?: OnSkippedOffchainParamsVersion,\n ): Promise<AllOffchainParamsData> {\n const latestVersion = await this.getLatestOffchainParamsVersion();\n if (latestVersion === 0) {\n return { byVersion: new Map(), latestVersion: 0 };\n }\n\n const versions = Array.from({ length: latestVersion }, (_, i) => i + 1);\n const contracts = versions.map((v) => ({\n address: this.contractAddress,\n abi: ProtocolParamsABI as Abi,\n functionName: \"getOffchainParamsByVersion\" as const,\n args: [v] as const,\n }));\n\n const results = await this.publicClient.multicall({\n contracts,\n allowFailure: false,\n });\n\n const byVersion = new Map<number, VersionedOffchainParams>();\n for (let i = 0; i < versions.length; i++) {\n const params = mapOffchainParams(results[i] as RawOffchainParams);\n try {\n validateOffchainParams(params);\n byVersion.set(versions[i], params);\n } catch (error) {\n // A malformed historical version mustn't block lookup of the rest.\n // Surface the skip to the caller's observer if one was supplied.\n onSkippedVersion?.(\n versions[i],\n error instanceof Error ? error : new Error(String(error)),\n );\n }\n }\n\n return { byVersion, latestVersion };\n }\n}\n","/**\n * Concrete signer-set readers for vault keepers and universal challengers.\n *\n * These are optional utilities — callers can use their own implementations\n * of the VaultKeeperReader and UniversalChallengerReader interfaces.\n */\n\nimport type { Address, Hex, PublicClient } from \"viem\";\n\nimport { ApplicationRegistryABI } from \"../../contracts/abis/ApplicationRegistry.abi\";\nimport { ProtocolParamsABI } from \"../../contracts/abis/ProtocolParams.abi\";\nimport type {\n AddressBTCKeyPair,\n UniversalChallengerReader,\n VaultKeeperReader,\n} from \"./types\";\n\n/** Map viem tuple array to AddressBTCKeyPair[]. */\nfunction mapKeyPairs(\n result: readonly { ethAddress: Address; btcPubKey: Hex }[],\n): AddressBTCKeyPair[] {\n return result.map((pair) => ({\n ethAddress: pair.ethAddress,\n btcPubKey: pair.btcPubKey,\n }));\n}\n\n/**\n * Reads vault keepers from the ApplicationRegistry contract.\n *\n * Usage:\n * ```ts\n * const reader = new ViemVaultKeeperReader(publicClient, applicationRegistryAddress);\n * const keepers = await reader.getCurrentVaultKeepers(appEntryPoint);\n * ```\n */\nexport class ViemVaultKeeperReader implements VaultKeeperReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n async getVaultKeepersByVersion(\n appEntryPoint: Address,\n version: number,\n ): Promise<AddressBTCKeyPair[]> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ApplicationRegistryABI,\n functionName: \"getVaultKeepersByVersion\",\n args: [appEntryPoint, version],\n })) as readonly { ethAddress: Address; btcPubKey: Hex }[];\n\n return mapKeyPairs(result);\n }\n\n async getCurrentVaultKeepers(\n appEntryPoint: Address,\n ): Promise<AddressBTCKeyPair[]> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ApplicationRegistryABI,\n functionName: \"getCurrentVaultKeepers\",\n args: [appEntryPoint],\n })) as readonly { ethAddress: Address; btcPubKey: Hex }[];\n\n return mapKeyPairs(result);\n }\n\n async getCurrentVaultKeepersVersion(\n appEntryPoint: Address,\n ): Promise<number> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ApplicationRegistryABI,\n functionName: \"getCurrentVaultKeepersVersion\",\n args: [appEntryPoint],\n })) as number;\n\n return result;\n }\n}\n\n/**\n * Reads universal challengers from the ProtocolParams contract.\n *\n * Usage:\n * ```ts\n * const reader = new ViemUniversalChallengerReader(publicClient, protocolParamsAddress);\n * const challengers = await reader.getCurrentUniversalChallengers();\n * ```\n */\nexport class ViemUniversalChallengerReader implements UniversalChallengerReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n async getUniversalChallengersByVersion(\n version: number,\n ): Promise<AddressBTCKeyPair[]> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getUniversalChallengersByVersion\",\n args: [version],\n })) as readonly { ethAddress: Address; btcPubKey: Hex }[];\n\n return mapKeyPairs(result);\n }\n\n async getCurrentUniversalChallengers(): Promise<AddressBTCKeyPair[]> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getCurrentUniversalChallengers\",\n })) as readonly { ethAddress: Address; btcPubKey: Hex }[];\n\n return mapKeyPairs(result);\n }\n\n async getLatestUniversalChallengersVersion(): Promise<number> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"latestUniversalChallengersVersion\",\n })) as number;\n\n return result;\n }\n}\n","/**\n * Types and interfaces for ETH contract readers.\n *\n * These are optional utilities — callers can use them or build their own.\n * Core service functions never import from this module.\n */\n\nimport type { Address, Hex } from \"viem\";\n\n// ============================================================================\n// Vault Registry Types\n// ============================================================================\n\ndeclare const onChainBtcPubkeyBrand: unique symbol;\n\n/**\n * 64-char lowercase hex (no `0x`) x-only BTC pubkey sourced from the\n * on-chain BTCVaultRegistry. The only legitimate producer is\n * {@link VaultRegistryReader.getVaultProviderBtcPubKey}.\n *\n * @stability frozen\n */\nexport type OnChainBtcPubkey = string & {\n readonly [onChainBtcPubkeyBrand]: true;\n};\n\n/**\n * Mirrors `IBTCVaultRegistry.BTCVaultStatus` in BTCVaultRegistry.sol exactly.\n * Use this when consuming `status` from `getVaultBasicInfo` /\n * `getBtcVaultBasicInfo`.\n *\n * Do NOT confuse with the app-side `ContractStatus` enum\n * (`services/deposit/peginState.ts`) — that one is for the indexer and\n * extends this with values 5-7, reassigning 4 to LIQUIDATED. Reading an\n * on-chain status through `ContractStatus[n]` for labels will mislabel\n * Expired(4) as LIQUIDATED.\n */\nexport enum OnChainBtcVaultStatus {\n PENDING = 0,\n VERIFIED = 1,\n ACTIVE = 2,\n REDEEMED = 3,\n EXPIRED = 4,\n}\n\n/** Basic vault info from BTCVaultRegistry.getBtcVaultBasicInfo */\nexport interface VaultBasicInfo {\n depositor: Address;\n depositorBtcPubKey: Hex;\n amount: bigint;\n vaultProvider: Address;\n status: number;\n applicationEntryPoint: Address;\n createdAt: bigint;\n}\n\n/** Protocol info from BTCVaultRegistry.getBtcVaultProtocolInfo */\nexport interface VaultProtocolInfo {\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 /** Block deadline (uint256) for depositor reclaim. TODO(#1690): wire to refund flow. */\n claimExpiredUntil: bigint;\n /** Vault core version (uint16) stamped at registration. VP-side gating only — see #1690. */\n vaultCoreVersion: number;\n}\n\n/** Combined vault data (basic + protocol) */\nexport interface VaultData {\n basic: VaultBasicInfo;\n protocol: VaultProtocolInfo;\n}\n\n/** Interface for reading vault data from the BTCVaultRegistry contract. */\nexport interface VaultRegistryReader {\n getVaultBasicInfo(vaultId: Hex): Promise<VaultBasicInfo>;\n getVaultProtocolInfo(vaultId: Hex): Promise<VaultProtocolInfo>;\n getProtocolInfoBatch(vaultIds: readonly Hex[]): Promise<VaultProtocolInfo[]>;\n getVaultData(vaultId: Hex): Promise<VaultData>;\n getVaultProviderBtcPubKey(vpAddress: Address): Promise<OnChainBtcPubkey>;\n /** Read the protocol pegin fee (in wei) for a given vault provider. */\n getPegInFee(vaultProvider: Address): Promise<bigint>;\n /**\n * Read a vault provider's current commission in basis points.\n *\n * Validates the contract-enforced `[0, 9999]` range — an out-of-range\n * value signals a wrong contract address or ABI drift, not a real rate.\n */\n getVaultProviderCommission(vaultProvider: Address): Promise<number>;\n /**\n * Read `offchainParamsVersion` for many vaults in a single multicall.\n * Returns versions in the same order as the input. Throws if any vault\n * is missing on-chain.\n */\n getOffchainParamsVersionsByVaultIds(\n vaultIds: readonly Hex[],\n ): Promise<number[]>;\n}\n\n// ============================================================================\n// Protocol Params Types (from IProtocolParams.sol)\n// ============================================================================\n\n/**\n * TBV protocol parameters from the ProtocolParams contract.\n * Matches Solidity struct `IProtocolParams.TBVProtocolParams` exactly.\n *\n * All uint64 amounts use bigint (satoshi values can exceed 2^53).\n * uint8 uses number (bounded, max 255).\n */\nexport interface TBVProtocolParams {\n minimumPegInAmount: bigint;\n maxPegInAmount: bigint;\n pegInAckTimeout: bigint;\n pegInActivationTimeout: bigint;\n maxHtlcOutputCount: number;\n /**\n * Number of blocks added to the activation deadline as a grace window\n * during which a depositor may still reclaim an expired pegin via the\n * HTLC preimage. Source: `IProtocolParams.TBVProtocolParams.expiredPegInGraceBlocks`.\n */\n expiredPegInGraceBlocks: bigint;\n}\n\n/**\n * Versioned offchain parameters from the ProtocolParams contract.\n * Matches Solidity struct `IProtocolParams.VersionedOffchainParams` exactly.\n *\n * bigint for: uint256 timelocks, uint64 fee rates/amounts.\n * number for: uint8/uint16/uint32 fields (bounded, safe for JS arithmetic).\n */\nexport interface VersionedOffchainParams {\n timelockAssert: bigint;\n timelockChallengeAssert: bigint;\n securityCouncilKeys: Hex[];\n councilQuorum: number;\n feeRate: bigint;\n babeTotalInstances: number;\n babeInstancesToFinalize: number;\n minVpCommissionBps: number;\n tRefund: number;\n tStale: number;\n minPeginFeeRate: bigint;\n proverCircuitVersion: number;\n minPrepeginDepth: number;\n}\n\n/**\n * Combined peg-in configuration read atomically via multicall.\n * Prevents TOCTOU inconsistency if governance updates params between reads.\n */\nexport interface PegInConfiguration {\n minimumPegInAmount: bigint;\n maxPegInAmount: bigint;\n pegInAckTimeout: bigint;\n pegInActivationTimeout: bigint;\n maxHtlcOutputCount: number;\n expiredPegInGraceBlocks: bigint;\n timelockPegin: number;\n timelockRefund: number;\n minVpCommissionBps: number;\n offchainParams: VersionedOffchainParams;\n /**\n * Version label paired atomically with `offchainParams`.\n * Read in the same multicall as the params struct so that, if a parameter\n * update lands between separate reads, the script-construction code and\n * the version label stay consistent.\n */\n offchainParamsVersion: number;\n}\n\n/**\n * All offchain params snapshots indexed by version, plus the latest version\n * number known when the snapshot was taken. Used by consumers that need to\n * resolve any historical version (e.g. signing for an existing vault locked\n * to an older version).\n */\nexport interface AllOffchainParamsData {\n byVersion: Map<number, VersionedOffchainParams>;\n latestVersion: number;\n}\n\n/**\n * Optional observer invoked by `fetchAllOffchainParams` when a historical\n * version fails validation. Called once per skipped version so callers can\n * log/telemeter without coupling the SDK to a specific logger.\n */\nexport type OnSkippedOffchainParamsVersion = (\n version: number,\n error: Error,\n) => void;\n\n/** Interface for reading protocol parameters from the ProtocolParams contract. */\nexport interface ProtocolParamsReader {\n getTBVProtocolParams(): Promise<TBVProtocolParams>;\n getOffchainParamsByVersion(version: number): Promise<VersionedOffchainParams>;\n getLatestOffchainParams(): Promise<VersionedOffchainParams>;\n getLatestOffchainParamsVersion(): Promise<number>;\n getTimelockPeginByVersion(version: number): Promise<number>;\n getPegInConfiguration(): Promise<PegInConfiguration>;\n fetchAllOffchainParams(\n onSkippedVersion?: OnSkippedOffchainParamsVersion,\n ): Promise<AllOffchainParamsData>;\n}\n\n// ============================================================================\n// Signer-Set Types (from BTCVaultTypes.sol)\n// ============================================================================\n\n/**\n * Matches Solidity struct `BTCVaultTypes.AddressBTCKeyPair` exactly.\n * Used for vault keepers and universal challengers.\n */\nexport interface AddressBTCKeyPair {\n ethAddress: Address;\n btcPubKey: Hex;\n}\n\n/** Interface for reading vault keepers from the ApplicationRegistry contract. */\nexport interface VaultKeeperReader {\n getVaultKeepersByVersion(\n appEntryPoint: Address,\n version: number,\n ): Promise<AddressBTCKeyPair[]>;\n getCurrentVaultKeepers(\n appEntryPoint: Address,\n ): Promise<AddressBTCKeyPair[]>;\n getCurrentVaultKeepersVersion(appEntryPoint: Address): Promise<number>;\n}\n\n/** Interface for reading universal challengers from the ProtocolParams contract. */\nexport interface UniversalChallengerReader {\n getUniversalChallengersByVersion(\n version: number,\n ): Promise<AddressBTCKeyPair[]>;\n getCurrentUniversalChallengers(): Promise<AddressBTCKeyPair[]>;\n getLatestUniversalChallengersVersion(): Promise<number>;\n}\n","/**\n * Runtime validation for vault provider RPC responses.\n *\n * All VP RPC methods return untyped JSON that TypeScript generics cast without\n * inspection. These validators check the critical top-level fields and\n * security-relevant values (status, txids, pubkeys). Optional progress\n * sub-fields (gc_data, ack_collection, claimer_graphs) are NOT validated\n * since they are informational and not used for signing or transaction\n * construction. Only `progress.presigning` sub-fields are checked.\n */\n\nimport {\n COMPRESSED_PUBKEY_HEX_LEN,\n X_ONLY_PUBKEY_HEX_LEN,\n} from \"../../primitives/utils/bitcoin\";\nimport { HEX_RE } from \"../../utils/validation\";\n\nimport { DaemonStatus } from \"./types\";\nimport type {\n BatchGetPeginStatusResponse,\n BatchGetPegoutStatusResponse,\n GetPeginStatusResponse,\n GetPegoutStatusResponse,\n RequestDepositorClaimerArtifactsResponse,\n RequestDepositorPresignTransactionsResponse,\n} from \"./types\";\n\nconst DAEMON_STATUS_VALUES = new Set<string>(Object.values(DaemonStatus));\n\nconst VP_ERROR_PREVIEW_MAX_LEN = 200;\n\nfunction preview(value: unknown): string {\n return (\n JSON.stringify(value)?.slice(0, VP_ERROR_PREVIEW_MAX_LEN) ?? \"undefined\"\n );\n}\n\nconst VP_VALIDATION_USER_MESSAGE =\n \"The vault provider returned an unexpected response. Please try again or contact support.\";\n\n/**\n * Thrown when a VP RPC response fails runtime validation.\n *\n * `.message` is a user-facing string safe to display in the UI.\n * `.detail` contains the technical reason, suitable for logging.\n */\nexport class VpResponseValidationError extends Error {\n readonly detail: string;\n\n constructor(detail: string) {\n super(VP_VALIDATION_USER_MESSAGE);\n this.name = \"VpResponseValidationError\";\n this.detail = detail;\n }\n}\n\n/** Expected length (in hex chars) of a Bitcoin transaction ID (32 bytes). */\nconst TXID_HEX_LEN = 64;\n\nfunction isNonEmptyHex(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0 && HEX_RE.test(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value.length > 0;\n}\n\nfunction assertNonEmptyHex(value: unknown, field: string): void {\n if (!isNonEmptyHex(value)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be a non-empty hex string, got ${preview(value)}`,\n );\n }\n}\n\nfunction assertNonEmptyString(value: unknown, field: string): void {\n if (!isNonEmptyString(value)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be a non-empty string, got ${preview(value)}`,\n );\n }\n}\n\n/**\n * Accept both x-only (64-char) and compressed (66-char) pubkeys from VP responses.\n * The signing code normalizes to x-only via processPublicKeyToXOnly().\n */\nfunction assertBtcPubkey(value: unknown, field: string): void {\n if (\n !isNonEmptyHex(value) ||\n (value.length !== X_ONLY_PUBKEY_HEX_LEN &&\n value.length !== COMPRESSED_PUBKEY_HEX_LEN)\n ) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be a ${X_ONLY_PUBKEY_HEX_LEN} or ${COMPRESSED_PUBKEY_HEX_LEN}-char hex string (BTC pubkey), got ${preview(value)}`,\n );\n }\n}\n\n/**\n * Validate the optional presigning progress fields returned inside PeginProgressDetails.\n */\nfunction validatePresigningProgressFields(\n progress: Record<string, unknown>,\n): void {\n const presigning = progress.presigning;\n if (presigning === undefined || presigning === null) return;\n if (typeof presigning !== \"object\" || Array.isArray(presigning)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"progress.presigning\" must be an object if present`,\n );\n }\n\n const p = presigning as Record<string, unknown>;\n\n if (\n p.depositor_graph_created !== undefined &&\n typeof p.depositor_graph_created !== \"boolean\"\n ) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"progress.presigning.depositor_graph_created\" must be a boolean if present, got ${preview(p.depositor_graph_created)}`,\n );\n }\n\n if (\n p.vk_challenger_presigning_completed !== undefined &&\n typeof p.vk_challenger_presigning_completed !== \"number\"\n ) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"progress.presigning.vk_challenger_presigning_completed\" must be a number if present, got ${preview(p.vk_challenger_presigning_completed)}`,\n );\n }\n\n if (\n p.vk_challenger_presigning_total !== undefined &&\n typeof p.vk_challenger_presigning_total !== \"number\"\n ) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"progress.presigning.vk_challenger_presigning_total\" must be a number if present, got ${preview(p.vk_challenger_presigning_total)}`,\n );\n }\n}\n\n/**\n * Validate a getPeginStatus response.\n *\n * Throws if the status field is not a recognized DaemonStatus value.\n */\nexport function validateGetPeginStatusResponse(\n response: unknown,\n): asserts response is GetPeginStatusResponse {\n if (response === null || typeof response !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: getPeginStatus response is not an object`,\n );\n }\n\n const r = response as Record<string, unknown>;\n\n if (!isNonEmptyHex(r.pegin_txid) || r.pegin_txid.length !== TXID_HEX_LEN) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"pegin_txid\" must be a ${TXID_HEX_LEN}-char hex string (txid), got ${preview(r.pegin_txid)}`,\n );\n }\n\n if (typeof r.status !== \"string\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"status\" must be a string`,\n );\n }\n\n if (!DAEMON_STATUS_VALUES.has(r.status)) {\n throw new VpResponseValidationError(\n `VP response validation failed: unrecognized status \"${r.status}\". Expected one of: ${[...DAEMON_STATUS_VALUES].join(\", \")}`,\n );\n }\n\n if (\n r.progress === null ||\n typeof r.progress !== \"object\" ||\n Array.isArray(r.progress)\n ) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"progress\" must be an object`,\n );\n }\n\n validatePresigningProgressFields(r.progress as Record<string, unknown>);\n\n if (typeof r.health_info !== \"string\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"health_info\" must be a string`,\n );\n }\n\n if (r.last_error !== undefined && typeof r.last_error !== \"string\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"last_error\" must be a string if present, got ${preview(r.last_error)}`,\n );\n }\n}\n\n/**\n * Validate a requestDepositorPresignTransactions response.\n */\nexport function validateRequestDepositorPresignTransactionsResponse(\n response: unknown,\n): asserts response is RequestDepositorPresignTransactionsResponse {\n if (response === null || typeof response !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: requestDepositorPresignTransactions response is not an object`,\n );\n }\n\n const r = response as Record<string, unknown>;\n\n if (!Array.isArray(r.txs)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"txs\" must be an array`,\n );\n }\n\n for (let i = 0; i < r.txs.length; i++) {\n validateClaimerTransactions(r.txs[i], `txs[${i}]`);\n }\n\n if (r.depositor_graph === null || typeof r.depositor_graph !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"depositor_graph\" must be an object`,\n );\n }\n\n validateDepositorGraphTransactions(\n r.depositor_graph as Record<string, unknown>,\n );\n}\n\nfunction validateTransactionData(value: unknown, field: string): void {\n if (value === null || typeof value !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be an object`,\n );\n }\n const tx = value as Record<string, unknown>;\n assertNonEmptyHex(tx.tx_hex, `${field}.tx_hex`);\n}\n\nfunction validateClaimerTransactions(value: unknown, field: string): void {\n if (value === null || typeof value !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be an object`,\n );\n }\n\n const tx = value as Record<string, unknown>;\n\n assertBtcPubkey(tx.claimer_pubkey, `${field}.claimer_pubkey`);\n validateTransactionData(tx.claim_tx, `${field}.claim_tx`);\n validateTransactionData(tx.assert_tx, `${field}.assert_tx`);\n validateTransactionData(tx.payout_tx, `${field}.payout_tx`);\n assertNonEmptyString(tx.payout_psbt, `${field}.payout_psbt`);\n}\n\nfunction validateChallengeAssertConnectorData(\n value: unknown,\n field: string,\n): void {\n if (value === null || typeof value !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be an object`,\n );\n }\n\n const c = value as Record<string, unknown>;\n assertNonEmptyString(c.wots_pks_json, `${field}.wots_pks_json`);\n assertNonEmptyString(c.gc_wots_keys_json, `${field}.gc_wots_keys_json`);\n}\n\nfunction validatePresignDataPerChallenger(value: unknown, field: string): void {\n if (value === null || typeof value !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be an object`,\n );\n }\n\n const d = value as Record<string, unknown>;\n\n assertBtcPubkey(d.challenger_pubkey, `${field}.challenger_pubkey`);\n validateTransactionData(\n d.challenge_assert_x_tx,\n `${field}.challenge_assert_x_tx`,\n );\n validateTransactionData(\n d.challenge_assert_y_tx,\n `${field}.challenge_assert_y_tx`,\n );\n validateTransactionData(d.nopayout_tx, `${field}.nopayout_tx`);\n assertNonEmptyString(d.nopayout_psbt, `${field}.nopayout_psbt`);\n\n if (!Array.isArray(d.challenge_assert_connectors)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}.challenge_assert_connectors\" must be an array`,\n );\n }\n\n for (let i = 0; i < d.challenge_assert_connectors.length; i++) {\n validateChallengeAssertConnectorData(\n d.challenge_assert_connectors[i],\n `${field}.challenge_assert_connectors[${i}]`,\n );\n }\n\n if (!Array.isArray(d.output_label_hashes)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}.output_label_hashes\" must be an array`,\n );\n }\n\n for (let i = 0; i < d.output_label_hashes.length; i++) {\n assertNonEmptyHex(\n d.output_label_hashes[i],\n `${field}.output_label_hashes[${i}]`,\n );\n }\n}\n\n/**\n * Validate a requestDepositorClaimerArtifacts response.\n */\nexport function validateRequestDepositorClaimerArtifactsResponse(\n response: unknown,\n): asserts response is RequestDepositorClaimerArtifactsResponse {\n if (response === null || typeof response !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: requestDepositorClaimerArtifacts response is not an object`,\n );\n }\n\n const r = response as Record<string, unknown>;\n\n if (!isNonEmptyString(r.tx_graph_json)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"tx_graph_json\" must be a non-empty string, got ${preview(r.tx_graph_json)}`,\n );\n }\n\n if (!isNonEmptyHex(r.verifying_key_hex)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"verifying_key_hex\" must be a non-empty hex string, got ${preview(r.verifying_key_hex)}`,\n );\n }\n\n if (\n r.babe_sessions === null ||\n typeof r.babe_sessions !== \"object\" ||\n Array.isArray(r.babe_sessions)\n ) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"babe_sessions\" must be an object`,\n );\n }\n\n const sessionEntries = Object.entries(\n r.babe_sessions as Record<string, unknown>,\n );\n if (sessionEntries.length === 0) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"babe_sessions\" must contain at least one challenger entry`,\n );\n }\n\n for (const [key, session] of sessionEntries) {\n assertBtcPubkey(key, `babe_sessions[\"${key}\"]`);\n if (session === null || typeof session !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"babe_sessions.${key}\" must be an object`,\n );\n }\n const s = session as Record<string, unknown>;\n if (!isNonEmptyHex(s.decryptor_artifacts_hex)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"babe_sessions.${key}.decryptor_artifacts_hex\" must be a non-empty hex string, got ${preview(s.decryptor_artifacts_hex)}`,\n );\n }\n }\n}\n\n/**\n * Validate a single pegout status payload. Embedded by\n * `validateBatchGetPegoutStatusResponse`. Mirrors btc-vault\n * `crates/vaultd/src/rpc/server/pegout_status.rs::GetPegoutStatusResponse`.\n */\nexport function validateGetPegoutStatusResponse(\n response: unknown,\n): asserts response is GetPegoutStatusResponse {\n if (response === null || typeof response !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: pegout status payload is not an object`,\n );\n }\n\n const r = response as Record<string, unknown>;\n\n if (!isNonEmptyHex(r.pegin_txid) || r.pegin_txid.length !== TXID_HEX_LEN) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"pegin_txid\" must be a ${TXID_HEX_LEN}-char hex string (txid), got ${preview(r.pegin_txid)}`,\n );\n }\n\n if (typeof r.found !== \"boolean\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"found\" must be a boolean, got ${preview(r.found)}`,\n );\n }\n\n // `claimer` is `Option<ClaimerPegoutStatus>` server-side; null when absent.\n if (r.claimer !== null) {\n if (typeof r.claimer !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"claimer\" must be an object or null, got ${preview(r.claimer)}`,\n );\n }\n validateClaimerPegoutStatus(r.claimer as Record<string, unknown>);\n }\n\n // `challengers: Vec<ChallengerStatus>` server-side; always present (possibly empty).\n if (!Array.isArray(r.challengers)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"challengers\" must be an array, got ${preview(r.challengers)}`,\n );\n }\n for (let i = 0; i < r.challengers.length; i++) {\n validateChallengerStatus(r.challengers[i], i);\n }\n}\n\nfunction validateClaimerPegoutStatus(value: Record<string, unknown>): void {\n assertNonEmptyString(value.status, \"claimer.status\");\n if (typeof value.failed !== \"boolean\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"claimer.failed\" must be a boolean, got ${preview(value.failed)}`,\n );\n }\n assertNonEmptyString(value.claim_txid, \"claimer.claim_txid\");\n assertNonEmptyString(value.claimer_pubkey, \"claimer.claimer_pubkey\");\n assertNonEmptyString(value.assert_txid, \"claimer.assert_txid\");\n if (typeof value.created_at !== \"number\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"claimer.created_at\" must be a number, got ${preview(value.created_at)}`,\n );\n }\n if (typeof value.updated_at !== \"number\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"claimer.updated_at\" must be a number, got ${preview(value.updated_at)}`,\n );\n }\n}\n\nfunction validateChallengerStatus(value: unknown, index: number): void {\n if (value === null || typeof value !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"challengers[${index}]\" must be an object, got ${preview(value)}`,\n );\n }\n const c = value as Record<string, unknown>;\n assertNonEmptyString(c.status, `challengers[${index}].status`);\n assertNonEmptyString(c.claim_txid, `challengers[${index}].claim_txid`);\n assertNonEmptyString(c.claimer_pubkey, `challengers[${index}].claimer_pubkey`);\n assertNullableString(c.assert_txid, `challengers[${index}].assert_txid`);\n assertNullableString(\n c.challenge_assert_x_txid,\n `challengers[${index}].challenge_assert_x_txid`,\n );\n assertNullableString(\n c.challenge_assert_y_txid,\n `challengers[${index}].challenge_assert_y_txid`,\n );\n assertNullableString(c.nopayout_txid, `challengers[${index}].nopayout_txid`);\n if (typeof c.created_at !== \"number\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"challengers[${index}].created_at\" must be a number, got ${preview(c.created_at)}`,\n );\n }\n if (typeof c.updated_at !== \"number\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"challengers[${index}].updated_at\" must be a number, got ${preview(c.updated_at)}`,\n );\n }\n}\n\nfunction assertNullableString(value: unknown, field: string): void {\n if (value !== null && typeof value !== \"string\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${field}\" must be a string or null, got ${preview(value)}`,\n );\n }\n}\n\n/**\n * Validate a `batchGetPeginStatus` response. Per-result envelope shape:\n * `{ pegin_txid, result: GetPeginStatusResponse | null, error: string | null }`.\n * The inner result (when non-null) is validated via the single-item validator.\n */\nexport function validateBatchGetPeginStatusResponse(\n response: unknown,\n): asserts response is BatchGetPeginStatusResponse {\n validateBatchEnvelope(response, \"batchGetPeginStatus\", (entry) => {\n if (entry.result !== null) {\n validateGetPeginStatusResponse(entry.result);\n }\n });\n}\n\n/** Validate a `batchGetPegoutStatus` response. Same envelope as peginStatus. */\nexport function validateBatchGetPegoutStatusResponse(\n response: unknown,\n): asserts response is BatchGetPegoutStatusResponse {\n validateBatchEnvelope(response, \"batchGetPegoutStatus\", (entry) => {\n if (entry.result !== null) {\n validateGetPegoutStatusResponse(entry.result);\n }\n });\n}\n\ninterface BatchResultEnvelope {\n pegin_txid: string;\n result: unknown;\n error: string | null;\n}\n\nfunction validateBatchEnvelope(\n response: unknown,\n rpcName: string,\n validateInnerResult: (entry: BatchResultEnvelope, index: number) => void,\n): void {\n if (response === null || typeof response !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: ${rpcName} response is not an object`,\n );\n }\n const r = response as Record<string, unknown>;\n if (!Array.isArray(r.results)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${rpcName}.results\" must be an array, got ${preview(r.results)}`,\n );\n }\n for (let i = 0; i < r.results.length; i++) {\n const entry = r.results[i];\n if (entry === null || typeof entry !== \"object\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${rpcName}.results[${i}]\" must be an object, got ${preview(entry)}`,\n );\n }\n const e = entry as Record<string, unknown>;\n if (\n !isNonEmptyHex(e.pegin_txid) ||\n e.pegin_txid.length !== TXID_HEX_LEN\n ) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${rpcName}.results[${i}].pegin_txid\" must be a ${TXID_HEX_LEN}-char hex string, got ${preview(e.pegin_txid)}`,\n );\n }\n if (e.error !== null && typeof e.error !== \"string\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${rpcName}.results[${i}].error\" must be a string or null, got ${preview(e.error)}`,\n );\n }\n // Exactly one of `result` / `error` must be populated. The server only\n // ever sets one per item; treating both-null as a protocol violation\n // surfaces server bugs early instead of letting them silently degrade.\n if (e.result === null && e.error === null) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${rpcName}.results[${i}]\" has neither \"result\" nor \"error\" populated`,\n );\n }\n if (e.result !== null && e.error !== null) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"${rpcName}.results[${i}]\" has both \"result\" and \"error\" populated`,\n );\n }\n validateInnerResult(e as unknown as BatchResultEnvelope, i);\n }\n}\n\nfunction validateDepositorGraphTransactions(\n graph: Record<string, unknown>,\n): void {\n validateTransactionData(graph.claim_tx, \"depositor_graph.claim_tx\");\n validateTransactionData(graph.assert_tx, \"depositor_graph.assert_tx\");\n validateTransactionData(graph.payout_tx, \"depositor_graph.payout_tx\");\n assertNonEmptyString(graph.payout_psbt, \"depositor_graph.payout_psbt\");\n\n if (!Array.isArray(graph.challenger_presign_data)) {\n throw new VpResponseValidationError(\n `VP response validation failed: \"depositor_graph.challenger_presign_data\" must be an array`,\n );\n }\n\n for (let i = 0; i < graph.challenger_presign_data.length; i++) {\n validatePresignDataPerChallenger(\n graph.challenger_presign_data[i],\n `depositor_graph.challenger_presign_data[${i}]`,\n );\n }\n\n if (typeof graph.offchain_params_version !== \"number\") {\n throw new VpResponseValidationError(\n `VP response validation failed: \"depositor_graph.offchain_params_version\" must be a number`,\n );\n }\n}\n","/**\n * JSON-RPC client for the Vault Provider API.\n *\n * Wraps {@link JsonRpcClient} with typed methods matching the\n * `vaultProvider_*` RPC namespace defined in the btc-vault pegin spec.\n *\n * Implements the narrow service interfaces (PeginStatusReader, WotsKeySubmitter,\n * PresignClient, ClaimerArtifactsReader) so it can be passed directly to\n * any deposit protocol service function.\n *\n * @see https://github.com/babylonlabs-io/btc-vault/blob/main/docs/pegin.md\n */\n\nimport type { PeginStatusReader, WotsKeySubmitter, PresignClient, ClaimerArtifactsReader } from \"../../services/deposit/interfaces\";\n\nimport {\n type BearerTokenProvider,\n JsonRpcClient,\n type JsonRpcClientConfig,\n} from \"./json-rpc-client\";\nimport type {\n BatchGetPeginStatusParams,\n BatchGetPeginStatusResponse,\n BatchGetPegoutStatusParams,\n BatchGetPegoutStatusResponse,\n GetPeginStatusParams,\n GetPeginStatusResponse,\n RequestDepositorClaimerArtifactsParams,\n RequestDepositorClaimerArtifactsResponse,\n RequestDepositorPresignTransactionsParams,\n RequestDepositorPresignTransactionsResponse,\n SubmitDepositorPresignaturesParams,\n SubmitDepositorWotsKeyParams,\n} from \"./types\";\nimport {\n validateBatchGetPeginStatusResponse,\n validateBatchGetPegoutStatusResponse,\n validateGetPeginStatusResponse,\n validateRequestDepositorClaimerArtifactsResponse,\n validateRequestDepositorPresignTransactionsResponse,\n} from \"./validators\";\n\nexport interface VaultProviderRpcClientOptions {\n /** Timeout in milliseconds per request (default: 60000) */\n timeout?: number;\n /** Number of retry attempts for safe methods (default: 3) */\n retries?: number;\n /** Initial retry delay in milliseconds (default: 1000) */\n retryDelay?: number;\n /**\n * Custom retry predicate. Default retries only the idempotent read\n * methods: `getPeginStatus`, `batchGetPeginStatus`, `batchGetPegoutStatus`,\n * `requestDepositorPresignTransactions`.\n */\n retryableFor?: (method: string) => boolean;\n /** Custom headers. */\n headers?: Record<string, string>;\n /**\n * Per-request bearer-token source. A non-null return attaches\n * `Authorization: Bearer <token>`; `null` skips auth. Wire a\n * {@link VpTokenProvider} for depositor-gated methods.\n */\n tokenProvider?: BearerTokenProvider;\n /** Maximum response body size, in bytes, for typed JSON-RPC calls */\n maxResponseBytes?: number;\n}\n\nconst DEFAULT_TIMEOUT_MS = 60_000;\n\n/**\n * Concrete VP RPC client implementing all service interfaces.\n *\n * Usage:\n * ```ts\n * const client = new VaultProviderRpcClient(\"https://vp.example.com/rpc\");\n * const status = await client.getPeginStatus({ pegin_txid: \"abc...\" });\n * ```\n */\nexport class VaultProviderRpcClient\n implements PeginStatusReader, WotsKeySubmitter, PresignClient, ClaimerArtifactsReader\n{\n private client: JsonRpcClient;\n\n constructor(baseUrl: string, options?: VaultProviderRpcClientOptions) {\n const config: JsonRpcClientConfig = {\n baseUrl,\n timeout: options?.timeout ?? DEFAULT_TIMEOUT_MS,\n retries: options?.retries,\n retryDelay: options?.retryDelay,\n retryableFor: options?.retryableFor,\n headers: options?.headers,\n tokenProvider: options?.tokenProvider,\n maxResponseBytes: options?.maxResponseBytes,\n };\n this.client = new JsonRpcClient(config);\n }\n\n /**\n * Request the payout/claim/assert transactions that the depositor\n * needs to pre-sign before the vault can be activated on Bitcoin.\n */\n async requestDepositorPresignTransactions(\n params: RequestDepositorPresignTransactionsParams,\n signal?: AbortSignal,\n ): Promise<RequestDepositorPresignTransactionsResponse> {\n const response = await this.client.call<\n RequestDepositorPresignTransactionsParams,\n unknown\n >(\"vaultProvider_requestDepositorPresignTransactions\", params, signal);\n validateRequestDepositorPresignTransactionsResponse(response);\n return response;\n }\n\n /**\n * Submit the depositor's pre-signatures for the payout transactions\n * and the depositor-as-claimer graph.\n */\n async submitDepositorPresignatures(\n params: SubmitDepositorPresignaturesParams,\n signal?: AbortSignal,\n ): Promise<void> {\n return this.client.call<SubmitDepositorPresignaturesParams, void>(\n \"vaultProvider_submitDepositorPresignatures\",\n params,\n signal,\n );\n }\n\n /**\n * Submit the depositor's WOTS public key to the vault provider.\n * Called after the pegin is finalized on Ethereum, when the VP is in\n * `PendingDepositorWotsPK` status.\n */\n async submitDepositorWotsKey(\n params: SubmitDepositorWotsKeyParams,\n signal?: AbortSignal,\n ): Promise<void> {\n return this.client.call<SubmitDepositorWotsKeyParams, void>(\n \"vaultProvider_submitDepositorWotsKey\",\n params,\n signal,\n );\n }\n\n /**\n * Request the BaBe DecryptorArtifacts needed for the depositor to\n * independently evaluate garbled circuits during a challenge.\n */\n async requestDepositorClaimerArtifacts(\n params: RequestDepositorClaimerArtifactsParams,\n signal?: AbortSignal,\n ): Promise<RequestDepositorClaimerArtifactsResponse> {\n const response = await this.client.call<\n RequestDepositorClaimerArtifactsParams,\n unknown\n >(\"vaultProvider_requestDepositorClaimerArtifacts\", params, signal);\n validateRequestDepositorClaimerArtifactsResponse(response);\n return response;\n }\n\n /** Get the current pegin status from the vault provider daemon. */\n async getPeginStatus(\n params: GetPeginStatusParams,\n signal?: AbortSignal,\n ): Promise<GetPeginStatusResponse> {\n const response = await this.client.call<GetPeginStatusParams, unknown>(\n \"vaultProvider_getPeginStatus\",\n params,\n signal,\n );\n validateGetPeginStatusResponse(response);\n return response;\n }\n\n /**\n * Get pegin status for many txids in one round trip. Per-result envelope\n * isolates per-pegin failures from the overall RPC. Caller must chunk\n * inputs at `VP_BATCH_MAX_SIZE`.\n */\n async batchGetPeginStatus(\n params: BatchGetPeginStatusParams,\n signal?: AbortSignal,\n ): Promise<BatchGetPeginStatusResponse> {\n const response = await this.client.call<\n BatchGetPeginStatusParams,\n unknown\n >(\"vaultProvider_batchGetPeginStatus\", params, signal);\n validateBatchGetPeginStatusResponse(response);\n return response;\n }\n\n /**\n * Get pegout status for many txids in one round trip. Same per-result\n * envelope semantics as `batchGetPeginStatus`.\n */\n async batchGetPegoutStatus(\n params: BatchGetPegoutStatusParams,\n signal?: AbortSignal,\n ): Promise<BatchGetPegoutStatusResponse> {\n const response = await this.client.call<\n BatchGetPegoutStatusParams,\n unknown\n >(\"vaultProvider_batchGetPegoutStatus\", params, signal);\n validateBatchGetPegoutStatusResponse(response);\n return response;\n }\n}\n","/**\n * Defensive helper for attributing per-item results in a VP batch RPC\n * response back to the requested txids. The server promises 1:1 ordered\n * results, but we don't trust that promise — a server bug could duplicate,\n * skip, or scramble items, and silent attribution-by-array-index would\n * mask the bug.\n *\n * Lowercases all txids on both sides to absorb case mismatch (the FE\n * strips `0x` but doesn't otherwise normalize).\n *\n * @module tbv/core/clients/vault-provider/batchAttribution\n */\n\n/** Per-item entry in a VP batch response. */\nexport interface BatchResultEntry<T> {\n pegin_txid: string;\n result: T | null;\n error: string | null;\n}\n\n/** Output of {@link attributeBatchResults}. */\nexport interface BatchAttributionResult<T> {\n /** Lowercase requested txid -> per-item envelope. */\n byTxid: Map<string, { result: T | null; error: string | null }>;\n /** Requested txids that did not appear in the response. */\n missing: string[];\n /** Echoed txids that were not in the request — logged + dropped. */\n unexpected: string[];\n /** Echoed txids that appeared more than once — first kept, rest dropped. */\n duplicate: string[];\n}\n\n/**\n * Attribute batch results to requested txids defensively.\n *\n * Both `requestedTxids` and the echoed `pegin_txid` field on each result\n * are lowercased before lookup. Duplicates and unexpected echoes are\n * surfaced so callers can flag the affected items as errored rather than\n * silently overwriting state.\n *\n * `requestedTxids` may contain duplicates; they are de-duplicated for the\n * purposes of map keys (each unique txid becomes a single map entry).\n */\nexport function attributeBatchResults<T>(\n requestedTxids: string[],\n results: ReadonlyArray<BatchResultEntry<T>>,\n): BatchAttributionResult<T> {\n const requestedSet = new Set<string>();\n for (const txid of requestedTxids) {\n requestedSet.add(txid.toLowerCase());\n }\n\n const byTxid = new Map<\n string,\n { result: T | null; error: string | null }\n >();\n const seen = new Set<string>();\n const duplicate: string[] = [];\n const unexpected: string[] = [];\n\n for (const entry of results) {\n const lower = entry.pegin_txid.toLowerCase();\n if (!requestedSet.has(lower)) {\n unexpected.push(lower);\n continue;\n }\n if (seen.has(lower)) {\n duplicate.push(lower);\n continue;\n }\n seen.add(lower);\n byTxid.set(lower, { result: entry.result, error: entry.error });\n }\n\n const missing: string[] = [];\n for (const txid of requestedSet) {\n if (!seen.has(txid)) missing.push(txid);\n }\n\n return { byTxid, missing, unexpected, duplicate };\n}\n","/**\n * Generic chunk + attribute + dispatch loop for VP batch RPCs.\n *\n * Wraps {@link attributeBatchResults} with chunking and per-callback\n * dispatch so the FE polling hooks (and any future SDK consumer) only\n * have to declare per-item handlers — chunking by `VP_BATCH_MAX_SIZE`,\n * lowercase txid normalization, missing/duplicate/unexpected\n * surfacing, and the duplicate-skip invariant in the byTxid loop are\n * all owned here.\n *\n * @module tbv/core/clients/vault-provider/batchPoll\n */\n\nimport {\n attributeBatchResults,\n type BatchResultEntry,\n} from \"./batchAttribution\";\nimport { VP_BATCH_MAX_SIZE } from \"./types\";\n\nexport interface BatchPollByProviderOptions<TItem, TResult> {\n /** Items to poll for this provider, e.g. `DepositToPoll[]`. */\n items: TItem[];\n /** Extract the canonical txid for each item. Helper lowercases it. */\n getTxid: (item: TItem) => string;\n /**\n * Per-chunk RPC call. Receives lowercased txids; returns the batch\n * envelope. Caller wraps `rpcClient.batchGet*Status({ pegin_txids })`.\n */\n batchCall: (\n txids: string[],\n ) => Promise<{ results: ReadonlyArray<BatchResultEntry<TResult>> }>;\n /**\n * Handle a per-item envelope. Exactly one of `result` / `error` is\n * populated (validator invariant). Caller decides UI state, logging,\n * etc. Not invoked for txids surfaced via {@link onDuplicate}.\n *\n * Note: `envelope.pegin_txid` is the lowercased txid the helper\n * sent in the request, not whatever case/encoding the server echoed.\n */\n onItem: (item: TItem, envelope: BatchResultEntry<TResult>) => void;\n /** Server omitted this item from the response. */\n onMissing: (item: TItem) => void;\n /** Server returned this item more than once. Caller picks UI state. */\n onDuplicate: (item: TItem) => void;\n /**\n * Optional aggregate signal for an entire chunk where the server\n * returned duplicates. Fires once per chunk (only if `count > 0`)\n * AFTER all per-item `onDuplicate` dispatches. Caller typically logs\n * the count alongside the provider name.\n */\n onDuplicateBatch?: (count: number) => void;\n /**\n * The whole chunk's RPC call failed (transport or response\n * validation). Receives the chunk and the error. Caller decides how\n * to project that onto per-item state.\n */\n onWholeBatchError: (chunk: TItem[], error: unknown) => void;\n /**\n * Server returned txids that were not in the request. Caller\n * typically logs the count for observability — there's no recovery\n * action since the original request items are unaffected. Optional;\n * defaults to no-op.\n */\n onUnexpected?: (echoedTxids: string[]) => void;\n /**\n * Maximum items per RPC call. Defaults to {@link VP_BATCH_MAX_SIZE}.\n * Exposed for tests so chunking can be exercised without 50+\n * fixtures.\n */\n batchSize?: number;\n}\n\nexport async function batchPollByProvider<TItem, TResult>(\n options: BatchPollByProviderOptions<TItem, TResult>,\n): Promise<void> {\n const {\n items,\n getTxid,\n batchCall,\n onItem,\n onMissing,\n onDuplicate,\n onDuplicateBatch,\n onWholeBatchError,\n onUnexpected,\n batchSize = VP_BATCH_MAX_SIZE,\n } = options;\n\n if (!Number.isInteger(batchSize) || batchSize <= 0) {\n throw new Error(\n `batchPollByProvider: batchSize must be a positive integer, got ${batchSize}`,\n );\n }\n\n for (let i = 0; i < items.length; i += batchSize) {\n const chunk = items.slice(i, i + batchSize);\n const txidToItem = new Map<string, TItem>();\n const txids: string[] = [];\n for (const item of chunk) {\n const lowerTxid = getTxid(item).toLowerCase();\n txidToItem.set(lowerTxid, item);\n txids.push(lowerTxid);\n }\n\n // Both the RPC call and attribution sit inside the same try/catch\n // so a malformed-batch validator throw is routed through\n // `onWholeBatchError` rather than aborting the polling pass.\n let attribution;\n try {\n const response = await batchCall(txids);\n attribution = attributeBatchResults<TResult>(txids, response.results);\n } catch (error) {\n onWholeBatchError(chunk, error);\n continue;\n }\n\n if (onUnexpected && attribution.unexpected.length > 0) {\n onUnexpected(attribution.unexpected);\n }\n\n const duplicateTxids = new Set(attribution.duplicate);\n for (const txid of duplicateTxids) {\n const item = txidToItem.get(txid);\n if (item) onDuplicate(item);\n }\n if (onDuplicateBatch && duplicateTxids.size > 0) {\n onDuplicateBatch(duplicateTxids.size);\n }\n for (const txid of attribution.missing) {\n const item = txidToItem.get(txid);\n if (item) onMissing(item);\n }\n for (const [txid, envelope] of attribution.byTxid) {\n // Skip duplicates — already dispatched via onDuplicate above.\n if (duplicateTxids.has(txid)) continue;\n const item = txidToItem.get(txid);\n if (!item) continue;\n onItem(item, {\n pegin_txid: txid,\n result: envelope.result,\n error: envelope.error,\n });\n }\n }\n}\n","/**\n * BIP-322 \"simple\" signature verification for P2TR key-path.\n *\n * Mirrors the Rust reference in\n * `btc-vault/crates/btc-signer/src/message.rs::verify_bip322_message`\n * (which delegates to `rust-bitcoin::bip322::verify_simple` for a\n * P2TR key-path-only address with no merkle root).\n *\n * The algorithm:\n *\n * 1. Compute the BIP-322 tagged-hash of the message:\n * m_hash = SHA256( SHA256(tag) || SHA256(tag) || message )\n * where tag = \"BIP0322-signed-message\".\n *\n * 2. Build a virtual \"to_spend\" transaction with one input (prevout\n * all-zero txid + 0xFFFFFFFF vout, scriptSig = `OP_0 PUSH32 m_hash`,\n * sequence = 0) and one output (value 0, scriptPubKey = P2TR for\n * the signer's x-only pubkey).\n *\n * 3. Build a \"to_sign\" transaction that spends to_spend[0] and has a\n * single `OP_RETURN` output (value 0).\n *\n * 4. Compute the BIP-341 taproot sighash of to_sign input 0 with\n * SIGHASH_DEFAULT (0x00).\n *\n * 5. Verify the 64-byte Schnorr signature against the **tweaked**\n * output key `Q = P + tap_tweak(P) * G`, where `tap_tweak(P) =\n * hash_TapTweak(serialize_x_only(P))` (no merkle root — key-path\n * only).\n *\n * `bitcoinjs-lib` handles (2)–(4); `tiny-secp256k1-asmjs` provides\n * the tweak and Schnorr verify. Pulling in a full BIP-322 library\n * would add a peer dep for what amounts to ~40 lines of glue.\n *\n * @module tbv/core/clients/vault-provider/auth/bip322Verify\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { payments, Transaction } from \"bitcoinjs-lib\";\n\nimport { Buffer } from \"buffer\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\n/** BIP-322 message tag (BIP-340 tagged-hash style). */\nconst BIP322_TAG = \"BIP0322-signed-message\";\n\n/** BIP-341 taproot-tweak tag. */\nconst TAPTWEAK_TAG = \"TapTweak\";\n\nconst X_ONLY_PUBKEY_SIZE = 32;\nconst SCHNORR_SIG_SIZE = 64;\n\n/**\n * BIP-340 tagged hash: `SHA256( SHA256(tag) || SHA256(tag) || data )`.\n * Used for both BIP-322 message hashing and BIP-341 tap-tweak.\n */\nfunction taggedHash(tag: string, data: Uint8Array): Uint8Array {\n const tagBytes = new TextEncoder().encode(tag);\n const tagHash = sha256(tagBytes);\n const preimage = new Uint8Array(tagHash.length * 2 + data.length);\n preimage.set(tagHash, 0);\n preimage.set(tagHash, tagHash.length);\n preimage.set(data, tagHash.length * 2);\n return sha256(preimage);\n}\n\n/**\n * Apply BIP-341 taproot tweak to an x-only pubkey with no merkle\n * root (key-path-only address).\n *\n * `tap_tweak = hash_TapTweak(P)`\n * `Q = P + tap_tweak * G` (x-only, even-Y parity)\n *\n * Returns the tweaked 32-byte x-only pubkey, or null if the tweak\n * produces a point-at-infinity or invalid result.\n */\nfunction tweakXOnlyKey(xOnly: Uint8Array): Uint8Array | null {\n if (xOnly.length !== X_ONLY_PUBKEY_SIZE) return null;\n const tweak = taggedHash(TAPTWEAK_TAG, xOnly);\n const tweaked = ecc.xOnlyPointAddTweak(xOnly, tweak);\n return tweaked ? tweaked.xOnlyPubkey : null;\n}\n\n/**\n * Verify a BIP-322 \"simple\" P2TR key-path signature over an arbitrary\n * byte message.\n *\n * @internal Exposed only so the golden-vector test suite can pin the\n * verifier independently of `verifyServerIdentity`. Production callers\n * should use `verifyServerIdentity` from `./serverIdentity` instead.\n *\n * @param messageBytes - The bytes that were signed (e.g. a CBOR-encoded\n * payload). Not pre-hashed; this function applies\n * the BIP-322 tagged hash internally.\n * @param xOnlyPubkey - 32-byte x-only pubkey of the signer (pre-tweak).\n * @param signature - 64-byte raw Schnorr signature (BIP-340), as\n * emitted by a key-path witness with\n * SIGHASH_DEFAULT.\n * @returns `true` if the signature verifies against the address\n * derived from `xOnlyPubkey`; `false` otherwise.\n */\nexport function verifyBip322Simple(\n messageBytes: Uint8Array,\n xOnlyPubkey: Uint8Array,\n signature: Uint8Array,\n): boolean {\n if (xOnlyPubkey.length !== X_ONLY_PUBKEY_SIZE) return false;\n if (signature.length !== SCHNORR_SIG_SIZE) return false;\n\n // Any exception from the underlying crypto libraries (e.g. the\n // `Expected Point` error `tiny-secp256k1` throws when the supplied\n // 32 bytes don't represent a valid x-coordinate on secp256k1) is\n // treated as a verification failure rather than propagated — a\n // verifier MUST return a boolean, not raise.\n try {\n // Step 1: BIP-322 tagged hash of the message.\n const messageHash = taggedHash(BIP322_TAG, messageBytes);\n\n // Step 2: scriptPubKey for the signer's P2TR key-path-only address.\n // bitcoinjs-lib's `payments.p2tr({ internalPubkey })` computes the\n // tweak and produces the `OP_1 <tweaked_xonly>` output script.\n const p2tr = payments.p2tr({\n internalPubkey: Buffer.from(xOnlyPubkey),\n });\n if (!p2tr.output) return false;\n const scriptPubKey = p2tr.output;\n\n // Step 3: build to_spend virtual tx.\n //\n // NOTE: bitcoinjs-lib v6.x's `Transaction.addOutput` and\n // `hashForWitnessV1` are typed for `Satoshi` (a UInt53 number),\n // not `bigint`. Passing `BigInt(0)` triggers a typeforce\n // assertion in `addOutput` (\"Expected property '1' of type\n // Satoshi, got BigInt 0\") which our outer try/catch silently\n // turns into `verify -> false`. Use plain `0` everywhere.\n const ZERO_SATS = 0;\n const toSpend = new Transaction();\n toSpend.version = 0;\n toSpend.locktime = 0;\n // scriptSig: OP_0 (0x00) + OP_PUSHBYTES_32 (0x20) + message_hash (32B)\n const scriptSig = Buffer.concat([\n Buffer.from([0x00, 0x20]),\n Buffer.from(messageHash),\n ]);\n toSpend.addInput(\n Buffer.alloc(32, 0), // prev_txid = 0x0000...0000\n 0xffffffff, // prev_vout = 0xFFFFFFFF\n 0, // sequence = 0\n scriptSig,\n );\n toSpend.addOutput(scriptPubKey, ZERO_SATS);\n\n // Step 4: build to_sign virtual tx spending to_spend[0].\n const toSign = new Transaction();\n toSign.version = 0;\n toSign.locktime = 0;\n // Bitcoin txid in natural-byte (little-endian) form.\n const toSpendTxid = toSpend.getHash();\n toSign.addInput(toSpendTxid, 0, 0);\n toSign.addOutput(Buffer.from([0x6a]), ZERO_SATS); // OP_RETURN\n\n // Step 5: taproot sighash for to_sign input 0 (SIGHASH_DEFAULT).\n const sighash = toSign.hashForWitnessV1(\n 0,\n [scriptPubKey],\n [ZERO_SATS],\n Transaction.SIGHASH_DEFAULT,\n );\n\n // Step 6: tweak the x-only pubkey (no merkle root) and verify Schnorr.\n const tweakedXOnly = tweakXOnlyKey(xOnlyPubkey);\n if (!tweakedXOnly) return false;\n\n return ecc.verifySchnorr(sighash, tweakedXOnly, signature);\n } catch {\n return false;\n }\n}\n","/**\n * Minimal CBOR encoder for the server-identity payload shape.\n *\n * We only need to encode one specific CBOR structure — the 3-tuple\n * `(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey_bytes, expires_at_u64)` —\n * byte-for-byte identical to what the Rust `ciborium` crate produces\n * for the corresponding tuple, because that's the exact message the\n * VP signs with BIP-322.\n *\n * IMPORTANT encoding quirk: the Rust side passes the domain and\n * pubkey as `&[u8]` / `Vec<u8>` without a `#[serde(with = \"serde_bytes\")]`\n * attribute, so serde/ciborium encodes them as **CBOR arrays of u8**\n * (major type 4, one item per byte) — NOT as CBOR byte strings (major\n * type 2). A naive byte-string encoding would produce the wrong bytes\n * and signature verification would fail.\n *\n * Rather than pull in a full CBOR dependency for this one shape, we\n * implement the exact subset inline (~40 LOC) and pin it with golden\n * vectors against the Rust reference output.\n *\n * @module tbv/core/clients/vault-provider/auth/cbor\n */\n\n/**\n * Encode a small CBOR unsigned-integer \"head\" byte for major type\n * `major` (0..7) with argument `arg` (0..2^64-1).\n *\n * Returns the header bytes; the caller concatenates any trailing data\n * (e.g. array elements). Encoding rules:\n * arg < 24 → single byte `(major << 5) | arg`\n * arg < 256 → `(major << 5) | 24` + 1-byte arg\n * arg < 65536 → `(major << 5) | 25` + 2-byte BE arg\n * arg < 2^32 → `(major << 5) | 26` + 4-byte BE arg\n * arg < 2^64 → `(major << 5) | 27` + 8-byte BE arg\n */\nfunction cborHead(major: number, arg: number | bigint): Uint8Array {\n const tag = (major & 0x07) << 5;\n const n = typeof arg === \"bigint\" ? arg : BigInt(arg);\n if (n < 0n) throw new Error(\"cborHead: negative argument\");\n\n if (n < 24n) return new Uint8Array([tag | Number(n)]);\n if (n < 0x100n) return new Uint8Array([tag | 24, Number(n)]);\n if (n < 0x10000n) {\n const v = Number(n);\n return new Uint8Array([tag | 25, (v >>> 8) & 0xff, v & 0xff]);\n }\n if (n < 0x1_0000_0000n) {\n const v = Number(n);\n return new Uint8Array([\n tag | 26,\n (v >>> 24) & 0xff,\n (v >>> 16) & 0xff,\n (v >>> 8) & 0xff,\n v & 0xff,\n ]);\n }\n // 8-byte BE for u64 range\n const out = new Uint8Array(9);\n out[0] = tag | 27;\n for (let i = 7; i >= 0; i--) {\n out[1 + i] = Number(n >> BigInt((7 - i) * 8)) & 0xff;\n }\n return out;\n}\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n const total = parts.reduce((s, p) => s + p.length, 0);\n const out = new Uint8Array(total);\n let offset = 0;\n for (const p of parts) {\n out.set(p, offset);\n offset += p.length;\n }\n return out;\n}\n\n/**\n * Encode a `Vec<u8>` / `&[u8]` the way ciborium does by default — as a\n * CBOR array of u8 (major type 4), one element per byte.\n *\n * Each byte becomes a CBOR unsigned integer (major type 0): bytes\n * < 24 are encoded as single bytes, bytes 24..255 as `0x18 XX`.\n */\nfunction encodeBytesAsArrayOfU8(bytes: Uint8Array): Uint8Array {\n const header = cborHead(4, bytes.length);\n const items: Uint8Array[] = [header];\n for (const b of bytes) {\n items.push(cborHead(0, b));\n }\n return concat(...items);\n}\n\n/**\n * Encode the server-identity payload the Rust side signs:\n *\n * ciborium::into_writer(\n * &(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey.serialize().to_vec(), expires_at),\n * buf\n * )\n *\n * Output bytes are byte-for-byte identical to the Rust reference,\n * pinned by the golden vector in the corresponding test file.\n *\n * @internal Exposed only for the golden-vector test that pins this\n * encoding against ciborium's output. Production callers reach this\n * via `verifyServerIdentity` from `./serverIdentity`.\n *\n * @param domain - Must be `\"btc-auth.server-identity.v1\"` (27 bytes)\n * — the constant from btc-vault's `server_identity.rs`.\n * @param ephemeralPubkeyCompressed - 33-byte SEC1-compressed pubkey.\n * @param expiresAt - Unix timestamp (seconds). Must be a safe integer.\n */\nexport function encodeServerIdentityPayload(\n domain: Uint8Array,\n ephemeralPubkeyCompressed: Uint8Array,\n expiresAt: number,\n): Uint8Array {\n if (!Number.isSafeInteger(expiresAt) || expiresAt < 0) {\n throw new Error(\n `encodeServerIdentityPayload: expires_at must be a non-negative safe integer, got ${expiresAt}`,\n );\n }\n const arrayHeader = cborHead(4, 3); // 3-tuple encoded as array of 3\n const domainBytes = encodeBytesAsArrayOfU8(domain);\n const pubkeyBytes = encodeBytesAsArrayOfU8(ephemeralPubkeyCompressed);\n const expiresAtBytes = cborHead(0, expiresAt);\n return concat(arrayHeader, domainBytes, pubkeyBytes, expiresAtBytes);\n}\n","/**\n * Server-identity verification for the vault provider's\n * `auth_createDepositorToken` response.\n *\n * The VP returns a `ServerIdentityResponse` bundled with every issued\n * token:\n *\n * - `server_pubkey`: VP's persistent x-only pubkey (HEX, 32B)\n * - `ephemeral_pubkey`: VP's ephemeral token-signing key (HEX, 33B compressed)\n * - `expires_at`: Unix timestamp when the ephemeral key expires\n * - `signature`: BIP-322 signature by the persistent key over\n * `(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey, expires_at)`\n *\n * The FE pins `server_pubkey` against the on-chain `VaultProvider.btcPubKey`\n * it reads from the registry contract. A mismatch rejects the token.\n *\n * @module tbv/core/clients/vault-provider/auth/serverIdentity\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\n\nimport {\n COMPRESSED_PUBKEY_HEX_LEN,\n SCHNORR_SIG_HEX_LEN,\n stripHexPrefix,\n X_ONLY_PUBKEY_HEX_LEN,\n} from \"../../../primitives/utils/bitcoin\";\nimport { HEX_RE } from \"../../../utils/validation\";\n\nimport { verifyBip322Simple } from \"./bip322Verify\";\nimport { encodeServerIdentityPayload } from \"./cbor\";\n\n/**\n * Byte-string domain the btc-vault Rust reference passes as the first\n * element of the CBOR tuple signed over for server-identity proofs.\n * Must match `SERVER_IDENTITY_DOMAIN` in\n * `btc-vault/crates/btc-auth/src/server_identity.rs`.\n */\nconst SERVER_IDENTITY_DOMAIN = new TextEncoder().encode(\n \"btc-auth.server-identity.v1\",\n);\n\n/**\n * Cap on `proof.expires_at - now`. Bounds how long a leaked VP\n * ephemeral key stays usable; the bearer token's own TTL does not\n * (different trust boundary). 2h = Rust ref VP's 1h rotation × 2 for\n * clock skew. Override per call via `maxLifetimeSecs`.\n */\nconst DEFAULT_MAX_PROOF_LIFETIME_SECS = 2 * 3600;\n\n/**\n * Wire representation from btc-vault's `ServerIdentityResponse`.\n */\nexport interface ServerIdentityResponse {\n /** Hex-encoded x-only (32-byte) persistent server pubkey. */\n server_pubkey: string;\n /** Hex-encoded compressed (33-byte) ephemeral token-signing pubkey. */\n ephemeral_pubkey: string;\n /** Unix timestamp at which the ephemeral key expires. */\n expires_at: number;\n /** Hex-encoded 64-byte BIP-322 Schnorr signature. */\n signature: string;\n}\n\nexport interface VerifyServerIdentityInput {\n /** The proof returned by `auth_createDepositorToken`. */\n proof: ServerIdentityResponse;\n /**\n * The x-only persistent server pubkey the FE expects (sourced from\n * the on-chain `VaultProvider.btcPubKey` via the vault registry\n * reader). 64-char lowercase hex, no `0x` prefix.\n */\n pinnedServerPubkey: string;\n /** Current Unix timestamp in seconds. Injected for testability. */\n now: number;\n /** Cap on `proof.expires_at - now` (seconds). Defaults to {@link DEFAULT_MAX_PROOF_LIFETIME_SECS}. */\n maxLifetimeSecs?: number;\n}\n\nexport class ServerIdentityError extends Error {\n constructor(\n message: string,\n public readonly reason:\n | \"pinned_pubkey_mismatch\"\n | \"expired\"\n | \"expires_too_far\"\n | \"invalid_expires_at\"\n | \"invalid_max_lifetime\"\n | \"invalid_pubkey_encoding\"\n | \"invalid_ephemeral_pubkey\"\n | \"invalid_signature_encoding\"\n | \"signature_verification_failed\",\n ) {\n super(message);\n this.name = \"ServerIdentityError\";\n }\n}\n\n/** Parse a lowercase-hex string to bytes. Expects even length, already validated. */\nfunction hexToBytes(hex: string): Uint8Array {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < out.length; i++) {\n out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n }\n return out;\n}\n\n\n/**\n * Verify a server identity proof against a pinned server pubkey.\n *\n * Checks:\n * 1. `server_pubkey` matches the pin.\n * 2. `now < expires_at <= now + maxLifetimeSecs` (with integer guards).\n * 3. `ephemeral_pubkey` is a well-formed 33-byte compressed pubkey.\n * 4. `signature` is a well-formed 64-byte Schnorr hex string.\n * 5. The BIP-322 Schnorr signature cryptographically verifies\n * against `server_pubkey` over the CBOR-encoded tuple\n * `(SERVER_IDENTITY_DOMAIN, ephemeral_pubkey, expires_at)`.\n *\n * Step 5 is what actually binds the ephemeral key to the persistent\n * pubkey — without it, a TLS-MITM attacker who reads the pinned\n * pubkey from the on-chain registry could substitute an arbitrary\n * ephemeral pubkey paired with any lexically-valid signature.\n *\n * @throws ServerIdentityError on any validation failure.\n */\nexport function verifyServerIdentity(input: VerifyServerIdentityInput): void {\n const { proof, pinnedServerPubkey, now } = input;\n const maxLifetimeSecs =\n input.maxLifetimeSecs ?? DEFAULT_MAX_PROOF_LIFETIME_SECS;\n\n const pinned = stripHexPrefix(pinnedServerPubkey).toLowerCase();\n if (pinned.length !== X_ONLY_PUBKEY_HEX_LEN || !HEX_RE.test(pinned)) {\n throw new ServerIdentityError(\n `pinnedServerPubkey must be 32-byte hex; got ${pinned.length} chars`,\n \"invalid_pubkey_encoding\",\n );\n }\n\n const actual = stripHexPrefix(proof.server_pubkey).toLowerCase();\n if (actual.length !== X_ONLY_PUBKEY_HEX_LEN || !HEX_RE.test(actual)) {\n throw new ServerIdentityError(\n `server_pubkey must be 32-byte hex; got ${actual.length} chars`,\n \"invalid_pubkey_encoding\",\n );\n }\n\n if (actual !== pinned) {\n throw new ServerIdentityError(\n `server_pubkey does not match pinned value: expected ${pinned}, got ${actual}`,\n \"pinned_pubkey_mismatch\",\n );\n }\n\n // Validate both sides of the comparison are well-formed integers\n // BEFORE comparing — untrusted JSON-RPC input can supply\n // undefined/NaN/string values for `expires_at`, and relational\n // comparisons with those silently evaluate to `false` (accepting the\n // proof). Caller's `now` is injected but we still sanity-check it.\n // Garbage data and \"valid but past\" both render the proof unusable\n // but mean different things to a caller — keep the reasons distinct.\n if (!Number.isSafeInteger(proof.expires_at)) {\n throw new ServerIdentityError(\n `expires_at must be a finite integer; got ${JSON.stringify(proof.expires_at)}`,\n \"invalid_expires_at\",\n );\n }\n if (!Number.isSafeInteger(now)) {\n throw new ServerIdentityError(\n `now must be a finite integer; got ${JSON.stringify(now)}`,\n \"invalid_expires_at\",\n );\n }\n if (proof.expires_at <= now) {\n throw new ServerIdentityError(\n `server identity proof expired at ${proof.expires_at}, now ${now}`,\n \"expired\",\n );\n }\n if (!Number.isSafeInteger(maxLifetimeSecs) || maxLifetimeSecs <= 0) {\n throw new ServerIdentityError(\n `maxLifetimeSecs must be a positive safe integer; got ${JSON.stringify(maxLifetimeSecs)}`,\n \"invalid_max_lifetime\",\n );\n }\n if (proof.expires_at - now > maxLifetimeSecs) {\n throw new ServerIdentityError(\n `server identity proof expires too far in the future: ` +\n `expires_at=${proof.expires_at}, now=${now}, max lifetime=${maxLifetimeSecs}s`,\n \"expires_too_far\",\n );\n }\n\n const eph = stripHexPrefix(proof.ephemeral_pubkey).toLowerCase();\n if (eph.length !== COMPRESSED_PUBKEY_HEX_LEN || !HEX_RE.test(eph)) {\n throw new ServerIdentityError(\n `ephemeral_pubkey must be 33-byte compressed hex; got ${eph.length} chars`,\n \"invalid_ephemeral_pubkey\",\n );\n }\n const prefix = eph.slice(0, 2);\n if (prefix !== \"02\" && prefix !== \"03\") {\n throw new ServerIdentityError(\n `ephemeral_pubkey must be compressed (prefix 02/03); got ${prefix}`,\n \"invalid_ephemeral_pubkey\",\n );\n }\n // Curve validation. The BIP-322 signature attests to the byte string\n // of `ephemeral_pubkey` only, not to its curve validity. Without\n // this check, a server could sign a structurally-valid byte string\n // that doesn't decode to a secp256k1 point — passing verification\n // here and surfacing as an obscure crypto error later when the\n // depositor tries to use the key. Reject up front.\n const ephBytes = hexToBytes(eph);\n if (!ecc.isPoint(ephBytes)) {\n throw new ServerIdentityError(\n \"ephemeral_pubkey is not a valid secp256k1 point\",\n \"invalid_ephemeral_pubkey\",\n );\n }\n\n const sig = stripHexPrefix(proof.signature).toLowerCase();\n if (sig.length !== SCHNORR_SIG_HEX_LEN || !HEX_RE.test(sig)) {\n throw new ServerIdentityError(\n `signature must be 64-byte Schnorr hex; got ${sig.length} chars`,\n \"invalid_signature_encoding\",\n );\n }\n\n // Cryptographic verification of the BIP-322 signature over the\n // CBOR-encoded payload. Without this, the ephemeral-key binding is\n // unenforced and a TLS-MITM could substitute a fake ephemeral key\n // alongside the real (publicly-readable) pinned pubkey.\n const payload = encodeServerIdentityPayload(\n SERVER_IDENTITY_DOMAIN,\n hexToBytes(eph),\n proof.expires_at,\n );\n const verified = verifyBip322Simple(payload, hexToBytes(actual), hexToBytes(sig));\n if (!verified) {\n throw new ServerIdentityError(\n \"BIP-322 signature verification failed — ephemeral key is not attested by pinned server pubkey\",\n \"signature_verification_failed\",\n );\n }\n}\n","/**\n * VP RPC methods that require `Authorization: Bearer <token>`.\n * Protocol invariant — must be kept in sync with the VP server.\n *\n * Split into two sets by the CWT subject the VP demands:\n *\n * - {@link AUTH_GATED_METHODS} — bearer minted by\n * `auth_createDepositorToken` (Subject::VaultdJsonRpc). These run\n * through the proxy's plain JSON-RPC forward path.\n * - {@link GRPC_AUTH_GATED_METHODS} — bearer minted by\n * `auth_createDepositorTokenGrpc` (Subject::VaultdGrpc). The proxy\n * translates these into gRPC calls to vaultd's daemon gRPC server,\n * so a JSON-RPC-subject token would be rejected by\n * `GrpcAuthInterceptor`.\n *\n * @stability frozen\n *\n * @module tbv/core/clients/vault-provider/auth/gatedMethods\n */\n\nexport const AUTH_GATED_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_submitDepositorWotsKey\",\n \"vaultProvider_submitDepositorPresignatures\",\n \"vaultProvider_requestDepositorPresignTransactions\",\n]);\n\nexport const GRPC_AUTH_GATED_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_requestDepositorClaimerArtifacts\",\n]);\n","/**\n * Shared internals for the unauthenticated token-issuing JSON-RPC\n * client. The \"inner\" client is dedicated to `auth_createDepositorToken`\n * — it MUST NOT carry a `tokenProvider`, else the JSON-RPC header\n * builder would recurse into token acquisition.\n *\n * @module tbv/core/clients/vault-provider/auth/innerTokenClient\n */\n\nimport { JsonRpcClient } from \"../json-rpc-client\";\n\nconst TOKEN_RPC_TIMEOUT_MS = 60_000;\n\nexport const TOKEN_ISSUE_METHOD = \"auth_createDepositorToken\";\n/**\n * gRPC-subject sibling of {@link TOKEN_ISSUE_METHOD}. The proxy bridges\n * this call to vaultd's `VaultProviderDepositorAuthService.CreateDepositorToken`\n * so the resulting CWT is bound to `Subject::VaultdGrpc` — required to\n * pass vaultd's `GrpcAuthInterceptor` on methods the proxy translates to\n * gRPC (currently just the artifact stream).\n */\nexport const GRPC_TOKEN_ISSUE_METHOD = \"auth_createDepositorTokenGrpc\";\n\nexport function buildInnerTokenClient(\n baseUrl: string,\n headers?: Record<string, string>,\n): JsonRpcClient {\n return new JsonRpcClient({\n baseUrl,\n timeout: TOKEN_RPC_TIMEOUT_MS,\n headers,\n retryableFor: (method) =>\n method === TOKEN_ISSUE_METHOD || method === GRPC_TOKEN_ISSUE_METHOD,\n });\n}\n","/**\n * `VpTokenProvider` — caches CWT bearer tokens issued by the vault\n * provider's `auth_createDepositorToken` RPC, with lazy expiry check\n * and single-flight concurrent acquire.\n *\n * Usage:\n *\n * ```ts\n * const provider = new VpTokenProvider({\n * client,\n * peginTxid,\n * authAnchorHex,\n * pinnedServerPubkey,\n * authGatedMethods,\n * });\n * const bearer = await provider.getToken(method); // null if not gated\n * ```\n *\n * The provider implements the `BearerTokenProvider` interface expected\n * by `JsonRpcClient`. Plug directly:\n *\n * ```ts\n * const client = new JsonRpcClient({ ..., tokenProvider: provider });\n * ```\n *\n * @module tbv/core/clients/vault-provider/auth/tokenProvider\n */\n\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\nimport type { BearerTokenProvider, JsonRpcClient } from \"../json-rpc-client\";\nimport {\n GRPC_TOKEN_ISSUE_METHOD,\n TOKEN_ISSUE_METHOD,\n} from \"./innerTokenClient\";\nimport {\n type ServerIdentityResponse,\n verifyServerIdentity,\n} from \"./serverIdentity\";\n\n/**\n * Maximum reasonable `expires_at` value (seconds since epoch). Guards\n * against a bogus far-future timestamp that would lock the cache on a\n * bad token forever. Jan 1, 2100 in Unix seconds.\n */\nconst MAX_EXPIRES_AT_SECS = 4_102_444_800;\n\n/**\n * Default safety margin before `expires_at` — we treat a token as\n * expired this many seconds before its stated expiry so that in-flight\n * requests don't race the expiry boundary.\n */\nconst DEFAULT_REFRESH_SKEW_SECS = 30;\n\n/**\n * Wire response shape of `auth_createDepositorToken`.\n */\nexport interface CreateDepositorTokenResponse {\n /** Base64url-encoded COSE Sign1 CWT bearer token. */\n token: string;\n /** Unix timestamp at which the token expires. */\n expires_at: number;\n /** Server identity proof bundled with every token response. */\n server_identity: ServerIdentityResponse;\n}\n\nexport interface VpTokenProviderConfig {\n client: JsonRpcClient;\n /** Per-vault depositor-signed PegIn tx id. NOT shared across sibling vaults in a batch. */\n peginTxid: string;\n /** 64-char hex of the 32-byte OP_RETURN auth-anchor preimage. */\n authAnchorHex: string;\n /** Pinned VP pubkey from the on-chain registry; branded so indexer mirrors can't substitute. */\n pinnedServerPubkey: OnChainBtcPubkey;\n /**\n * Methods that need a JSON-RPC-subject bearer (minted via\n * `auth_createDepositorToken`). Forwarded over plain HTTP JSON-RPC by\n * the proxy. `getToken` returns `null` for any method outside this and\n * {@link grpcGatedMethods}.\n */\n authGatedMethods: ReadonlySet<string>;\n /**\n * Methods that need a gRPC-subject bearer (minted via\n * `auth_createDepositorTokenGrpc`). The proxy translates these into\n * gRPC calls to vaultd; the JSON-RPC bearer is rejected with a\n * `Subject` mismatch.\n */\n grpcGatedMethods: ReadonlySet<string>;\n /** Default {@link DEFAULT_REFRESH_SKEW_SECS}. */\n refreshSkewSecs?: number;\n /** Clock source for testability. */\n now?: () => number;\n}\n\ninterface CachedToken {\n token: string;\n expiresAt: number;\n}\n\n/**\n * Acquire, cache, and refresh VP bearer tokens.\n *\n * Implements {@link BearerTokenProvider}. Safe to pass directly into\n * `JsonRpcClient` as `tokenProvider`.\n */\nexport class VpTokenProvider implements BearerTokenProvider {\n // `client` is the only mutable field — see `setClient`. The\n // identity-bearing fields (peginTxid/authAnchorHex/pinnedServerPubkey)\n // remain readonly and are checked against re-registration in the\n // registry's `getOrCreate`.\n private client: JsonRpcClient;\n private readonly peginTxid: string;\n private readonly authAnchorHex: string;\n private readonly pinnedServerPubkey: OnChainBtcPubkey;\n private readonly authGatedMethods: ReadonlySet<string>;\n private readonly grpcGatedMethods: ReadonlySet<string>;\n private readonly refreshSkewSecs: number;\n private readonly now: () => number;\n\n /** Cached JSON-RPC-subject bearer (auth_createDepositorToken). */\n private cachedJsonRpc: CachedToken | null = null;\n private inFlightJsonRpc: Promise<CachedToken> | null = null;\n /** Cached gRPC-subject bearer (auth_createDepositorTokenGrpc). */\n private cachedGrpc: CachedToken | null = null;\n private inFlightGrpc: Promise<CachedToken> | null = null;\n\n constructor(config: VpTokenProviderConfig) {\n this.client = config.client;\n this.peginTxid = config.peginTxid;\n this.authAnchorHex = config.authAnchorHex;\n this.pinnedServerPubkey = config.pinnedServerPubkey;\n this.authGatedMethods = config.authGatedMethods;\n this.grpcGatedMethods = config.grpcGatedMethods;\n this.refreshSkewSecs = config.refreshSkewSecs ?? DEFAULT_REFRESH_SKEW_SECS;\n this.now = config.now ?? (() => Math.floor(Date.now() / 1000));\n }\n\n /**\n * Return a bearer token for `method`, or `null` if `method` is not\n * auth-gated.\n *\n * Routes by subject: `authGatedMethods` → JSON-RPC bearer (issued via\n * `auth_createDepositorToken`); `grpcGatedMethods` → gRPC bearer\n * (`auth_createDepositorTokenGrpc`). Either path acquires lazily and\n * single-flights concurrent callers; the two cache slots are\n * independent.\n *\n * Both token-issuing methods are hard-exempted from the gate — if\n * either were ever included in the gated sets (caller misconfiguration)\n * the provider would recurse into `acquireSingleFlight` from inside the\n * JSON-RPC header builder before `inFlight` is assigned, defeating the\n * single-flight guard. Returning `null` here breaks that recursion\n * deterministically.\n */\n async getToken(method: string): Promise<string | null> {\n if (method === TOKEN_ISSUE_METHOD || method === GRPC_TOKEN_ISSUE_METHOD) {\n return null;\n }\n\n if (this.grpcGatedMethods.has(method)) {\n return this.getTokenForSubject(\"grpc\");\n }\n if (this.authGatedMethods.has(method)) {\n return this.getTokenForSubject(\"jsonrpc\");\n }\n return null;\n }\n\n /**\n * Drop both cached tokens. Next `getToken` call re-acquires the slot\n * that's actually needed. Called by `JsonRpcClient` on wire\n * `auth_expired` responses; the client doesn't tell us which subject\n * expired, so we evict both to stay correct under either.\n *\n * Worst case is one extra round-trip on the slot that was still fresh,\n * which is cheaper than carrying a `Subject` argument through\n * `BearerTokenProvider`.\n */\n invalidate(): void {\n this.cachedJsonRpc = null;\n this.cachedGrpc = null;\n // Do NOT clear `inFlight*` — a concurrent acquire is still valid;\n // the invalidator is saying \"the cached token is bad\", not \"any\n // in-flight acquire is bad\". The in-flight acquire will populate\n // a fresh `cached*` on completion.\n }\n\n private async getTokenForSubject(\n subject: \"jsonrpc\" | \"grpc\",\n ): Promise<string> {\n const cached =\n subject === \"grpc\" ? this.cachedGrpc : this.cachedJsonRpc;\n if (cached && this.now() + this.refreshSkewSecs < cached.expiresAt) {\n return cached.token;\n }\n const fresh = await this.acquireSingleFlight(subject);\n return fresh.token;\n }\n\n /**\n * Swap in a different transport for subsequent token-issuing calls.\n * Used by the registry when a later caller registers the same\n * `peginTxid` against a different `baseUrl` — the cached token\n * (bound to identity, not transport) stays valid, but future\n * refreshes hit the new URL. An in-flight acquire keeps using the\n * old client (it captured the reference); next call uses the new.\n */\n setClient(client: JsonRpcClient): void {\n this.client = client;\n }\n\n private acquireSingleFlight(\n subject: \"jsonrpc\" | \"grpc\",\n ): Promise<CachedToken> {\n const existing =\n subject === \"grpc\" ? this.inFlightGrpc : this.inFlightJsonRpc;\n if (existing) return existing;\n\n const issueMethod =\n subject === \"grpc\" ? GRPC_TOKEN_ISSUE_METHOD : TOKEN_ISSUE_METHOD;\n\n const p = (async () => {\n try {\n const response = await this.client.call<\n { pegin_txid: string; auth_anchor: string },\n CreateDepositorTokenResponse\n >(issueMethod, {\n pegin_txid: this.peginTxid,\n auth_anchor: this.authAnchorHex,\n });\n\n verifyServerIdentity({\n proof: response.server_identity,\n pinnedServerPubkey: this.pinnedServerPubkey,\n now: this.now(),\n });\n\n // Validate wire payload before caching so a malformed response\n // from a compromised VP or proxy can't poison the cache with\n // unusable values (non-string token, non-integer expiry, etc.).\n if (typeof response.token !== \"string\" || response.token.length === 0) {\n throw new Error(\n `VpTokenProvider: invalid token in acquire response (expected non-empty string, got ${typeof response.token})`,\n );\n }\n const now = this.now();\n if (\n !Number.isSafeInteger(response.expires_at) ||\n response.expires_at <= now ||\n response.expires_at > MAX_EXPIRES_AT_SECS\n ) {\n throw new Error(\n `VpTokenProvider: invalid expires_at in acquire response (got ${JSON.stringify(response.expires_at)}; must be a safe integer in (${now}, ${MAX_EXPIRES_AT_SECS}])`,\n );\n }\n\n const fresh: CachedToken = {\n token: response.token,\n expiresAt: response.expires_at,\n };\n if (subject === \"grpc\") {\n this.cachedGrpc = fresh;\n } else {\n this.cachedJsonRpc = fresh;\n }\n return fresh;\n } finally {\n if (subject === \"grpc\") {\n this.inFlightGrpc = null;\n } else {\n this.inFlightJsonRpc = null;\n }\n }\n })();\n\n if (subject === \"grpc\") {\n this.inFlightGrpc = p;\n } else {\n this.inFlightJsonRpc = p;\n }\n return p;\n }\n}\n","/**\n * In-memory registry of {@link VpTokenProvider} instances keyed by\n * the per-vault depositor-signed PegIn tx hash. Module-level\n * singleton, per-tab, never persisted.\n *\n * @module tbv/core/clients/vault-provider/auth/tokenRegistry\n */\n\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\nimport type { JsonRpcClient } from \"../json-rpc-client\";\n\nimport { AUTH_GATED_METHODS, GRPC_AUTH_GATED_METHODS } from \"./gatedMethods\";\nimport { VpTokenProvider } from \"./tokenProvider\";\n\nexport interface VpTokenRegistryInput {\n client: JsonRpcClient;\n peginTxid: string;\n authAnchorHex: string;\n pinnedServerPubkey: OnChainBtcPubkey;\n /**\n * Opt into gRPC-subject auth for {@link GRPC_AUTH_GATED_METHODS}\n * (currently the artifact stream). Defaults to `false`: those methods\n * fall back into the JSON-RPC-subject set and authenticate via\n * `auth_createDepositorToken`, matching a proxy that runs with\n * `ENABLE_GRPC_ARTIFACTS` off. Set `true` only against a proxy that\n * serves `auth_createDepositorTokenGrpc`.\n */\n enableGrpcArtifactAuth?: boolean;\n}\n\ninterface RegistryEntry {\n provider: VpTokenProvider;\n authAnchorHex: string;\n pinnedServerPubkey: OnChainBtcPubkey;\n /** Resolved (defaulted) gRPC-auth gating the provider was built with. */\n enableGrpcArtifactAuth: boolean;\n}\n\nexport class VpTokenRegistry {\n private readonly entries = new Map<string, RegistryEntry>();\n\n /**\n * Return the cached `VpTokenProvider` for `peginTxid` if one exists\n * with matching `authAnchorHex`, `pinnedServerPubkey`, and\n * `enableGrpcArtifactAuth`, otherwise construct and cache a fresh\n * provider. A mismatch on any of those throws — silent overwrite would\n * mask derivation drift, VP pubkey rotation, or a caller that disagrees\n * on the auth subject (which the cached provider can't switch).\n */\n getOrCreate(input: VpTokenRegistryInput): VpTokenProvider {\n // gRPC-subject auth is opt-in. When off (default), the gRPC-gated\n // methods are folded into the JSON-RPC-subject set so they keep\n // minting their bearer via `auth_createDepositorToken` — the\n // pre-PR-#1789 behaviour, and the only path a proxy without\n // `ENABLE_GRPC_ARTIFACTS` accepts. Resolved once here so the cache-hit\n // mismatch check and the miss-path construction agree on the default.\n const useGrpcAuth = input.enableGrpcArtifactAuth ?? false;\n\n const existing = this.entries.get(input.peginTxid);\n if (existing) {\n if (existing.authAnchorHex !== input.authAnchorHex) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to authAnchorHex ${existing.authAnchorHex.slice(0, 8)}…; got ${input.authAnchorHex.slice(0, 8)}…`,\n );\n }\n if (existing.pinnedServerPubkey !== input.pinnedServerPubkey) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to pinnedServerPubkey ${existing.pinnedServerPubkey.slice(0, 8)}…; got ${input.pinnedServerPubkey.slice(0, 8)}…`,\n );\n }\n // The provider's gated-method sets are fixed at construction, so a\n // later caller asking for a different subject can't be honoured by\n // the cached instance. Fail loudly rather than silently serve the\n // wrong-subject token (a Subject-mismatch rejection at the VP).\n if (existing.enableGrpcArtifactAuth !== useGrpcAuth) {\n throw new Error(\n `VpTokenRegistry: peginTxid ${input.peginTxid} already bound to enableGrpcArtifactAuth=${existing.enableGrpcArtifactAuth}; got ${useGrpcAuth}`,\n );\n }\n // Refresh the inner transport on every reuse so a VP URL\n // change between calls doesn't leave the cached provider\n // pinned to a dead URL for token refresh.\n existing.provider.setClient(input.client);\n return existing.provider;\n }\n\n const provider = new VpTokenProvider({\n client: input.client,\n peginTxid: input.peginTxid,\n authAnchorHex: input.authAnchorHex,\n pinnedServerPubkey: input.pinnedServerPubkey,\n authGatedMethods: useGrpcAuth\n ? AUTH_GATED_METHODS\n : new Set([...AUTH_GATED_METHODS, ...GRPC_AUTH_GATED_METHODS]),\n grpcGatedMethods: useGrpcAuth ? GRPC_AUTH_GATED_METHODS : new Set(),\n });\n this.entries.set(input.peginTxid, {\n provider,\n authAnchorHex: input.authAnchorHex,\n pinnedServerPubkey: input.pinnedServerPubkey,\n enableGrpcArtifactAuth: useGrpcAuth,\n });\n return provider;\n }\n\n /** Return the cached provider, or `undefined` if none. */\n peek(peginTxid: string): VpTokenProvider | undefined {\n return this.entries.get(peginTxid)?.provider;\n }\n\n /**\n * Evict the entry for `peginTxid`. Idempotent. Called on terminal\n * paths — activation success, user-cancel, or component unmount —\n * so `authAnchorHex` doesn't outlive the deposit session.\n */\n release(peginTxid: string): void {\n this.entries.delete(peginTxid);\n }\n\n /**\n * Wipe every cached entry. Test-only escape hatch — not exposed on\n * the public {@link VpTokenRegistryPublic} singleton type.\n *\n * @internal\n */\n clear(): void {\n this.entries.clear();\n }\n\n get size(): number {\n return this.entries.size;\n }\n}\n\n/**\n * Public surface of the singleton — excludes the test-only `clear`\n * method.\n */\nexport interface VpTokenRegistryPublic {\n getOrCreate(input: VpTokenRegistryInput): VpTokenProvider;\n peek(peginTxid: string): VpTokenProvider | undefined;\n release(peginTxid: string): void;\n readonly size: number;\n}\n\nexport const vpTokenRegistry: VpTokenRegistryPublic = new VpTokenRegistry();\n","/**\n * Build a {@link VaultProviderRpcClient} that auto-attaches CWT\n * bearer tokens on auth-gated methods. Caller pre-derives both the\n * `authAnchorHex` (from the wallet) and the `pinnedServerPubkey`\n * (from the on-chain registry) and hands them in — the SDK has no\n * notion of wallets here.\n *\n * @module tbv/core/clients/vault-provider/auth/createAuthenticatedVpClient\n */\n\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\nimport {\n VaultProviderRpcClient,\n type VaultProviderRpcClientOptions,\n} from \"../api\";\n\nimport { buildInnerTokenClient } from \"./innerTokenClient\";\nimport { vpTokenRegistry } from \"./tokenRegistry\";\n\nexport interface AuthenticatedVpClientConfig {\n /** Base URL of the VP RPC endpoint (already proxied if applicable). */\n baseUrl: string;\n /** Per-vault depositor-signed PegIn tx id (registry cache key). */\n peginTxid: string;\n /** Already-derived 32-byte auth-anchor preimage (64-char hex, no `0x`). */\n authAnchorHex: string;\n /** On-chain VP pubkey, branded so it can only come from the registry reader. */\n pinnedServerPubkey: OnChainBtcPubkey;\n /**\n * Opt into gRPC-subject auth for the artifact stream. Defaults to\n * `false` (JSON-RPC bearer). Only enable against a proxy running with\n * `ENABLE_GRPC_ARTIFACTS`. Forwarded to {@link vpTokenRegistry}.\n */\n enableGrpcArtifactAuth?: boolean;\n /** Optional outer-client tunables (timeout, retries, headers, etc.). */\n options?: VaultProviderRpcClientOptions;\n}\n\nexport function createAuthenticatedVpClient(\n config: AuthenticatedVpClientConfig,\n): VaultProviderRpcClient {\n const innerTokenClient = buildInnerTokenClient(\n config.baseUrl,\n config.options?.headers,\n );\n\n const tokenProvider = vpTokenRegistry.getOrCreate({\n client: innerTokenClient,\n peginTxid: config.peginTxid,\n authAnchorHex: config.authAnchorHex,\n pinnedServerPubkey: config.pinnedServerPubkey,\n enableGrpcArtifactAuth: config.enableGrpcArtifactAuth,\n });\n\n return new VaultProviderRpcClient(config.baseUrl, {\n ...config.options,\n tokenProvider,\n });\n}\n","/**\n * Pre-populate {@link vpTokenRegistry} when the caller already has\n * both the auth-anchor preimage and the on-chain VP pubkey. Seeds\n * the cache for a `peginTxid` so a later `createAuthenticatedVpClient`\n * call reuses the cached `VpTokenProvider` instead of rebuilding it.\n *\n * @module tbv/core/clients/vault-provider/auth/primeVpAuth\n */\n\nimport type { OnChainBtcPubkey } from \"../../eth/types\";\n\nimport { buildInnerTokenClient } from \"./innerTokenClient\";\nimport { vpTokenRegistry } from \"./tokenRegistry\";\n\nexport interface PrimeVpAuthInput {\n baseUrl: string;\n peginTxid: string;\n authAnchorHex: string;\n pinnedServerPubkey: OnChainBtcPubkey;\n /** Optional headers forwarded to the inner token client (e.g. gateway auth). */\n headers?: Record<string, string>;\n /**\n * Opt into gRPC-subject auth for the artifact stream. Defaults to\n * `false`. Must match the value passed to a later\n * `createAuthenticatedVpClient` for the same `peginTxid` —\n * `VpTokenRegistry.getOrCreate` throws on a mismatch rather than\n * serve the wrong-subject token from the primed provider.\n */\n enableGrpcArtifactAuth?: boolean;\n}\n\nexport function primeVpTokenRegistry(input: PrimeVpAuthInput): void {\n vpTokenRegistry.getOrCreate({\n client: buildInnerTokenClient(input.baseUrl, input.headers),\n peginTxid: input.peginTxid,\n authAnchorHex: input.authAnchorHex,\n pinnedServerPubkey: input.pinnedServerPubkey,\n enableGrpcArtifactAuth: input.enableGrpcArtifactAuth,\n });\n}\n"],"names":["resolveProtocolAddresses","publicClient","btcVaultRegistryAddress","protocolParams","applicationRegistry","BTCVaultRegistryABI","UINT16_MAX","mapOffchainParams","result","mapTBVParams","deriveTimelockPegin","timelockAssert","ViemProtocolParamsReader","contractAddress","ProtocolParamsABI","params","validateTBVProtocolParams","validateOffchainParams","version","raw","assertValidOffchainParamsVersion","results","tbvParams","offchainParams","offchainParamsVersion","config","validatePegInConfiguration","onSkippedVersion","latestVersion","versions","_","i","contracts","v","byVersion","error","mapKeyPairs","pair","ViemVaultKeeperReader","appEntryPoint","ApplicationRegistryABI","ViemUniversalChallengerReader","OnChainBtcVaultStatus","DAEMON_STATUS_VALUES","DaemonStatus","VP_ERROR_PREVIEW_MAX_LEN","preview","value","_a","VP_VALIDATION_USER_MESSAGE","VpResponseValidationError","detail","__publicField","TXID_HEX_LEN","isNonEmptyHex","HEX_RE","isNonEmptyString","assertNonEmptyHex","field","assertNonEmptyString","assertBtcPubkey","X_ONLY_PUBKEY_HEX_LEN","COMPRESSED_PUBKEY_HEX_LEN","validatePresigningProgressFields","progress","presigning","p","validateGetPeginStatusResponse","response","r","validateRequestDepositorPresignTransactionsResponse","validateClaimerTransactions","validateDepositorGraphTransactions","validateTransactionData","tx","validateChallengeAssertConnectorData","c","validatePresignDataPerChallenger","d","validateRequestDepositorClaimerArtifactsResponse","sessionEntries","key","session","s","validateGetPegoutStatusResponse","validateClaimerPegoutStatus","validateChallengerStatus","index","assertNullableString","validateBatchGetPeginStatusResponse","validateBatchEnvelope","entry","validateBatchGetPegoutStatusResponse","rpcName","validateInnerResult","e","graph","DEFAULT_TIMEOUT_MS","VaultProviderRpcClient","baseUrl","options","JsonRpcClient","signal","attributeBatchResults","requestedTxids","requestedSet","txid","byTxid","seen","duplicate","unexpected","lower","missing","batchPollByProvider","items","getTxid","batchCall","onItem","onMissing","onDuplicate","onDuplicateBatch","onWholeBatchError","onUnexpected","batchSize","VP_BATCH_MAX_SIZE","chunk","txidToItem","txids","item","lowerTxid","attribution","duplicateTxids","envelope","BIP322_TAG","TAPTWEAK_TAG","X_ONLY_PUBKEY_SIZE","SCHNORR_SIG_SIZE","taggedHash","tag","data","tagBytes","tagHash","sha256","preimage","tweakXOnlyKey","xOnly","tweak","tweaked","ecc","verifyBip322Simple","messageBytes","xOnlyPubkey","signature","messageHash","p2tr","payments","Buffer","scriptPubKey","ZERO_SATS","toSpend","Transaction","scriptSig","toSign","toSpendTxid","sighash","tweakedXOnly","cborHead","major","arg","out","concat","parts","total","offset","encodeBytesAsArrayOfU8","bytes","b","encodeServerIdentityPayload","domain","ephemeralPubkeyCompressed","expiresAt","arrayHeader","domainBytes","pubkeyBytes","expiresAtBytes","SERVER_IDENTITY_DOMAIN","DEFAULT_MAX_PROOF_LIFETIME_SECS","ServerIdentityError","message","reason","hexToBytes","hex","verifyServerIdentity","input","proof","pinnedServerPubkey","now","maxLifetimeSecs","pinned","stripHexPrefix","actual","eph","prefix","ephBytes","sig","SCHNORR_SIG_HEX_LEN","payload","AUTH_GATED_METHODS","GRPC_AUTH_GATED_METHODS","TOKEN_RPC_TIMEOUT_MS","TOKEN_ISSUE_METHOD","GRPC_TOKEN_ISSUE_METHOD","buildInnerTokenClient","headers","method","MAX_EXPIRES_AT_SECS","DEFAULT_REFRESH_SKEW_SECS","VpTokenProvider","subject","cached","client","existing","issueMethod","fresh","VpTokenRegistry","useGrpcAuth","provider","peginTxid","vpTokenRegistry","createAuthenticatedVpClient","innerTokenClient","tokenProvider","primeVpTokenRegistry"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const m=require("@babylonlabs-io/babylon-tbv-rust-wasm"),I=require("./fundPeginTransaction-DuMwnytD.cjs"),l=require("buffer"),w=require("bitcoinjs-lib"),c=require("./bitcoin-CHfKAhcI.cjs"),z=require("@bitcoin-js/tiny-secp256k1-asmjs");function Y(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const D=Y(z);async function G(e,t){const r=t.pegInAmounts.length;if(e.htlcValues.length!==r)throw new Error(`WASM Pre-PegIn returned ${e.htlcValues.length} HTLC value(s), expected ${r} (one per requested deposit).`);if(e.peginAmounts.length!==r||e.htlcScriptPubKeys.length!==r||e.htlcAddresses.length!==r)throw new Error(`WASM Pre-PegIn returned mismatched array lengths (htlcValues=${e.htlcValues.length}, peginAmounts=${e.peginAmounts.length}, htlcScriptPubKeys=${e.htlcScriptPubKeys.length}, htlcAddresses=${e.htlcAddresses.length}); expected ${r} each.`);if(e.depositorClaimValue<=0n)throw new Error(`WASM Pre-PegIn returned non-positive depositorClaimValue ${e.depositorClaimValue}; expected > 0.`);const n=await m.computeMinClaimValue(t.numLocalChallengers,t.universalChallengerPubkeys.length,t.councilQuorum,t.councilSize,t.feeRate);if(e.depositorClaimValue!==n)throw new Error(`WASM Pre-PegIn depositorClaimValue ${e.depositorClaimValue} does not match the independently computed minimum claim value ${n} (numLocalChallengers=${t.numLocalChallengers}, numUniversalChallengers=${t.universalChallengerPubkeys.length}, councilQuorum=${t.councilQuorum}, councilSize=${t.councilSize}, feeRate=${t.feeRate}).`);const o=t.minPeginFeeRate*I.MAX_REASONABLE_PEGIN_VBYTES;for(let i=0;i<r;i++){const u=t.pegInAmounts[i],s=e.peginAmounts[i],a=e.htlcValues[i];if(s!==u)throw new Error(`WASM Pre-PegIn peginAmount[${i}] ${s} does not match the requested amount ${u}; refusing to build a tx whose recorded amount differs from the depositor's request.`);if(s<=0n)throw new Error(`WASM Pre-PegIn peginAmount[${i}] is non-positive (${s}); expected > 0.`);if(a<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${i}] is non-positive (${a}); expected > 0.`);const h=a-s-e.depositorClaimValue;if(h<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${i}] ${a} does not strictly cover peginAmount ${s} + depositorClaimValue ${e.depositorClaimValue} + a PegIn fee (implied fee ${h}).`);if(h>o)throw new Error(`WASM Pre-PegIn implied PegIn fee for HTLC[${i}] (${h} sat) exceeds the plausibility cap ${o} sat (minPeginFeeRate=${t.minPeginFeeRate} × ${I.MAX_REASONABLE_PEGIN_VBYTES} vbytes); htlcValue ${a} appears grossly inflated.`)}}function Q(e,t,r){if(e.length<t.length)throw new Error(`Encoded Pre-PegIn tx has ${e.length} output(s), fewer than the ${t.length} HTLC output(s) the cross-check validated.`);for(let n=0;n<t.length;n++){const o=BigInt(e[n].value);if(o!==t[n])throw new Error(`Encoded Pre-PegIn HTLC output[${n}] value ${o} does not match the cross-checked htlcValue ${t[n]}; the funded/signed tx would not pay the validated amount.`);const i=e[n].script.toString("hex").toLowerCase(),u=r[n].toLowerCase();if(i!==u)throw new Error(`Encoded Pre-PegIn HTLC output[${n}] scriptPubKey ${i} does not match the cross-checked htlcScriptPubKey ${u}.`)}}const B=64,Z=/^[0-9a-fA-F]+$/;async function j(e){const t=H(e.authAnchorHash),r=await m.createPrePeginTransaction({depositorPubkey:e.depositorPubkey,vaultProviderPubkey:e.vaultProviderPubkey,vaultKeeperPubkeys:e.vaultKeeperPubkeys,universalChallengerPubkeys:e.universalChallengerPubkeys,hashlocks:[...e.hashlocks],timelockRefund:e.timelockRefund,pegInAmounts:[...e.pegInAmounts],feeRate:e.feeRate,minPeginFeeRate:e.minPeginFeeRate,numLocalChallengers:e.numLocalChallengers,councilQuorum:e.councilQuorum,councilSize:e.councilSize,network:e.network,authAnchorHash:t});await G(r,e);const n=I.parseUnfundedWasmTransaction(r.txHex);Q(n.outputs,r.htlcValues,r.htlcScriptPubKeys);const o=n.outputs.reduce((u,s)=>u+BigInt(s.value),0n),i=t!==void 0?r.htlcValues.length:null;return{psbtHex:r.txHex,totalOutputValue:o,htlcValues:r.htlcValues,htlcScriptPubKeys:r.htlcScriptPubKeys,htlcAddresses:r.htlcAddresses,peginAmounts:r.peginAmounts,depositorClaimValue:r.depositorClaimValue,authAnchorVout:i}}function H(e){if(e===void 0)return;const t=e.startsWith("0x")||e.startsWith("0X")?e.slice(2):e;if(t.length!==B||!Z.test(t))throw new Error(`authAnchorHash must be 32-byte hex (${B} chars, no 0x prefix); got length ${t.length}`);return t.toLowerCase()}async function J(e){const t=await m.buildPeginTxFromPrePegin({depositorPubkey:e.prePeginParams.depositorPubkey,vaultProviderPubkey:e.prePeginParams.vaultProviderPubkey,vaultKeeperPubkeys:e.prePeginParams.vaultKeeperPubkeys,universalChallengerPubkeys:e.prePeginParams.universalChallengerPubkeys,hashlocks:[...e.prePeginParams.hashlocks],timelockRefund:e.prePeginParams.timelockRefund,pegInAmounts:[...e.prePeginParams.pegInAmounts],feeRate:e.prePeginParams.feeRate,minPeginFeeRate:e.prePeginParams.minPeginFeeRate,numLocalChallengers:e.prePeginParams.numLocalChallengers,councilQuorum:e.prePeginParams.councilQuorum,councilSize:e.prePeginParams.councilSize,network:e.prePeginParams.network,authAnchorHash:H(e.prePeginParams.authAnchorHash)},e.timelockPegin,e.fundedPrePeginTxHex,e.htlcVout);return{txHex:t.txHex,txid:t.txid,vaultScriptPubKey:t.vaultScriptPubKey,vaultValue:t.vaultValue}}async function W(e){const t=await m.createPayoutConnector({depositor:e.depositor,vaultProvider:e.vaultProvider,vaultKeepers:e.vaultKeepers,universalChallengers:e.universalChallengers,timelockPegin:e.timelockPegin},e.network);return{payoutScript:t.payoutScript,taprootScriptHash:t.taprootScriptHash,scriptPubKey:t.scriptPubKey,address:t.address,payoutControlBlock:t.payoutControlBlock}}const ee=2,A=0,_=0,V=546,te=3,R=2,k=1e4,L=3,N=10,q=100;async function re(e){const t=c.stripHexPrefix(e.payoutTxHex),r=c.stripHexPrefix(e.peginTxHex),n=c.stripHexPrefix(e.assertTxHex),o=await W({depositor:e.depositorBtcPubkey,vaultProvider:e.vaultProviderBtcPubkey,vaultKeepers:e.vaultKeeperBtcPubkeys,universalChallengers:e.universalChallengerBtcPubkeys,timelockPegin:e.timelockPegin,network:e.network}),i=c.hexToUint8Array(o.payoutScript),u=c.hexToUint8Array(o.payoutControlBlock),s=w.Transaction.fromHex(t),a=w.Transaction.fromHex(r),h=w.Transaction.fromHex(n),f=new w.Psbt;if(f.setVersion(s.version),f.setLocktime(s.locktime),s.ins.length!==2)throw new Error(`Payout transaction must have exactly 2 inputs, got ${s.ins.length}`);const P=s.ins[0],x=s.ins[1],d=c.uint8ArrayToHex(new Uint8Array(P.hash).slice().reverse()),y=a.getId();if(d!==y||P.index!==A)throw new Error(`Input 0 must spend PegIn:${A}. Expected ${y}:${A}, got ${d}:${P.index}`);const $=c.uint8ArrayToHex(new Uint8Array(x.hash).slice().reverse()),p=h.getId();if($!==p||x.index!==_)throw new Error(`Input 1 must spend Assert:${_}. Expected ${p}:${_}, got ${$}:${x.index}`);const g=a.outs[P.index];if(!g)throw new Error(`Previous output not found for input 0 (txid: ${d}, index: ${P.index})`);const v=h.outs[x.index];if(!v)throw new Error(`Previous output not found for input 1 (txid: ${$}, index: ${x.index})`);ne({payoutTx:s,peginValueSats:g.value,claimerBtcPubkey:e.claimerBtcPubkey,vaultProviderBtcPubkey:e.vaultProviderBtcPubkey,depositorBtcPubkey:e.depositorBtcPubkey,vaultKeeperBtcPubkeys:e.vaultKeeperBtcPubkeys,registeredPayoutScriptPubKey:e.registeredPayoutScriptPubKey,commissionBps:e.commissionBps});const E=g.value+v.value;let b=0;for(const T of s.outs)b+=T.value;if(b>E)throw new Error(`Payout outputs (${b} sats) exceed inputs (${E} sats); invalid transaction.`);const O=E-b,U=Math.floor(E*N/q);if(O>U)throw new Error(`Payout implicit fee ${O} sats exceeds the safety cap of ${U} sats (${N}/${q} of inputs=${E}); refusing to sign payout.`);f.addInput({hash:P.hash,index:P.index,sequence:P.sequence,witnessUtxo:{script:g.script,value:g.value},tapLeafScript:[{leafVersion:c.TAPSCRIPT_LEAF_VERSION,script:l.Buffer.from(i),controlBlock:l.Buffer.from(u)}],tapInternalKey:l.Buffer.from(m.tapInternalPubkey)}),f.addInput({hash:x.hash,index:x.index,sequence:x.sequence,witnessUtxo:{script:v.script,value:v.value}});for(const T of s.outs)f.addOutput({script:T.script,value:T.value});return{psbtHex:f.toHex()}}function ne(e){const{payoutTx:t,peginValueSats:r,claimerBtcPubkey:n,vaultProviderBtcPubkey:o,depositorBtcPubkey:i,vaultKeeperBtcPubkeys:u,registeredPayoutScriptPubKey:s,commissionBps:a}=e;if(!c.isValidHex(s))throw new Error("Invalid registeredPayoutScriptPubKey: not valid hex");const h=c.stripHexPrefix(n).toLowerCase(),f=c.stripHexPrefix(o).toLowerCase(),P=c.stripHexPrefix(i).toLowerCase(),x=u.map(v=>c.stripHexPrefix(v).toLowerCase());let d,y,$;if(h===f)d="vp-claimer",y=te,$=c.stripHexPrefix(s);else if(h===P)d="depositor-as-claimer",y=R,$=c.stripHexPrefix(s);else if(x.includes(h))d="vk-claimer",y=R,$=c.stripHexPrefix(c.deriveBip86ScriptPubKeyHex(h));else throw new Error(`Unknown claimer pubkey ${h}: not VP, depositor, or a registered vault keeper`);if(t.outs.length!==y)throw new Error(`Payout transaction has ${t.outs.length} output(s), expected exactly ${y} for role ${d}.`);const p=l.Buffer.from($,"hex");if(!t.outs[0].script.equals(p))throw new Error(`Payout transaction output 0 does not pay the expected scriptPubKey for role ${d}`);const g=y-1;if(t.outs[g].value!==V)throw new Error(`Payout CPFP anchor (out ${g}) value ${t.outs[g].value} sats must equal ${V} sats`);if(d==="vp-claimer"){if(!Number.isInteger(a)||a<0||a>=k)throw new Error(`commissionBps must be an integer in [0, ${k}), got ${a}`);const v=Math.floor(r*a/k);if(t.outs[1].value>v)throw new Error(`Payout VP commission (out 1) value ${t.outs[1].value} sats exceeds cap ${v} sats (${a} bps of peginValue=${r})`)}}function oe(e,t,r=0){const n=w.Psbt.fromHex(e);if(r>=n.data.inputs.length)throw new Error(`Input index ${r} out of range (${n.data.inputs.length} inputs)`);const o=n.data.inputs[r];if(o.tapScriptSig&&o.tapScriptSig.length>0){const i=c.hexToUint8Array(t);for(const u of o.tapScriptSig)if(u.pubkey.equals(l.Buffer.from(i)))return M(u.signature,r);throw new Error(`No signature found for depositor pubkey: ${t} at input ${r}`)}if(o.finalScriptWitness&&o.finalScriptWitness.length>0){const i=ie(o.finalScriptWitness);if(i.length!==L)throw new Error(`Unexpected finalized witness stack size at input ${r}: expected ${L} items (signature, script, controlBlock), got ${i.length}`);return M(i[0],r)}throw new Error(`No tapScriptSig or finalScriptWitness found in signed PSBT at input ${r}`)}function M(e,t){if(e.length===64)return c.uint8ArrayToHex(new Uint8Array(e));throw e.length===65?new Error(`Unexpected sighash byte 0x${e[64].toString(16).padStart(2,"0")} at input ${t}. Expected implicit SIGHASH_DEFAULT as a 64-byte signature.`):new Error(`Unexpected signature length at input ${t}: ${e.length}`)}function ie(e){const t=[];let r=0;const n=u=>{if(r+u>e.length)throw new Error(`Malformed witness data: need ${u} byte(s) at offset ${r}, only ${e.length-r} remaining`)},o=()=>{n(1);const u=e[r++];if(u<253)return u;if(u===253){n(2);const s=(e[r]|e[r+1]<<8)>>>0;return r+=2,s}if(u===254){n(4);const s=(e[r]|e[r+1]<<8|e[r+2]<<16|e[r+3]<<24)>>>0;return r+=4,s}throw new Error(`Malformed witness data: 8-byte varint (0xff) not supported at offset ${r-1}`)},i=o();for(let u=0;u<i;u++){const s=o();n(s),t.push(l.Buffer.from(e.subarray(r,r+s))),r+=s}if(r!==e.length)throw new Error(`Malformed witness data: ${e.length-r} trailing byte(s) after parsing ${i} item(s)`);return t}class S extends Error{constructor(t){super(`Wallet returned a PSBT for a different transaction: ${t}`),this.name="PsbtSubstitutionError"}}function K(e,t){try{return w.Psbt.fromHex(t)}catch(r){const n=r instanceof Error?r.message:String(r);throw new Error(`Failed to parse ${e} PSBT: ${n}`)}}const se=8;function C(e){return`${e.toString("hex").slice(0,se)}…`}function F(e){const t=l.Buffer.from(e).reverse();return C(t)}function ue(e){const t=K("requested",e.requestedPsbtHex),r=K("returned",e.returnedPsbtHex);if(t.version!==r.version)throw new S(`tx version differs (requested=${t.version}, returned=${r.version})`);if(t.locktime!==r.locktime)throw new S(`tx locktime differs (requested=${t.locktime}, returned=${r.locktime})`);if(t.txInputs.length!==r.txInputs.length)throw new S(`input count differs (requested=${t.txInputs.length}, returned=${r.txInputs.length})`);if(t.txOutputs.length!==r.txOutputs.length)throw new S(`output count differs (requested=${t.txOutputs.length}, returned=${r.txOutputs.length})`);for(let n=0;n<t.txInputs.length;n++){const o=t.txInputs[n],i=r.txInputs[n];if(!o.hash.equals(i.hash))throw new S(`input ${n} prevout txid differs (requested=${F(o.hash)}, returned=${F(i.hash)})`);if(o.index!==i.index)throw new S(`input ${n} prevout vout differs (requested=${o.index}, returned=${i.index})`);if(o.sequence!==i.sequence)throw new S(`input ${n} sequence differs (requested=${o.sequence}, returned=${i.sequence})`)}for(let n=0;n<t.txOutputs.length;n++){const o=t.txOutputs[n],i=r.txOutputs[n];if(!o.script.equals(i.script))throw new S(`output ${n} scriptPubKey differs (requested=${C(o.script)}, returned=${C(i.script)})`);if(o.value!==i.value)throw new S(`output ${n} value differs (requested=${o.value}, returned=${i.value})`)}}const X=253,ce=254,ae=65535,le=4294967295;function he(e){if(e<X)return l.Buffer.from([e]);if(e<=ae){const t=l.Buffer.alloc(2);return t.writeUInt16LE(e),l.Buffer.concat([l.Buffer.from([X]),t])}if(e<=le){const t=l.Buffer.alloc(4);return t.writeUInt32LE(e),l.Buffer.concat([l.Buffer.from([ce]),t])}throw new Error(`Script too large to encode as CompactSize: ${e} bytes`)}const de="TapLeaf";function pe(e,t){const r=l.Buffer.concat([l.Buffer.from([e]),he(t.length),l.Buffer.from(t)]);return w.crypto.taggedHash(de,r)}function fe(e){const{requestedPsbtHex:t,signatureHex:r,signerXOnlyPubkeyHex:n,inputIndex:o}=e,i=c.stripHexPrefix(r);if(i.length!==c.SCHNORR_SIG_HEX_LEN)throw new Error(`Schnorr signature for input ${o} must be ${c.SCHNORR_SIG_HEX_LEN} hex chars (64 bytes), got ${i.length}.`);const u=c.stripHexPrefix(n);if(u.length!==c.X_ONLY_PUBKEY_HEX_LEN)throw new Error(`Signer x-only pubkey for input ${o} must be ${c.X_ONLY_PUBKEY_HEX_LEN} hex chars (32 bytes), got ${u.length}.`);const s=w.Psbt.fromHex(t);if(o<0||o>=s.data.inputs.length)throw new Error(`Input index ${o} out of range (${s.data.inputs.length} inputs).`);const a=[],h=[];for(let p=0;p<s.data.inputs.length;p++){const g=s.data.inputs[p].witnessUtxo;if(!g)throw new Error(`Cannot verify signature: input ${p} of the requested PSBT has no witnessUtxo (required to recompute the Taproot sighash).`);a.push(g.script),h.push(g.value)}const f=s.data.inputs[o].tapLeafScript;if(!f||f.length!==1)throw new Error(`Cannot verify signature: input ${o} of the requested PSBT must have exactly one tapLeafScript, got ${(f==null?void 0:f.length)??0}.`);const P=f[0];if(P.leafVersion!==c.TAPSCRIPT_LEAF_VERSION)throw new Error(`Cannot verify signature: input ${o} tapLeafScript has leaf version 0x${P.leafVersion.toString(16)}, expected 0x${c.TAPSCRIPT_LEAF_VERSION.toString(16)}.`);const x=pe(P.leafVersion,P.script),d=new w.Transaction;d.version=s.version,d.locktime=s.locktime;for(const p of s.txInputs)d.addInput(p.hash,p.index,p.sequence);for(const p of s.txOutputs)d.addOutput(p.script,p.value);const y=d.hashForWitnessV1(o,a,h,w.Transaction.SIGHASH_DEFAULT,x);if(!D.verifySchnorr(y,c.hexToUint8Array(u),c.hexToUint8Array(i)))throw new Error(`Schnorr signature for input ${o} (signer ${u}) does not verify against the expected Taproot script-path sighash. The wallet may have signed with the tweaked key, signed a different transaction, or returned an invalid signature.`)}exports.ASSERT_PAYOUT_OUTPUT_INDEX=_;exports.DEPOSITOR_PAYOUT_INPUT_COUNT=ee;exports.PEGIN_VAULT_OUTPUT_INDEX=A;exports.PsbtSubstitutionError=S;exports.assertPsbtUnsignedTxMatches=ue;exports.assertScriptPathSchnorrSignature=fe;exports.buildPayoutPsbt=re;exports.buildPeginTxFromFundedPrePegin=J;exports.buildPrePeginPsbt=j;exports.createPayoutScript=W;exports.extractPayoutSignature=oe;exports.normalizeAuthAnchorHash=H;
|
|
2
|
-
//# sourceMappingURL=verifyScriptPathSchnorrSignature-D43cncKJ.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"verifyScriptPathSchnorrSignature-D43cncKJ.cjs","sources":["../src/tbv/core/primitives/psbt/assertWasmPeginSizing.ts","../src/tbv/core/primitives/psbt/pegin.ts","../src/tbv/core/primitives/scripts/payout.ts","../src/tbv/core/primitives/psbt/constants.ts","../src/tbv/core/primitives/psbt/payout.ts","../src/tbv/core/primitives/psbt/assertPsbtUnsignedTxMatches.ts","../src/tbv/core/primitives/psbt/verifyScriptPathSchnorrSignature.ts"],"sourcesContent":["/**\n * Cross-check the values WASM returns from `createPrePeginTransaction`\n * against independently-known expectations before they feed a signed\n * Bitcoin transaction or the on-chain PegIn registration.\n *\n * CLAUDE.md critical path #1: the Rust/WASM layer computes\n * `htlcValue = peginAmount + depositorClaimValue + minPeginFee` internally\n * and JS receives the outputs with no runtime validation. A doctored or\n * buggy binary that returns a different `peginAmount`, an out-of-formula\n * `htlcValue`, or a wrong `depositorClaimValue` would otherwise be committed\n * verbatim — taxing the depositor or starving the downstream tx graph of fees.\n *\n * @module primitives/psbt/assertWasmPeginSizing\n */\n\nimport {\n computeMinClaimValue,\n type PrePeginResult,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\nimport { MAX_REASONABLE_PEGIN_VBYTES } from \"../../utils/fee/constants\";\nimport type { ParsedOutput } from \"../../utils/transaction/fundPeginTransaction\";\n\nimport type { PrePeginParams } from \"./pegin\";\n\n/**\n * Assert the WASM Pre-PegIn sizing result is internally consistent and\n * matches what the caller requested.\n *\n * The strong checks are pure-JS and fully independent of the WASM binary:\n * the per-HTLC `peginAmount` must equal the requested amount, array lengths\n * must match, and every value must be positive. The implied PegIn fee\n * (`htlcValue - peginAmount - depositorClaimValue`) is bounded by\n * plausibility rather than recomputed exactly, because JS↔Rust vbyte parity\n * is not a cross-stack guarantee (see {@link MAX_REASONABLE_PEGIN_VBYTES}).\n * The `depositorClaimValue` cross-check against `computeMinClaimValue` is a\n * WASM-vs-WASM consistency check (a different entry point), not an\n * independent one.\n *\n * @param result - The result returned by `createPrePeginTransaction`.\n * @param params - The parameters that were passed to build it.\n * @throws If any value is missing, non-positive, mismatched against the\n * request, or outside the protocol formula / plausibility bounds.\n */\nexport async function assertWasmPeginSizing(\n result: PrePeginResult,\n params: PrePeginParams,\n): Promise<void> {\n const expectedCount = params.pegInAmounts.length;\n\n // Count: every parallel array must carry exactly one entry per requested\n // deposit, otherwise the per-HTLC indexing downstream is meaningless.\n if (result.htlcValues.length !== expectedCount) {\n throw new Error(\n `WASM Pre-PegIn returned ${result.htlcValues.length} HTLC value(s), ` +\n `expected ${expectedCount} (one per requested deposit).`,\n );\n }\n if (\n result.peginAmounts.length !== expectedCount ||\n result.htlcScriptPubKeys.length !== expectedCount ||\n result.htlcAddresses.length !== expectedCount\n ) {\n throw new Error(\n `WASM Pre-PegIn returned mismatched array lengths ` +\n `(htlcValues=${result.htlcValues.length}, ` +\n `peginAmounts=${result.peginAmounts.length}, ` +\n `htlcScriptPubKeys=${result.htlcScriptPubKeys.length}, ` +\n `htlcAddresses=${result.htlcAddresses.length}); ` +\n `expected ${expectedCount} each.`,\n );\n }\n\n // depositorClaimValue: positivity + WASM-vs-WASM consistency. Sized by the\n // tx-graph `feeRate` (see PrePeginParams.feeRate), so the standalone\n // `computeMinClaimValue` must reproduce the constructor's internal value.\n if (result.depositorClaimValue <= 0n) {\n throw new Error(\n `WASM Pre-PegIn returned non-positive depositorClaimValue ` +\n `${result.depositorClaimValue}; expected > 0.`,\n );\n }\n const expectedClaimValue = await computeMinClaimValue(\n params.numLocalChallengers,\n params.universalChallengerPubkeys.length,\n params.councilQuorum,\n params.councilSize,\n params.feeRate,\n );\n if (result.depositorClaimValue !== expectedClaimValue) {\n throw new Error(\n `WASM Pre-PegIn depositorClaimValue ${result.depositorClaimValue} does ` +\n `not match the independently computed minimum claim value ` +\n `${expectedClaimValue} (numLocalChallengers=${params.numLocalChallengers}, ` +\n `numUniversalChallengers=${params.universalChallengerPubkeys.length}, ` +\n `councilQuorum=${params.councilQuorum}, councilSize=${params.councilSize}, ` +\n `feeRate=${params.feeRate}).`,\n );\n }\n\n const maxImpliedFee = params.minPeginFeeRate * MAX_REASONABLE_PEGIN_VBYTES;\n\n for (let i = 0; i < expectedCount; i++) {\n const requested = params.pegInAmounts[i];\n const peginAmount = result.peginAmounts[i];\n const htlcValue = result.htlcValues[i];\n\n // Amount echo (strongest, fully independent): the recorded pegin amount\n // must equal exactly what the caller requested. A mismatch is the\n // WASM-tax attack — the contract would record a doctored amount while the\n // depositor's wallet funds the original, and the difference is a\n // WASM-controlled tax.\n if (peginAmount !== requested) {\n throw new Error(\n `WASM Pre-PegIn peginAmount[${i}] ${peginAmount} does not match the ` +\n `requested amount ${requested}; refusing to build a tx whose ` +\n `recorded amount differs from the depositor's request.`,\n );\n }\n if (peginAmount <= 0n) {\n throw new Error(\n `WASM Pre-PegIn peginAmount[${i}] is non-positive (${peginAmount}); ` +\n `expected > 0.`,\n );\n }\n if (htlcValue <= 0n) {\n throw new Error(\n `WASM Pre-PegIn htlcValue[${i}] is non-positive (${htlcValue}); ` +\n `expected > 0.`,\n );\n }\n\n // Formula: htlcValue = peginAmount + depositorClaimValue + minPeginFee.\n // The implied fee must be strictly positive (the HTLC must reserve a real\n // PegIn fee) and within the plausibility bound.\n const impliedFee = htlcValue - peginAmount - result.depositorClaimValue;\n if (impliedFee <= 0n) {\n throw new Error(\n `WASM Pre-PegIn htlcValue[${i}] ${htlcValue} does not strictly cover ` +\n `peginAmount ${peginAmount} + depositorClaimValue ` +\n `${result.depositorClaimValue} + a PegIn fee (implied fee ` +\n `${impliedFee}).`,\n );\n }\n if (impliedFee > maxImpliedFee) {\n throw new Error(\n `WASM Pre-PegIn implied PegIn fee for HTLC[${i}] (${impliedFee} sat) ` +\n `exceeds the plausibility cap ${maxImpliedFee} sat ` +\n `(minPeginFeeRate=${params.minPeginFeeRate} × ` +\n `${MAX_REASONABLE_PEGIN_VBYTES} vbytes); htlcValue ${htlcValue} ` +\n `appears grossly inflated.`,\n );\n }\n }\n}\n\n/**\n * Bind the validated metadata to the bytes that actually get funded and\n * signed.\n *\n * `assertWasmPeginSizing` proves the WASM *metadata* (`htlcValues`,\n * `htlcScriptPubKeys`) matches the request and the protocol formula — but the\n * transaction the depositor funds and signs is `result.txHex`. If the encoded\n * tx carried a different HTLC output value or script than the metadata, the\n * depositor would fund a transaction whose real outputs differ from the values\n * that were cross-checked. This closes that final link: the encoded HTLC\n * outputs must equal the validated metadata.\n *\n * The WASM lays out HTLC outputs first (vouts `0..N-1`), then the optional\n * auth-anchor OP_RETURN, then the CPFP anchor — so we only compare the first\n * `htlcValues.length` outputs.\n *\n * @param outputs - Outputs parsed from the unfunded Pre-PegIn tx hex.\n * @param htlcValues - The (already value-validated) per-HTLC values.\n * @param htlcScriptPubKeys - The per-HTLC scriptPubKeys (hex).\n * @throws If the encoded outputs are too few, or any HTLC output's value or\n * scriptPubKey disagrees with the validated metadata.\n */\nexport function assertEncodedHtlcOutputsMatch(\n outputs: readonly ParsedOutput[],\n htlcValues: readonly bigint[],\n htlcScriptPubKeys: readonly string[],\n): void {\n if (outputs.length < htlcValues.length) {\n throw new Error(\n `Encoded Pre-PegIn tx has ${outputs.length} output(s), fewer than the ` +\n `${htlcValues.length} HTLC output(s) the cross-check validated.`,\n );\n }\n\n for (let i = 0; i < htlcValues.length; i++) {\n const encodedValue = BigInt(outputs[i].value);\n if (encodedValue !== htlcValues[i]) {\n throw new Error(\n `Encoded Pre-PegIn HTLC output[${i}] value ${encodedValue} does not ` +\n `match the cross-checked htlcValue ${htlcValues[i]}; the funded/signed ` +\n `tx would not pay the validated amount.`,\n );\n }\n\n const encodedScript = outputs[i].script.toString(\"hex\").toLowerCase();\n const expectedScript = htlcScriptPubKeys[i].toLowerCase();\n if (encodedScript !== expectedScript) {\n throw new Error(\n `Encoded Pre-PegIn HTLC output[${i}] scriptPubKey ${encodedScript} does ` +\n `not match the cross-checked htlcScriptPubKey ${expectedScript}.`,\n );\n }\n }\n}\n","/**\n * Pre-PegIn PSBT Builder Primitive\n *\n * This module provides pure functions for building unfunded Pre-PegIn transactions\n * and deriving PegIn transactions from them, using the WASM implementation from\n * @babylonlabs-io/babylon-tbv-rust-wasm.\n *\n * Pre-PegIn Flow:\n * 1. buildPrePeginPsbt() — creates unfunded Pre-PegIn tx (HTLC output)\n * 2. [caller funds Pre-PegIn tx and computes txid]\n * 3. buildPeginTxFromFundedPrePegin() — derives PegIn tx spending the HTLC\n * 4. buildPeginInputPsbt() — PSBT for depositor to sign PegIn HTLC leaf 0 input\n *\n * @module primitives/psbt/pegin\n */\n\nimport {\n buildPeginTxFromPrePegin,\n createPrePeginTransaction,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\nimport { parseUnfundedWasmTransaction } from \"../../utils/transaction/fundPeginTransaction\";\n\nimport {\n assertEncodedHtlcOutputsMatch,\n assertWasmPeginSizing,\n} from \"./assertWasmPeginSizing\";\n\n/**\n * Parameters for building an unfunded Pre-PegIn PSBT\n */\nexport interface PrePeginParams {\n /** Depositor's BTC public key (x-only, 64-char hex without 0x prefix) */\n depositorPubkey: string;\n /** Vault provider's BTC public key (x-only, 64-char hex) */\n vaultProviderPubkey: string;\n /** Array of vault keeper BTC public keys (x-only, 64-char hex) */\n vaultKeeperPubkeys: string[];\n /** Array of universal challenger BTC public keys (x-only, 64-char hex) */\n universalChallengerPubkeys: string[];\n /** SHA256 hash commitment(s) (64 hex chars = 32 bytes each) */\n hashlocks: readonly string[];\n /** CSV timelock in blocks for the HTLC refund path */\n timelockRefund: number;\n /** Amounts to peg in (satoshis), one per deposit */\n pegInAmounts: readonly bigint[];\n /** TX-graph fee rate in sat/vB from contract offchain params; sizes the depositor claim value */\n feeRate: bigint;\n /** Minimum PegIn fee rate in sat/vB from contract offchain params; sizes the PegIn tx fee */\n minPeginFeeRate: bigint;\n /** Number of local challengers (from contract params) */\n numLocalChallengers: number;\n /** M in M-of-N council multisig (from contract params) */\n councilQuorum: number;\n /** N in M-of-N council multisig (from contract params) */\n councilSize: number;\n /** Bitcoin network */\n network: Network;\n /**\n * Optional 32-byte `SHA256(auth_anchor)` commitment (64-char hex, no\n * `0x` prefix). If provided, the Pre-PegIn tx will include an\n * `OP_RETURN <PUSH32 authAnchorHash>` output at vout =\n * `hashlocks.length`, binding the depositor's bearer-token\n * `auth_anchor` preimage to this Pre-PegIn.\n */\n authAnchorHash?: string;\n}\n\n/**\n * Byte length of an `auth_anchor_hash` commitment when encoded as a\n * lowercase hex string (32 bytes → 64 hex chars).\n */\nconst AUTH_ANCHOR_HASH_HEX_LEN = 64;\n\nconst HEX_PATTERN = /^[0-9a-fA-F]+$/;\n\n/**\n * Result of building an unfunded Pre-PegIn transaction\n */\nexport interface PrePeginPsbtResult {\n /**\n * Unfunded transaction hex (no inputs, HTLC outputs + optional\n * auth-anchor OP_RETURN + CPFP anchor).\n *\n * The caller is responsible for:\n * - Selecting UTXOs covering totalOutputValue + network fees\n * - Funding the transaction (add inputs and change output)\n * - Calling buildPeginTxFromFundedPrePegin() with the funded tx hex\n */\n psbtHex: string;\n /** Sum of all unfunded outputs — use this for UTXO selection */\n totalOutputValue: bigint;\n /** HTLC output values in satoshis, one per deposit (each includes peginAmount + depositorClaimValue + minPeginFee) */\n htlcValues: readonly bigint[];\n /** HTLC output scriptPubKeys (hex encoded), one per deposit */\n htlcScriptPubKeys: readonly string[];\n /** HTLC Taproot addresses, one per deposit */\n htlcAddresses: readonly string[];\n /** Pegin amounts in satoshis, one per deposit */\n peginAmounts: readonly bigint[];\n /** Depositor claim value computed by WASM from contract parameters */\n depositorClaimValue: bigint;\n /**\n * Vout index of the auth-anchor `OP_RETURN` output if one was\n * included (i.e. `authAnchorHash` was provided), or `null` if not.\n * Always equals `htlcValues.length` when present.\n */\n authAnchorVout: number | null;\n}\n\n/**\n * Parameters for building the PegIn transaction from a funded Pre-PegIn tx\n */\nexport interface BuildPeginTxParams {\n /** Same PrePeginParams used to create the Pre-PegIn transaction */\n prePeginParams: PrePeginParams;\n /** CSV timelock in blocks for the PegIn vault output */\n timelockPegin: number;\n /** Hex-encoded funded Pre-PegIn transaction */\n fundedPrePeginTxHex: string;\n /** Index of the HTLC output to spend */\n htlcVout: number;\n}\n\n/**\n * Result of building the PegIn transaction\n */\nexport interface PeginTxResult {\n /** PegIn transaction hex (1 input spending HTLC, 1 vault output) */\n txHex: string;\n /** PegIn transaction ID */\n txid: string;\n /** Vault output scriptPubKey (hex encoded) */\n vaultScriptPubKey: string;\n /** Vault output value in satoshis */\n vaultValue: bigint;\n}\n\n/**\n * Build unfunded Pre-PegIn transaction using WASM.\n *\n * Creates a Bitcoin transaction template with no inputs, an HTLC output, and a\n * CPFP anchor output. The HTLC value is computed internally from the contract\n * parameters — the caller does not need to compute depositorClaimValue separately.\n *\n * @param params - Pre-PegIn parameters\n * @returns Unfunded Pre-PegIn transaction details with HTLC output information\n * @throws If WASM initialization fails or parameters are invalid\n */\nexport async function buildPrePeginPsbt(\n params: PrePeginParams,\n): Promise<PrePeginPsbtResult> {\n const authAnchorHash = normalizeAuthAnchorHash(params.authAnchorHash);\n\n const result = await createPrePeginTransaction({\n depositorPubkey: params.depositorPubkey,\n vaultProviderPubkey: params.vaultProviderPubkey,\n vaultKeeperPubkeys: params.vaultKeeperPubkeys,\n universalChallengerPubkeys: params.universalChallengerPubkeys,\n hashlocks: [...params.hashlocks],\n timelockRefund: params.timelockRefund,\n pegInAmounts: [...params.pegInAmounts],\n feeRate: params.feeRate,\n minPeginFeeRate: params.minPeginFeeRate,\n numLocalChallengers: params.numLocalChallengers,\n councilQuorum: params.councilQuorum,\n councilSize: params.councilSize,\n network: params.network,\n authAnchorHash,\n });\n\n // CLAUDE.md critical path #1: the WASM outputs reach JS with no runtime\n // validation. Cross-check every value-bearing field against the request\n // and the protocol formula before it can feed a signed tx or the on-chain\n // PegIn registration. Both the sizing and commit passes route through here.\n await assertWasmPeginSizing(result, params);\n\n // Parse the unfunded tx to sum all output values\n // (HTLCs + optional OP_RETURN + CPFP anchor). This is the amount\n // UTXOs must cover before adding network fees.\n const parsed = parseUnfundedWasmTransaction(result.txHex);\n\n // Bind the validated metadata to the bytes that get funded and signed:\n // the encoded HTLC outputs must carry exactly the values/scripts the\n // cross-check above validated. Otherwise a tx whose real outputs differ\n // from the checked metadata could still be funded and signed.\n assertEncodedHtlcOutputsMatch(\n parsed.outputs,\n result.htlcValues,\n result.htlcScriptPubKeys,\n );\n\n const totalOutputValue = parsed.outputs.reduce(\n (sum, o) => sum + BigInt(o.value),\n 0n,\n );\n\n // The WASM places the OP_RETURN commitment immediately after the\n // HTLC outputs when authAnchorHash is provided.\n const authAnchorVout =\n authAnchorHash !== undefined ? result.htlcValues.length : null;\n\n return {\n psbtHex: result.txHex,\n totalOutputValue,\n htlcValues: result.htlcValues,\n htlcScriptPubKeys: result.htlcScriptPubKeys,\n htlcAddresses: result.htlcAddresses,\n peginAmounts: result.peginAmounts,\n depositorClaimValue: result.depositorClaimValue,\n authAnchorVout,\n };\n}\n\n/**\n * Validate and normalize an `authAnchorHash` hex string before passing\n * it to the WASM boundary. WASM expects exactly 64 lowercase hex chars.\n */\nexport function normalizeAuthAnchorHash(\n value: string | undefined,\n): string | undefined {\n if (value === undefined) return undefined;\n const cleaned =\n value.startsWith(\"0x\") || value.startsWith(\"0X\") ? value.slice(2) : value;\n if (\n cleaned.length !== AUTH_ANCHOR_HASH_HEX_LEN ||\n !HEX_PATTERN.test(cleaned)\n ) {\n throw new Error(\n `authAnchorHash must be 32-byte hex (${AUTH_ANCHOR_HASH_HEX_LEN} chars, no 0x prefix); got length ${cleaned.length}`,\n );\n }\n return cleaned.toLowerCase();\n}\n\n/**\n * Build the PegIn transaction from a funded Pre-PegIn transaction.\n *\n * The PegIn transaction spends the Pre-PegIn HTLC output at htlcVout via the\n * hashlock + all-party script (leaf 0).\n *\n * @param params - Build parameters including Pre-PegIn params and funded tx hex\n * @returns PegIn transaction details\n * @throws If WASM initialization fails or parameters are invalid\n */\nexport async function buildPeginTxFromFundedPrePegin(\n params: BuildPeginTxParams,\n): Promise<PeginTxResult> {\n // WASM reconstructs the Pre-PegIn template from these params to\n // decode the funded tx. Must pass `authAnchorHash` (normalized\n // identically to buildPrePeginPsbt) so the reconstruction matches\n // the original outputs, including the OP_RETURN at vout =\n // hashlocks.length.\n const result = await buildPeginTxFromPrePegin(\n {\n depositorPubkey: params.prePeginParams.depositorPubkey,\n vaultProviderPubkey: params.prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: params.prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys:\n params.prePeginParams.universalChallengerPubkeys,\n hashlocks: [...params.prePeginParams.hashlocks],\n timelockRefund: params.prePeginParams.timelockRefund,\n pegInAmounts: [...params.prePeginParams.pegInAmounts],\n feeRate: params.prePeginParams.feeRate,\n minPeginFeeRate: params.prePeginParams.minPeginFeeRate,\n numLocalChallengers: params.prePeginParams.numLocalChallengers,\n councilQuorum: params.prePeginParams.councilQuorum,\n councilSize: params.prePeginParams.councilSize,\n network: params.prePeginParams.network,\n authAnchorHash: normalizeAuthAnchorHash(\n params.prePeginParams.authAnchorHash,\n ),\n },\n params.timelockPegin,\n params.fundedPrePeginTxHex,\n params.htlcVout,\n );\n\n return {\n txHex: result.txHex,\n txid: result.txid,\n vaultScriptPubKey: result.vaultScriptPubKey,\n vaultValue: result.vaultValue,\n };\n}\n","/**\n * Payout Script Generator Primitive\n *\n * This module provides pure functions for generating payout scripts and taproot information\n * by wrapping the WASM implementation from @babylonlabs-io/babylon-tbv-rust-wasm.\n *\n * The payout script is used for signing payout transactions in the vault system.\n * It defines the spending conditions for the vault output, enabling the depositor\n * to authorize payouts during the peg-in flow (Step 3).\n *\n * @remarks\n * This is a low-level primitive. For most use cases, prefer using {@link buildPayoutPsbt}\n * which handles script creation internally. For high-level wallet orchestration, use\n * PayoutManager from the managers module.\n *\n * @see {@link buildPayoutPsbt} - Higher-level function that uses this internally\n *\n * @module primitives/scripts/payout\n */\n\nimport {\n createPayoutConnector,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\n/**\n * Parameters for creating a payout script.\n *\n * These parameters define the participants in a vault and are used to generate\n * the taproot script that controls how funds can be spent from the vault.\n */\nexport interface PayoutScriptParams {\n /**\n * Depositor's BTC public key (x-only, 64-char hex without 0x prefix).\n *\n * This is the user depositing BTC into the vault. The depositor must sign\n * payout transactions to authorize fund distribution.\n */\n depositor: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex without 0x prefix).\n *\n * The service provider managing vault operations. Also referred to as\n * \"claimer\" in the WASM layer.\n */\n vaultProvider: string;\n\n /**\n * Array of vault keeper BTC public keys (x-only, 64-char hex without 0x prefix).\n *\n * Vault keepers participate in vault operations and script spending conditions.\n */\n vaultKeepers: string[];\n\n /**\n * Array of universal challenger BTC public keys (x-only, 64-char hex without 0x prefix).\n *\n * These parties can challenge the vault under certain conditions.\n */\n universalChallengers: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Bitcoin network for script generation.\n *\n * Must match the network used for all other vault operations to ensure\n * address encoding compatibility.\n */\n network: Network;\n}\n\n/**\n * Result of creating a payout script.\n *\n * Contains all the taproot-related data needed for constructing and signing\n * payout transactions from the vault.\n */\nexport interface PayoutScriptResult {\n /**\n * The payout script hex used in taproot script path spending.\n *\n * This is the raw script bytes that define the spending conditions,\n * encoded as a hexadecimal string. Used when constructing the\n * tapLeafScript for PSBT signing.\n */\n payoutScript: string;\n\n /**\n * The taproot script hash (leaf hash) for the payout script.\n *\n * This is the tagged hash of the script used in taproot tree construction.\n * Required for computing the control block during script path spending.\n */\n taprootScriptHash: string;\n\n /**\n * The full scriptPubKey for the vault output address.\n *\n * This is the complete output script (OP_1 <32-byte-key>) that should be\n * used when creating the vault output in a peg-in transaction.\n */\n scriptPubKey: string;\n\n /**\n * The vault Bitcoin address derived from the script.\n *\n * A human-readable bech32m address (bc1p... for mainnet, tb1p... for testnet/signet)\n * that can be used to receive funds into the vault.\n */\n address: string;\n\n /**\n * Serialized control block for Taproot script path spend (hex encoded).\n *\n * Computed by the Rust WASM PeginPayoutConnector. Used directly in\n * tapLeafScript when building payout PSBTs.\n */\n payoutControlBlock: string;\n}\n\n/**\n * Create payout script and taproot information using WASM.\n *\n * This is a pure function that wraps the Rust WASM implementation.\n * The payout connector generates the necessary taproot scripts and information\n * required for signing payout transactions.\n *\n * @remarks\n * The generated script encodes spending conditions that require signatures from\n * the depositor and vault provider (or liquidators in challenge scenarios).\n * This script is used internally by {@link buildPayoutPsbt}.\n *\n * @param params - Payout script parameters defining vault participants and network\n * @returns Payout script and taproot information for PSBT construction\n *\n * @see {@link buildPayoutPsbt} - Use this for building complete payout PSBTs\n */\nexport async function createPayoutScript(\n params: PayoutScriptParams,\n): Promise<PayoutScriptResult> {\n // Call the WASM wrapper with the correct parameter structure\n const connector = await createPayoutConnector(\n {\n depositor: params.depositor,\n vaultProvider: params.vaultProvider,\n vaultKeepers: params.vaultKeepers,\n universalChallengers: params.universalChallengers,\n timelockPegin: params.timelockPegin,\n },\n params.network,\n );\n\n return {\n payoutScript: connector.payoutScript,\n taprootScriptHash: connector.taprootScriptHash,\n scriptPubKey: connector.scriptPubKey,\n address: connector.address,\n payoutControlBlock: connector.payoutControlBlock,\n };\n}\n","/**\n * Protocol invariants for depositor graph transactions.\n *\n * These indices and counts encode the on-chain vault protocol layout\n * (which output of PegIn/Assert each child transaction spends, and how\n * many inputs each transaction has). Consumed by the PSBT builders and\n * the depositor graph signing service; a drift between copies of these\n * values would silently change validation behaviour.\n *\n * @module primitives/psbt/constants\n * @see btc-vault crates/vault/docs/btc-transactions-spec.md\n */\n\n/**\n * Depositor Payout transaction input count.\n * Input 0: PegIn:0 (signed). Input 1: Assert:0 (in sighash, not signed).\n */\nexport const DEPOSITOR_PAYOUT_INPUT_COUNT = 2;\n\n/** PegIn vault output index spent by the depositor's Payout input 0. */\nexport const PEGIN_VAULT_OUTPUT_INDEX = 0;\n\n/** Assert output index spent by the depositor's Payout input 1 (NOT signed). */\nexport const ASSERT_PAYOUT_OUTPUT_INDEX = 0;\n\n/**\n * Dust amount (sats) for the payout CPFP anchor output. Matches `DUST_AMOUNT`\n * in `btc-vault crates/vault/src/lib.rs`.\n */\nexport const PAYOUT_ANCHOR_DUST_SATS = 546;\n\n/** VP-claimer payout output count: [depositor payout, VP commission, CPFP anchor]. */\nexport const VP_CLAIMER_PAYOUT_OUTPUT_COUNT = 3;\n\n/** Depositor/VK-claimer payout output count: [claimer payout, CPFP anchor]. */\nexport const NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT = 2;\n\n/**\n * Exclusive upper bound on VP commission (bps), and the bps denominator for\n * `floor(peginValue * bps / 10_000)`. Matches `BTCVaultRegistry._validateCommission`\n * (`commissionBps >= 10000` reverts). The minimum is version-locked\n * (`minVpCommissionBps`) and enforced upstream, not here.\n */\nexport const MAX_VP_COMMISSION_BPS_EXCLUSIVE = 10_000;\n","/**\n * Payout PSBT Builder Primitives\n *\n * This module provides pure functions for building unsigned payout PSBTs and extracting\n * Schnorr signatures from signed PSBTs. It uses WASM-generated scripts from the payout\n * connector and bitcoinjs-lib for PSBT construction.\n *\n * The Payout transaction references the Assert transaction (input 1).\n *\n * @module primitives/psbt/payout\n */\n\nimport {\n type Network,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { Psbt, Transaction } from \"bitcoinjs-lib\";\nimport { createPayoutScript } from \"../scripts/payout\";\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n isValidHex,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport {\n ASSERT_PAYOUT_OUTPUT_INDEX,\n MAX_VP_COMMISSION_BPS_EXCLUSIVE,\n NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT,\n PAYOUT_ANCHOR_DUST_SATS,\n PEGIN_VAULT_OUTPUT_INDEX,\n VP_CLAIMER_PAYOUT_OUTPUT_COUNT,\n} from \"./constants\";\n\n/**\n * Number of items in a Taproot script-path spend witness stack for a\n * single-signature script: [signature, script, controlBlock].\n *\n * The current payout script requires exactly one depositor signature. If the\n * protocol evolves to require multiple signatures in the payout script, this\n * invariant and the finalized-PSBT extraction path must be revisited because\n * the first witness item would no longer necessarily be the depositor's.\n */\nconst TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE = 3;\n\n/**\n * Coarse cap on a payout tx's implicit fee (inputs − outputs), as a fraction\n * of input value — blocks a VP deflating outputs and burning the remainder\n * as miner fee. A backstop only; the per-role structural checks in\n * {@link assertPayoutOutputLayout} are the primary value-diversion guard.\n */\nconst MAX_PAYOUT_FEE_FRACTION_NUMERATOR = 10;\nconst MAX_PAYOUT_FEE_FRACTION_DENOMINATOR = 100;\n\n/**\n * Parameters for building an unsigned Payout PSBT\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface PayoutParams {\n /**\n * Payout transaction hex (unsigned)\n * This is the transaction that needs to be signed by the depositor\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex\n * Payout input 1 references Assert output 0\n */\n assertTxHex: string;\n\n /**\n * Peg-in transaction hex\n * This transaction created the vault output that we're spending\n */\n peginTxHex: string;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex without 0x prefix)\n */\n depositorBtcPubkey: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex)\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex)\n */\n vaultKeeperBtcPubkeys: string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex)\n */\n universalChallengerBtcPubkeys: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Bitcoin network\n */\n network: Network;\n\n /**\n * Claimer's x-only BTC public key (64-char hex, no prefix). Drives role\n * inference (VP / depositor-as-claimer / VK-claimer) inside `buildPayoutPsbt`.\n */\n claimerBtcPubkey: string;\n\n /**\n * On-chain registered depositor payout scriptPubKey (hex, 0x optional).\n * Expected outs[0].script for VP- and depositor-claimer roles; unused for\n * VK-claimer (its outs[0].script is derived from `claimerBtcPubkey`).\n */\n registeredPayoutScriptPubKey: string;\n\n /**\n * VP commission in basis points (`BTCVaultRegistry.vaultProviderCommissionBps`).\n * Caps the VP-claimer outs[1].value. The protocol minimum is enforced\n * upstream; here only `0 <= bps < 10_000` is checked, for safe cap math.\n */\n commissionBps: number;\n}\n\n/**\n * Result of building an unsigned payout PSBT\n */\nexport interface PayoutPsbtResult {\n /**\n * Unsigned PSBT hex ready for signing\n */\n psbtHex: string;\n}\n\n/**\n * Build unsigned Payout PSBT for depositor to sign.\n *\n * Payout is used in the **challenge path** when the claimer proves validity:\n * 1. Vault provider submits Claim transaction\n * 2. Challenge is raised during challenge period\n * 3. Claimer submits Assert transaction to prove validity\n * 4. Payout can be executed (references Assert tx)\n *\n * Payout transactions have the following structure:\n * - Input 0: from PeginTx output0 (signed by depositor)\n * - Input 1: from Assert output0 (NOT signed by depositor)\n *\n * @param params - Payout parameters\n * @returns Unsigned PSBT ready for depositor to sign\n *\n * @throws If payout transaction does not have exactly 2 inputs\n * @throws If input 0 does not spend PegIn:0 (vault UTXO)\n * @throws If input 1 does not spend Assert:0 (proof output)\n * @throws If previous output is not found for either input\n * @throws If sum of output values exceeds sum of input values (invalid tx)\n * @throws If implicit fee (inputs − outputs) exceeds the configured fraction\n * of total input value — see {@link MAX_PAYOUT_FEE_FRACTION_NUMERATOR}\n * @throws If `claimerBtcPubkey` is not VP, depositor, or a registered VK\n * @throws If payout output count, outs[0] script, outs[last] anchor value, or\n * (VP-claimer) outs[1] commission cap do not match the protocol layout\n * @throws If `commissionBps` is not a non-negative integer below 10_000\n */\nexport async function buildPayoutPsbt(\n params: PayoutParams,\n): Promise<PayoutPsbtResult> {\n // Normalize hex inputs (strip 0x prefix if present)\n const payoutTxHex = stripHexPrefix(params.payoutTxHex);\n const peginTxHex = stripHexPrefix(params.peginTxHex);\n const assertTxHex = stripHexPrefix(params.assertTxHex);\n\n // Get payout script from WASM\n const payoutConnector = await createPayoutScript({\n depositor: params.depositorBtcPubkey,\n vaultProvider: params.vaultProviderBtcPubkey,\n vaultKeepers: params.vaultKeeperBtcPubkeys,\n universalChallengers: params.universalChallengerBtcPubkeys,\n timelockPegin: params.timelockPegin,\n network: params.network,\n });\n\n const payoutScriptBytes = hexToUint8Array(payoutConnector.payoutScript);\n const controlBlock = hexToUint8Array(payoutConnector.payoutControlBlock);\n\n // Parse transactions\n const payoutTx = Transaction.fromHex(payoutTxHex);\n const peginTx = Transaction.fromHex(peginTxHex);\n const assertTx = Transaction.fromHex(assertTxHex);\n\n // Create PSBT\n const psbt = new Psbt();\n psbt.setVersion(payoutTx.version);\n psbt.setLocktime(payoutTx.locktime);\n\n // PayoutTx has exactly 2 inputs:\n // - Input 0: from PeginTx output0 (signed by depositor using taproot script path)\n // - Input 1: from Assert output0 (signed by claimer/challengers, not depositor)\n //\n // IMPORTANT: For Taproot SIGHASH_DEFAULT (0x00), the sighash commits to ALL inputs'\n // prevouts, not just the one being signed. Therefore, we must include BOTH inputs\n // in the PSBT so the wallet computes the correct sighash that the VP expects.\n\n // Verify payout transaction has expected structure\n if (payoutTx.ins.length !== 2) {\n throw new Error(\n `Payout transaction must have exactly 2 inputs, got ${payoutTx.ins.length}`,\n );\n }\n\n const input0 = payoutTx.ins[0];\n const input1 = payoutTx.ins[1];\n\n // Verify input 0 spends PegIn:0 (the vault UTXO).\n // Both txid AND vout must match the protocol contract — the vout is the\n // input-side anchor that prevents a malicious VP from binding the\n // depositor's signature to a different output of the same parent.\n const input0Txid = uint8ArrayToHex(\n new Uint8Array(input0.hash).slice().reverse(),\n );\n const peginTxid = peginTx.getId();\n\n if (input0Txid !== peginTxid || input0.index !== PEGIN_VAULT_OUTPUT_INDEX) {\n throw new Error(\n `Input 0 must spend PegIn:${PEGIN_VAULT_OUTPUT_INDEX}. ` +\n `Expected ${peginTxid}:${PEGIN_VAULT_OUTPUT_INDEX}, got ${input0Txid}:${input0.index}`,\n );\n }\n\n // Verify input 1 spends Assert:0 (the proof output).\n const input1Txid = uint8ArrayToHex(\n new Uint8Array(input1.hash).slice().reverse(),\n );\n const assertTxid = assertTx.getId();\n\n if (input1Txid !== assertTxid || input1.index !== ASSERT_PAYOUT_OUTPUT_INDEX) {\n throw new Error(\n `Input 1 must spend Assert:${ASSERT_PAYOUT_OUTPUT_INDEX}. ` +\n `Expected ${assertTxid}:${ASSERT_PAYOUT_OUTPUT_INDEX}, got ${input1Txid}:${input1.index}`,\n );\n }\n\n const peginPrevOut = peginTx.outs[input0.index];\n if (!peginPrevOut) {\n throw new Error(\n `Previous output not found for input 0 (txid: ${input0Txid}, index: ${input0.index})`,\n );\n }\n\n const input1PrevOut = assertTx.outs[input1.index];\n if (!input1PrevOut) {\n throw new Error(\n `Previous output not found for input 1 (txid: ${input1Txid}, index: ${input1.index})`,\n );\n }\n\n // Per-role output validation — blocks an extra attacker output or value\n // routed into a non-payout slot.\n assertPayoutOutputLayout({\n payoutTx,\n peginValueSats: peginPrevOut.value,\n claimerBtcPubkey: params.claimerBtcPubkey,\n vaultProviderBtcPubkey: params.vaultProviderBtcPubkey,\n depositorBtcPubkey: params.depositorBtcPubkey,\n vaultKeeperBtcPubkeys: params.vaultKeeperBtcPubkeys,\n registeredPayoutScriptPubKey: params.registeredPayoutScriptPubKey,\n commissionBps: params.commissionBps,\n });\n\n // Bound the implicit fee — blocks a VP deflating output values and burning\n // the difference as miner fee.\n const inputValueSats = peginPrevOut.value + input1PrevOut.value;\n let outputValueSats = 0;\n for (const out of payoutTx.outs) outputValueSats += out.value;\n if (outputValueSats > inputValueSats) {\n throw new Error(\n `Payout outputs (${outputValueSats} sats) exceed inputs ` +\n `(${inputValueSats} sats); invalid transaction.`,\n );\n }\n const implicitFeeSats = inputValueSats - outputValueSats;\n const maxFeeSats = Math.floor(\n (inputValueSats * MAX_PAYOUT_FEE_FRACTION_NUMERATOR) /\n MAX_PAYOUT_FEE_FRACTION_DENOMINATOR,\n );\n if (implicitFeeSats > maxFeeSats) {\n throw new Error(\n `Payout implicit fee ${implicitFeeSats} sats exceeds the safety cap ` +\n `of ${maxFeeSats} sats ` +\n `(${MAX_PAYOUT_FEE_FRACTION_NUMERATOR}/${MAX_PAYOUT_FEE_FRACTION_DENOMINATOR} ` +\n `of inputs=${inputValueSats}); refusing to sign payout.`,\n );\n }\n\n // Input 0: Depositor signs using Taproot script path spend\n // This input includes tapLeafScript for signing\n psbt.addInput({\n hash: input0.hash,\n index: input0.index,\n sequence: input0.sequence,\n witnessUtxo: {\n script: peginPrevOut.script,\n value: peginPrevOut.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(payoutScriptBytes),\n controlBlock: Buffer.from(controlBlock),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n // sighashType omitted - defaults to SIGHASH_DEFAULT (0x00) for Taproot\n });\n\n // Input 1: From Assert transaction (NOT signed by depositor)\n // We include this with witnessUtxo so the sighash is computed correctly,\n // but we do NOT include tapLeafScript since the depositor doesn't sign it.\n psbt.addInput({\n hash: input1.hash,\n index: input1.index,\n sequence: input1.sequence,\n witnessUtxo: {\n script: input1PrevOut.script,\n value: input1PrevOut.value,\n },\n // No tapLeafScript - depositor doesn't sign this input\n });\n\n // Add outputs\n for (const output of payoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return {\n psbtHex: psbt.toHex(),\n };\n}\n\n/**\n * Validate a payout transaction's output structure for the claimer's role,\n * keyed on `claimerBtcPubkey`. Pins per role: `outs.length`, `outs[0].script`,\n * `outs[last].value` (anchor dust), and (VP-claimer) `outs[1].value` capped at\n * `floor(peginValue × commissionBps / 10_000)`. Canonical layouts: VP-claimer\n * = [payout, commission, anchor]; depositor/VK-claimer = [payout, anchor].\n *\n * `outs[1].script` and `outs[last].script` are intentionally not pinned: the\n * value pins above bound depositor exposure regardless of where those outputs\n * are sent, so the value pins — not script pins — are load-bearing.\n *\n * @internal Helper invoked by {@link buildPayoutPsbt}.\n */\nfunction assertPayoutOutputLayout(args: {\n payoutTx: Transaction;\n peginValueSats: number;\n claimerBtcPubkey: string;\n vaultProviderBtcPubkey: string;\n depositorBtcPubkey: string;\n vaultKeeperBtcPubkeys: string[];\n registeredPayoutScriptPubKey: string;\n commissionBps: number;\n}): void {\n const {\n payoutTx,\n peginValueSats,\n claimerBtcPubkey,\n vaultProviderBtcPubkey,\n depositorBtcPubkey,\n vaultKeeperBtcPubkeys,\n registeredPayoutScriptPubKey,\n commissionBps,\n } = args;\n\n if (!isValidHex(registeredPayoutScriptPubKey)) {\n throw new Error(\"Invalid registeredPayoutScriptPubKey: not valid hex\");\n }\n\n const claimer = stripHexPrefix(claimerBtcPubkey).toLowerCase();\n const vp = stripHexPrefix(vaultProviderBtcPubkey).toLowerCase();\n const dep = stripHexPrefix(depositorBtcPubkey).toLowerCase();\n const keepers = vaultKeeperBtcPubkeys.map((k) =>\n stripHexPrefix(k).toLowerCase(),\n );\n\n type Role = \"vp-claimer\" | \"depositor-as-claimer\" | \"vk-claimer\";\n let role: Role;\n let expectedOutCount: number;\n let expectedOut0ScriptHex: string;\n\n if (claimer === vp) {\n role = \"vp-claimer\";\n expectedOutCount = VP_CLAIMER_PAYOUT_OUTPUT_COUNT;\n expectedOut0ScriptHex = stripHexPrefix(registeredPayoutScriptPubKey);\n } else if (claimer === dep) {\n role = \"depositor-as-claimer\";\n expectedOutCount = NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT;\n expectedOut0ScriptHex = stripHexPrefix(registeredPayoutScriptPubKey);\n } else if (keepers.includes(claimer)) {\n role = \"vk-claimer\";\n expectedOutCount = NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT;\n expectedOut0ScriptHex = stripHexPrefix(deriveBip86ScriptPubKeyHex(claimer));\n } else {\n throw new Error(\n `Unknown claimer pubkey ${claimer}: not VP, depositor, or a registered vault keeper`,\n );\n }\n\n if (payoutTx.outs.length !== expectedOutCount) {\n throw new Error(\n `Payout transaction has ${payoutTx.outs.length} output(s), ` +\n `expected exactly ${expectedOutCount} for role ${role}.`,\n );\n }\n\n const expectedOut0Script = Buffer.from(expectedOut0ScriptHex, \"hex\");\n if (!payoutTx.outs[0].script.equals(expectedOut0Script)) {\n throw new Error(\n `Payout transaction output 0 does not pay the expected scriptPubKey for role ${role}`,\n );\n }\n\n const anchorIdx = expectedOutCount - 1;\n if (payoutTx.outs[anchorIdx].value !== PAYOUT_ANCHOR_DUST_SATS) {\n throw new Error(\n `Payout CPFP anchor (out ${anchorIdx}) value ${payoutTx.outs[anchorIdx].value} sats ` +\n `must equal ${PAYOUT_ANCHOR_DUST_SATS} sats`,\n );\n }\n\n if (role === \"vp-claimer\") {\n // Structural guard only — a non-negative integer below the bps\n // denominator, so the cap math `floor(peginValue * bps / 10_000)` is\n // meaningful. The protocol minimum is enforced at the trust boundary\n // (`prepareSigningContext`); a too-low value here is fail-safe.\n if (\n !Number.isInteger(commissionBps) ||\n commissionBps < 0 ||\n commissionBps >= MAX_VP_COMMISSION_BPS_EXCLUSIVE\n ) {\n throw new Error(\n `commissionBps must be an integer in ` +\n `[0, ${MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${commissionBps}`,\n );\n }\n const maxCommissionSats = Math.floor(\n (peginValueSats * commissionBps) / MAX_VP_COMMISSION_BPS_EXCLUSIVE,\n );\n if (payoutTx.outs[1].value > maxCommissionSats) {\n throw new Error(\n `Payout VP commission (out 1) value ${payoutTx.outs[1].value} sats ` +\n `exceeds cap ${maxCommissionSats} sats ` +\n `(${commissionBps} bps of peginValue=${peginValueSats})`,\n );\n }\n }\n}\n\n/**\n * Extract Schnorr signature from signed payout PSBT.\n *\n * This function supports two cases:\n * 1. Non-finalized PSBT: Extracts from tapScriptSig field\n * 2. Finalized PSBT: Extracts from witness data\n *\n * The signature is returned as a 64-byte hex string (128 hex characters).\n * Payout signatures must use implicit Taproot SIGHASH_DEFAULT, which is\n * encoded by omitting the sighash byte.\n *\n * @param signedPsbtHex - Signed PSBT hex\n * @param depositorPubkey - Depositor's public key (x-only, 64-char hex)\n * @param inputIndex - Input index to extract signature from (default: 0)\n * @returns 64-byte Schnorr signature (128 hex characters, no sighash flag)\n *\n * @throws If no signature is found in the PSBT\n * @throws If the signature has an unexpected length\n */\nexport function extractPayoutSignature(\n signedPsbtHex: string,\n depositorPubkey: string,\n inputIndex = 0,\n): string {\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n\n if (inputIndex >= signedPsbt.data.inputs.length) {\n throw new Error(\n `Input index ${inputIndex} out of range (${signedPsbt.data.inputs.length} inputs)`,\n );\n }\n\n const input = signedPsbt.data.inputs[inputIndex];\n\n // Case 1: Non-finalized PSBT — extract from tapScriptSig\n if (input.tapScriptSig && input.tapScriptSig.length > 0) {\n const depositorPubkeyBytes = hexToUint8Array(depositorPubkey);\n\n for (const sigEntry of input.tapScriptSig) {\n if (sigEntry.pubkey.equals(Buffer.from(depositorPubkeyBytes))) {\n return extractSchnorrSig(sigEntry.signature, inputIndex);\n }\n }\n\n throw new Error(\n `No signature found for depositor pubkey: ${depositorPubkey} at input ${inputIndex}`,\n );\n }\n\n // Case 2: Finalized PSBT — extract from finalScriptWitness\n // Taproot single-signature script-path witness: [signature, script, controlBlock].\n // Enforce the exact stack size so that if a wallet produces an unexpected\n // finalization (e.g. a multi-signature stack, an annex, or malformed data),\n // we fail loudly instead of silently returning witnessStack[0] which may\n // not be the depositor's signature.\n if (input.finalScriptWitness && input.finalScriptWitness.length > 0) {\n const witnessStack = parseWitnessStack(input.finalScriptWitness);\n if (witnessStack.length !== TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE) {\n throw new Error(\n `Unexpected finalized witness stack size at input ${inputIndex}: ` +\n `expected ${TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE} items (signature, script, controlBlock), ` +\n `got ${witnessStack.length}`,\n );\n }\n return extractSchnorrSig(witnessStack[0], inputIndex);\n }\n\n throw new Error(\n `No tapScriptSig or finalScriptWitness found in signed PSBT at input ${inputIndex}`,\n );\n}\n\n/**\n * Extract and validate a 64-byte Schnorr signature.\n * Rejects 65-byte signatures because the appended sighash byte changes the\n * Taproot message being signed; stripping it would produce an unverifiable\n * SIGHASH_DEFAULT signature.\n * @internal\n */\nfunction extractSchnorrSig(sig: Uint8Array, inputIndex: number): string {\n if (sig.length === 64) {\n return uint8ArrayToHex(new Uint8Array(sig));\n }\n if (sig.length === 65) {\n throw new Error(\n `Unexpected sighash byte 0x${sig[64].toString(16).padStart(2, \"0\")} at input ${inputIndex}. ` +\n \"Expected implicit SIGHASH_DEFAULT as a 64-byte signature.\",\n );\n }\n throw new Error(\n `Unexpected signature length at input ${inputIndex}: ${sig.length}`,\n );\n}\n\n/**\n * Parse a BIP-141 serialized witness stack into individual stack items.\n * Format: [varint item_count] [varint len, data]...\n *\n * Throws on malformed input (truncated buffer, 8-byte varints, or trailing\n * bytes) so callers never receive silently-corrupted witness items.\n * @internal\n */\nfunction parseWitnessStack(witness: Buffer): Buffer[] {\n const items: Buffer[] = [];\n let offset = 0;\n\n const requireBytes = (n: number): void => {\n if (offset + n > witness.length) {\n throw new Error(\n `Malformed witness data: need ${n} byte(s) at offset ${offset}, only ${witness.length - offset} remaining`,\n );\n }\n };\n\n const readVarInt = (): number => {\n requireBytes(1);\n const first = witness[offset++];\n if (first < 0xfd) return first;\n if (first === 0xfd) {\n requireBytes(2);\n const val = (witness[offset] | (witness[offset + 1] << 8)) >>> 0;\n offset += 2;\n return val;\n }\n if (first === 0xfe) {\n requireBytes(4);\n const val =\n (witness[offset] |\n (witness[offset + 1] << 8) |\n (witness[offset + 2] << 16) |\n (witness[offset + 3] << 24)) >>>\n 0;\n offset += 4;\n return val;\n }\n // 0xff — 8-byte varint. Not used for witness sizes in practice and JS\n // numbers cannot represent all 64-bit values exactly, so reject rather\n // than risk silent truncation.\n throw new Error(\n `Malformed witness data: 8-byte varint (0xff) not supported at offset ${offset - 1}`,\n );\n };\n\n const count = readVarInt();\n for (let i = 0; i < count; i++) {\n const len = readVarInt();\n requireBytes(len);\n items.push(Buffer.from(witness.subarray(offset, offset + len)));\n offset += len;\n }\n\n if (offset !== witness.length) {\n throw new Error(\n `Malformed witness data: ${witness.length - offset} trailing byte(s) after parsing ${count} item(s)`,\n );\n }\n\n return items;\n}\n\n","/**\n * Asserts a wallet-returned PSBT encodes the same unsigned transaction\n * as the locally-built PSBT we asked the wallet to sign. Per-input PSBT\n * metadata (witnessUtxo, tapLeafScript, sighashType) is intentionally NOT\n * compared — those fields are committed to the Schnorr sighash and the\n * vault provider's `verify_depositor_signature` rejects mismatches there.\n * This primitive defends the path where a colluding VP would otherwise\n * accept a wallet-substituted signature.\n */\n\nimport { Buffer } from \"buffer\";\n\nimport { Psbt } from \"bitcoinjs-lib\";\n\n/**\n * Thrown when a wallet-returned PSBT encodes a different unsigned\n * transaction than the one the caller asked the wallet to sign.\n */\nexport class PsbtSubstitutionError extends Error {\n constructor(detail: string) {\n super(\n `Wallet returned a PSBT for a different transaction: ${detail}`,\n );\n this.name = \"PsbtSubstitutionError\";\n }\n}\n\nexport interface AssertPsbtUnsignedTxMatchesParams {\n /** PSBT we built locally and asked the wallet to sign. */\n requestedPsbtHex: string;\n /** PSBT the wallet returned after signing. */\n returnedPsbtHex: string;\n}\n\nfunction parsePsbt(label: \"requested\" | \"returned\", hex: string): Psbt {\n try {\n return Psbt.fromHex(hex);\n } catch (cause) {\n const reason = cause instanceof Error ? cause.message : String(cause);\n throw new Error(`Failed to parse ${label} PSBT: ${reason}`);\n }\n}\n\n/**\n * Length of the hex prefix included in mismatch errors. Short enough that\n * full prevout txids and output scriptPubKeys never reach logs / error\n * trackers, long enough to disambiguate during forensic triage.\n */\nconst REDACTED_HEX_PREFIX_LEN = 8;\n\nfunction redactHex(buf: Buffer): string {\n return `${buf.toString(\"hex\").slice(0, REDACTED_HEX_PREFIX_LEN)}…`;\n}\n\n/**\n * `bitcoinjs-lib` exposes `txInputs[i].hash` in internal little-endian form;\n * a human reading logs expects the big-endian txid an explorer would show.\n * Reverse before truncating so the surfaced prefix matches what an operator\n * can search for.\n */\nfunction redactTxid(internalHash: Buffer): string {\n const reversed = Buffer.from(internalHash).reverse();\n return redactHex(reversed);\n}\n\n/**\n * Compare two PSBTs and throw `PsbtSubstitutionError` unless they encode\n * the same unsigned transaction (version, locktime, inputs, outputs).\n *\n * @throws PsbtSubstitutionError on any mismatch in the unsigned tx\n * @throws Error if either PSBT cannot be parsed\n */\nexport function assertPsbtUnsignedTxMatches(\n params: AssertPsbtUnsignedTxMatchesParams,\n): void {\n const requested = parsePsbt(\"requested\", params.requestedPsbtHex);\n const returned = parsePsbt(\"returned\", params.returnedPsbtHex);\n\n if (requested.version !== returned.version) {\n throw new PsbtSubstitutionError(\n `tx version differs (requested=${requested.version}, returned=${returned.version})`,\n );\n }\n if (requested.locktime !== returned.locktime) {\n throw new PsbtSubstitutionError(\n `tx locktime differs (requested=${requested.locktime}, returned=${returned.locktime})`,\n );\n }\n if (requested.txInputs.length !== returned.txInputs.length) {\n throw new PsbtSubstitutionError(\n `input count differs (requested=${requested.txInputs.length}, returned=${returned.txInputs.length})`,\n );\n }\n if (requested.txOutputs.length !== returned.txOutputs.length) {\n throw new PsbtSubstitutionError(\n `output count differs (requested=${requested.txOutputs.length}, returned=${returned.txOutputs.length})`,\n );\n }\n for (let i = 0; i < requested.txInputs.length; i++) {\n const r = requested.txInputs[i];\n const s = returned.txInputs[i];\n if (!r.hash.equals(s.hash)) {\n throw new PsbtSubstitutionError(\n `input ${i} prevout txid differs (requested=${redactTxid(r.hash)}, returned=${redactTxid(s.hash)})`,\n );\n }\n if (r.index !== s.index) {\n throw new PsbtSubstitutionError(\n `input ${i} prevout vout differs (requested=${r.index}, returned=${s.index})`,\n );\n }\n if (r.sequence !== s.sequence) {\n throw new PsbtSubstitutionError(\n `input ${i} sequence differs (requested=${r.sequence}, returned=${s.sequence})`,\n );\n }\n }\n for (let i = 0; i < requested.txOutputs.length; i++) {\n const r = requested.txOutputs[i];\n const s = returned.txOutputs[i];\n if (!r.script.equals(s.script)) {\n throw new PsbtSubstitutionError(\n `output ${i} scriptPubKey differs (requested=${redactHex(r.script)}, returned=${redactHex(s.script)})`,\n );\n }\n if (r.value !== s.value) {\n throw new PsbtSubstitutionError(\n `output ${i} value differs (requested=${r.value}, returned=${s.value})`,\n );\n }\n }\n}\n","/**\n * Independent BIP-340 verification of a wallet-returned Taproot script-path\n * Schnorr signature against an independently-recomputed sighash.\n *\n * Critical Path #7 (CLAUDE.md): the SDK requests script-path signatures with\n * `useTweakedSigner: false, autoFinalized: false`. Wallet support for the\n * untweaked-key flag is inconsistent — older OKX / mobile bridges silently sign\n * with the *tweaked* key, Keystone ignores the flag — and a compromised\n * extension can stuff a 64-byte stub into `tapScriptSig`. A bad signature that\n * the SDK forwards is only caught on broadcast; in the worst case it passes the\n * VP off-chain but Bitcoin rejects it, leaving the depositor's BTC locked in the\n * HTLC until `timelockRefund` matures. This guard rejects such signatures before\n * they are trusted.\n *\n * Why verify against the *locally-built* PSBT, not the wallet-returned one:\n * `assertPsbtUnsignedTxMatches` pins the unsigned transaction but deliberately\n * skips per-input metadata (`witnessUtxo`, `tapLeafScript`). A malicious wallet\n * could rewrite those consistently in the returned PSBT so a wrong-message\n * signature self-validates. The trusted prevout scripts/values and leaf script\n * therefore come from the PSBT we built ourselves (derived from on-chain / WASM\n * sources); only the 64-byte signature comes from the wallet.\n *\n * Reuses the exact primitives `bip322Verify.ts` already depends on — no new\n * dependency:\n * - `@bitcoin-js/tiny-secp256k1-asmjs` → `verifySchnorr`\n * - `bitcoinjs-lib` → `Transaction.hashForWitnessV1`, `crypto.taggedHash` (TapLeaf hash)\n *\n * @module tbv/core/primitives/psbt/verifyScriptPathSchnorrSignature\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { Psbt, Transaction, crypto as bcrypto } from \"bitcoinjs-lib\";\n\nimport { Buffer } from \"buffer\";\n\nimport {\n SCHNORR_SIG_HEX_LEN,\n TAPSCRIPT_LEAF_VERSION,\n X_ONLY_PUBKEY_HEX_LEN,\n hexToUint8Array,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n// Bitcoin CompactSize (varint) prefix markers — values fixed by the protocol.\n// https://developer.bitcoin.org/reference/transactions.html#compactsize-unsigned-integers\nconst COMPACT_SIZE_UINT16_PREFIX = 0xfd; // value in [0xfd, 0xffff] → 0xfd + uint16 LE\nconst COMPACT_SIZE_UINT32_PREFIX = 0xfe; // value in [0x10000, 0xffffffff] → 0xfe + uint32 LE\nconst COMPACT_SIZE_UINT16_MAX = 0xffff;\nconst COMPACT_SIZE_UINT32_MAX = 0xffffffff;\n\n/**\n * Encode a length as a Bitcoin CompactSize (varint). Tapscript leaf scripts can\n * exceed 252 bytes (WOTS scripts), so the multi-byte forms are required, not\n * just the single-byte fast path.\n */\nfunction encodeCompactSize(n: number): Buffer {\n if (n < COMPACT_SIZE_UINT16_PREFIX) {\n return Buffer.from([n]);\n }\n if (n <= COMPACT_SIZE_UINT16_MAX) {\n const value = Buffer.alloc(2); // uint16, little-endian\n value.writeUInt16LE(n);\n return Buffer.concat([Buffer.from([COMPACT_SIZE_UINT16_PREFIX]), value]);\n }\n if (n <= COMPACT_SIZE_UINT32_MAX) {\n const value = Buffer.alloc(4); // uint32, little-endian\n value.writeUInt32LE(n);\n return Buffer.concat([Buffer.from([COMPACT_SIZE_UINT32_PREFIX]), value]);\n }\n throw new Error(`Script too large to encode as CompactSize: ${n} bytes`);\n}\n\n/** BIP-341 tag for the TapLeaf hash. */\nconst TAPLEAF_TAG = \"TapLeaf\";\n\n/**\n * Compute the BIP-341 TapLeaf hash for a tapscript leaf:\n * `tagged_hash(\"TapLeaf\", leaf_version || compact_size(script) || script)`.\n */\nfunction computeTapLeafHash(leafVersion: number, script: Uint8Array): Buffer {\n const preimage = Buffer.concat([\n Buffer.from([leafVersion]),\n encodeCompactSize(script.length),\n Buffer.from(script),\n ]);\n return bcrypto.taggedHash(TAPLEAF_TAG, preimage);\n}\n\nexport interface VerifyScriptPathSchnorrSignatureParams {\n /**\n * Hex of the PSBT we built locally and sent to the wallet (the trusted\n * source of prevout scripts/values and the leaf script). NOT the\n * wallet-returned PSBT.\n */\n requestedPsbtHex: string;\n /** The 64-byte Schnorr signature extracted from the wallet's response (128 hex chars). */\n signatureHex: string;\n /** X-only public key (64 hex chars) the wallet signed the script-path leaf with. */\n signerXOnlyPubkeyHex: string;\n /** Index of the input the signature is for. */\n inputIndex: number;\n}\n\n/**\n * Assert that `signatureHex` is a valid BIP-340 Schnorr signature by the\n * `signerXOnlyPubkeyHex` key over the Taproot script-path sighash of\n * `requestedPsbtHex` input `inputIndex` (SIGHASH_DEFAULT).\n *\n * @throws If the requested PSBT is malformed, lacks the prevout/leaf data needed\n * to recompute the sighash, or the signature does not verify.\n */\nexport function assertScriptPathSchnorrSignature(\n params: VerifyScriptPathSchnorrSignatureParams,\n): void {\n const { requestedPsbtHex, signatureHex, signerXOnlyPubkeyHex, inputIndex } =\n params;\n\n const signatureRaw = stripHexPrefix(signatureHex);\n if (signatureRaw.length !== SCHNORR_SIG_HEX_LEN) {\n throw new Error(\n `Schnorr signature for input ${inputIndex} must be ${SCHNORR_SIG_HEX_LEN} hex chars ` +\n `(64 bytes), got ${signatureRaw.length}.`,\n );\n }\n\n const signerXOnly = stripHexPrefix(signerXOnlyPubkeyHex);\n if (signerXOnly.length !== X_ONLY_PUBKEY_HEX_LEN) {\n throw new Error(\n `Signer x-only pubkey for input ${inputIndex} must be ${X_ONLY_PUBKEY_HEX_LEN} hex chars ` +\n `(32 bytes), got ${signerXOnly.length}.`,\n );\n }\n\n const psbt = Psbt.fromHex(requestedPsbtHex);\n\n if (inputIndex < 0 || inputIndex >= psbt.data.inputs.length) {\n throw new Error(\n `Input index ${inputIndex} out of range (${psbt.data.inputs.length} inputs).`,\n );\n }\n\n // Taproot's sighash commits to every input's prevout (script + value), so all\n // inputs must carry a witnessUtxo. A missing one is a build error, not a\n // value we can default — fail loudly.\n const prevOutScripts: Buffer[] = [];\n const values: number[] = [];\n for (let i = 0; i < psbt.data.inputs.length; i++) {\n const witnessUtxo = psbt.data.inputs[i].witnessUtxo;\n if (!witnessUtxo) {\n throw new Error(\n `Cannot verify signature: input ${i} of the requested PSBT has no witnessUtxo ` +\n `(required to recompute the Taproot sighash).`,\n );\n }\n prevOutScripts.push(witnessUtxo.script);\n values.push(witnessUtxo.value);\n }\n\n // The signed input must expose exactly one tapLeafScript — the leaf the\n // depositor signs. Zero means we sent the wrong PSBT; more than one means an\n // ambiguous spend path we never construct for a single-signature input.\n const tapLeafScripts = psbt.data.inputs[inputIndex].tapLeafScript;\n if (!tapLeafScripts || tapLeafScripts.length !== 1) {\n throw new Error(\n `Cannot verify signature: input ${inputIndex} of the requested PSBT must have exactly ` +\n `one tapLeafScript, got ${tapLeafScripts?.length ?? 0}.`,\n );\n }\n const leaf = tapLeafScripts[0];\n if (leaf.leafVersion !== TAPSCRIPT_LEAF_VERSION) {\n throw new Error(\n `Cannot verify signature: input ${inputIndex} tapLeafScript has leaf version ` +\n `0x${leaf.leafVersion.toString(16)}, expected 0x${TAPSCRIPT_LEAF_VERSION.toString(16)}.`,\n );\n }\n\n const leafHash = computeTapLeafHash(leaf.leafVersion, leaf.script);\n\n // Reconstruct the unsigned transaction from the requested PSBT using only\n // public bitcoinjs-lib API (same pattern as bip322Verify.ts), then compute the\n // BIP-341 script-path sighash with SIGHASH_DEFAULT.\n const tx = new Transaction();\n tx.version = psbt.version;\n tx.locktime = psbt.locktime;\n for (const input of psbt.txInputs) {\n tx.addInput(input.hash, input.index, input.sequence);\n }\n for (const output of psbt.txOutputs) {\n tx.addOutput(output.script, output.value);\n }\n\n const sighash = tx.hashForWitnessV1(\n inputIndex,\n prevOutScripts,\n values,\n Transaction.SIGHASH_DEFAULT,\n leafHash,\n );\n\n const isValid = ecc.verifySchnorr(\n sighash,\n hexToUint8Array(signerXOnly),\n hexToUint8Array(signatureRaw),\n );\n\n if (!isValid) {\n throw new Error(\n `Schnorr signature for input ${inputIndex} (signer ${signerXOnly}) does not verify ` +\n `against the expected Taproot script-path sighash. The wallet may have signed with ` +\n `the tweaked key, signed a different transaction, or returned an invalid signature.`,\n );\n }\n}\n"],"names":["assertWasmPeginSizing","result","params","expectedCount","expectedClaimValue","computeMinClaimValue","maxImpliedFee","MAX_REASONABLE_PEGIN_VBYTES","requested","peginAmount","htlcValue","impliedFee","assertEncodedHtlcOutputsMatch","outputs","htlcValues","htlcScriptPubKeys","i","encodedValue","encodedScript","expectedScript","AUTH_ANCHOR_HASH_HEX_LEN","HEX_PATTERN","buildPrePeginPsbt","authAnchorHash","normalizeAuthAnchorHash","createPrePeginTransaction","parsed","parseUnfundedWasmTransaction","totalOutputValue","sum","o","authAnchorVout","value","cleaned","buildPeginTxFromFundedPrePegin","buildPeginTxFromPrePegin","createPayoutScript","connector","createPayoutConnector","DEPOSITOR_PAYOUT_INPUT_COUNT","PEGIN_VAULT_OUTPUT_INDEX","ASSERT_PAYOUT_OUTPUT_INDEX","PAYOUT_ANCHOR_DUST_SATS","VP_CLAIMER_PAYOUT_OUTPUT_COUNT","NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT","MAX_VP_COMMISSION_BPS_EXCLUSIVE","TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE","MAX_PAYOUT_FEE_FRACTION_NUMERATOR","MAX_PAYOUT_FEE_FRACTION_DENOMINATOR","buildPayoutPsbt","payoutTxHex","stripHexPrefix","peginTxHex","assertTxHex","payoutConnector","payoutScriptBytes","hexToUint8Array","controlBlock","payoutTx","Transaction","peginTx","assertTx","psbt","Psbt","input0","input1","input0Txid","uint8ArrayToHex","peginTxid","input1Txid","assertTxid","peginPrevOut","input1PrevOut","assertPayoutOutputLayout","inputValueSats","outputValueSats","out","implicitFeeSats","maxFeeSats","TAPSCRIPT_LEAF_VERSION","Buffer","tapInternalPubkey","output","args","peginValueSats","claimerBtcPubkey","vaultProviderBtcPubkey","depositorBtcPubkey","vaultKeeperBtcPubkeys","registeredPayoutScriptPubKey","commissionBps","isValidHex","claimer","vp","dep","keepers","k","role","expectedOutCount","expectedOut0ScriptHex","deriveBip86ScriptPubKeyHex","expectedOut0Script","anchorIdx","maxCommissionSats","extractPayoutSignature","signedPsbtHex","depositorPubkey","inputIndex","signedPsbt","input","depositorPubkeyBytes","sigEntry","extractSchnorrSig","witnessStack","parseWitnessStack","sig","witness","items","offset","requireBytes","n","readVarInt","first","val","count","len","PsbtSubstitutionError","detail","parsePsbt","label","hex","cause","reason","REDACTED_HEX_PREFIX_LEN","redactHex","buf","redactTxid","internalHash","reversed","assertPsbtUnsignedTxMatches","returned","r","s","COMPACT_SIZE_UINT16_PREFIX","COMPACT_SIZE_UINT32_PREFIX","COMPACT_SIZE_UINT16_MAX","COMPACT_SIZE_UINT32_MAX","encodeCompactSize","TAPLEAF_TAG","computeTapLeafHash","leafVersion","script","preimage","bcrypto","assertScriptPathSchnorrSignature","requestedPsbtHex","signatureHex","signerXOnlyPubkeyHex","signatureRaw","SCHNORR_SIG_HEX_LEN","signerXOnly","X_ONLY_PUBKEY_HEX_LEN","prevOutScripts","values","witnessUtxo","tapLeafScripts","leaf","leafHash","tx","sighash","ecc"],"mappings":"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"}
|