@babylonlabs-io/ts-sdk 3.3.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BTCVaultRegistry.abi-BzNTa_EU.js → BTCVaultRegistry.abi-DnP4UkB5.js} +9 -140
- package/dist/BTCVaultRegistry.abi-DnP4UkB5.js.map +1 -0
- package/dist/{BTCVaultRegistry.abi-BH2-LHxN.cjs → BTCVaultRegistry.abi-DzbfZ9_s.cjs} +2 -2
- package/dist/BTCVaultRegistry.abi-DzbfZ9_s.cjs.map +1 -0
- package/dist/{PayoutManager-xEGvTbhL.js → PayoutManager-BUWP-H-q.js} +3 -3
- package/dist/PayoutManager-BUWP-H-q.js.map +1 -0
- package/dist/{PayoutManager-B1Ev0r7o.cjs → PayoutManager-Dopxq_Jv.cjs} +2 -2
- package/dist/PayoutManager-Dopxq_Jv.cjs.map +1 -0
- package/dist/{PeginManager-D2R4Q1bN.cjs → PeginManager-CMbRRTnr.cjs} +2 -2
- package/dist/{PeginManager-D2R4Q1bN.cjs.map → PeginManager-CMbRRTnr.cjs.map} +1 -1
- package/dist/{PeginManager-CQ9bVPR3.js → PeginManager-Cas6_j7t.js} +7 -7
- package/dist/{PeginManager-CQ9bVPR3.js.map → PeginManager-Cas6_j7t.js.map} +1 -1
- package/dist/{ProtocolParams.abi-Cv77fsUe.js → ProtocolParams.abi-CuDl7AuC.js} +3 -3
- package/dist/{ProtocolParams.abi-Cv77fsUe.js.map → ProtocolParams.abi-CuDl7AuC.js.map} +1 -1
- package/dist/{ProtocolParams.abi-BgEZaQ2I.cjs → ProtocolParams.abi-DWfIh6VH.cjs} +2 -2
- package/dist/{ProtocolParams.abi-BgEZaQ2I.cjs.map → ProtocolParams.abi-DWfIh6VH.cjs.map} +1 -1
- package/dist/VaultErrors.abi-Dc3UnB_h.js +5 -0
- package/dist/{VaultErrors.abi-Boz4w97c.js.map → VaultErrors.abi-Dc3UnB_h.js.map} +1 -1
- package/dist/VaultErrors.abi-Hjn1CdLs.cjs +2 -0
- package/dist/{VaultErrors.abi-DQ18kM0L.cjs.map → VaultErrors.abi-Hjn1CdLs.cjs.map} +1 -1
- package/dist/buildAndBroadcastReclaim-CVmG3ldA.cjs +2 -0
- package/dist/buildAndBroadcastReclaim-CVmG3ldA.cjs.map +1 -0
- package/dist/{buildAndBroadcastReclaim-CQANDXVJ.js → buildAndBroadcastReclaim-XRWuJWVL.js} +48 -50
- package/dist/buildAndBroadcastReclaim-XRWuJWVL.js.map +1 -0
- package/dist/{challengeAssert-C3eMcM5Y.cjs → challengeAssert-BE6Wm4x1.cjs} +2 -2
- package/dist/challengeAssert-BE6Wm4x1.cjs.map +1 -0
- package/dist/{challengeAssert-B2otuf7y.js → challengeAssert-DUKSjirl.js} +3 -3
- package/dist/challengeAssert-DUKSjirl.js.map +1 -0
- package/dist/constants-BCg6O0PX.cjs +2 -0
- package/dist/constants-BCg6O0PX.cjs.map +1 -0
- package/dist/constants-CmDDuM3L.js +50 -0
- package/dist/constants-CmDDuM3L.js.map +1 -0
- package/dist/{index-BRsWXDlv.js → index-B-9aXMxk.js} +6 -6
- package/dist/{index-BRsWXDlv.js.map → index-B-9aXMxk.js.map} +1 -1
- package/dist/{index-C6avwx1s.cjs → index-Dn7RlsKK.cjs} +2 -2
- package/dist/{index-C6avwx1s.cjs.map → index-Dn7RlsKK.cjs.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +16 -16
- package/dist/pegin-registration-client-DLlaZbsZ.cjs +2 -0
- package/dist/pegin-registration-client-DLlaZbsZ.cjs.map +1 -0
- package/dist/{pegin-registration-client-Cvjk4ILq.js → pegin-registration-client-ZI0k10_3.js} +90 -96
- package/dist/pegin-registration-client-ZI0k10_3.js.map +1 -0
- package/dist/{primeVpAuth-D4UWXQ76.js → primeVpAuth-C-ET0XF4.js} +2 -2
- package/dist/{primeVpAuth-D4UWXQ76.js.map → primeVpAuth-C-ET0XF4.js.map} +1 -1
- package/dist/{primeVpAuth-CXNXYKrh.cjs → primeVpAuth-Ch-ig2My.cjs} +2 -2
- package/dist/{primeVpAuth-CXNXYKrh.cjs.map → primeVpAuth-Ch-ig2My.cjs.map} +1 -1
- package/dist/registration-records-CKc0OVuK.cjs +2 -0
- package/dist/registration-records-CKc0OVuK.cjs.map +1 -0
- package/dist/{registration-records-DJJC2NiO.js → registration-records-D39ApuHS.js} +141 -141
- package/dist/registration-records-D39ApuHS.js.map +1 -0
- package/dist/{signer-set-reader-GrFe_rsW.cjs → signer-set-reader-CJfV-GDz.cjs} +2 -2
- package/dist/{signer-set-reader-GrFe_rsW.cjs.map → signer-set-reader-CJfV-GDz.cjs.map} +1 -1
- package/dist/{signer-set-reader-CSUe92zE.js → signer-set-reader-DiwLeqik.js} +3 -3
- package/dist/{signer-set-reader-CSUe92zE.js.map → signer-set-reader-DiwLeqik.js.map} +1 -1
- package/dist/tbv/core/clients/eth/index.cjs +1 -1
- package/dist/tbv/core/clients/eth/index.js +4 -4
- package/dist/tbv/core/clients/eth/protocol-params-validation.d.ts.map +1 -1
- package/dist/tbv/core/clients/eth/registration-logs-error.d.ts +6 -6
- package/dist/tbv/core/clients/eth/registration-records.d.ts +1 -1
- package/dist/tbv/core/clients/eth/types.d.ts +12 -13
- package/dist/tbv/core/clients/eth/types.d.ts.map +1 -1
- package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts +1 -1
- package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts.map +1 -1
- package/dist/tbv/core/clients/index.cjs +1 -1
- package/dist/tbv/core/clients/index.js +6 -6
- package/dist/tbv/core/clients/vault-provider/status/index.cjs +1 -1
- package/dist/tbv/core/clients/vault-provider/status/index.js +1 -1
- package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts +5 -111
- package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts.map +1 -1
- package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts +2 -2
- package/dist/tbv/core/contracts/abis/vaultErrors.abi.json.d.ts +1 -1
- package/dist/tbv/core/contracts/index.cjs +1 -1
- package/dist/tbv/core/contracts/index.js +3 -3
- package/dist/tbv/core/deposit-terms/__tests__/rebuildDepositTermsCore.test.d.ts +1 -1
- package/dist/tbv/core/deposit-terms/commissionCeiling.d.ts +1 -1
- package/dist/tbv/core/deposit-terms/depositTerms.d.ts +5 -5
- package/dist/tbv/core/deposit-terms/rebuildDepositTermsCore.d.ts.map +1 -1
- package/dist/tbv/core/index.cjs +1 -1
- package/dist/tbv/core/index.js +16 -16
- package/dist/tbv/core/managers/index.cjs +1 -1
- package/dist/tbv/core/managers/index.js +2 -2
- package/dist/tbv/core/primitives/__tests__/vaultCoreVersion.test.d.ts +1 -1
- 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__/deriveExpectedPeginPayoutScriptPubKey.test.d.ts +1 -1
- package/dist/tbv/core/primitives/psbt/assertWasmPeginSizing.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/constants.d.ts +38 -13
- package/dist/tbv/core/primitives/psbt/constants.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/depositorClaim.d.ts +3 -6
- package/dist/tbv/core/primitives/psbt/depositorClaim.d.ts.map +1 -1
- package/dist/tbv/core/primitives/psbt/pegin.d.ts +3 -5
- package/dist/tbv/core/primitives/psbt/pegin.d.ts.map +1 -1
- package/dist/tbv/core/recovery/peginParamsCandidates.d.ts +1 -1
- package/dist/tbv/core/recovery/reconstructPeginParams.d.ts.map +1 -1
- package/dist/tbv/core/services/delegated-claim/__tests__/realWasmWatchtowerArtifacts.test.d.ts +2 -2
- package/dist/tbv/core/services/delegated-claim/assembleWatchtowerArtifacts.d.ts +2 -1
- package/dist/tbv/core/services/delegated-claim/assembleWatchtowerArtifacts.d.ts.map +1 -1
- package/dist/tbv/core/services/delegated-claim/deriveClaimerWotsKeypair.d.ts +1 -1
- package/dist/tbv/core/services/delegated-claim/deriveClaimerWotsKeypair.d.ts.map +1 -1
- package/dist/tbv/core/services/delegated-claim/planDelegatedClaimSigning.d.ts +2 -1
- package/dist/tbv/core/services/delegated-claim/planDelegatedClaimSigning.d.ts.map +1 -1
- package/dist/tbv/core/services/delegated-claim/readDelegatedClaimVaultContext.d.ts +1 -1
- package/dist/tbv/core/services/delegated-claim/readDelegatedClaimVaultContext.d.ts.map +1 -1
- package/dist/tbv/core/services/delegated-claim/readWatchtowerArtifacts.d.ts +3 -3
- package/dist/tbv/core/services/delegated-claim/readWatchtowerArtifacts.d.ts.map +1 -1
- package/dist/tbv/core/services/delegated-claim/types.d.ts +5 -6
- package/dist/tbv/core/services/delegated-claim/types.d.ts.map +1 -1
- package/dist/tbv/core/services/deposit/__tests__/signDepositorGraph.realGraph.test.d.ts +3 -3
- package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts.map +1 -1
- package/dist/tbv/core/services/index.cjs +1 -1
- package/dist/tbv/core/services/index.js +2 -2
- package/dist/tbv/core/wasm/index.cjs.map +1 -1
- package/dist/tbv/core/wasm/index.d.ts +8 -11
- package/dist/tbv/core/wasm/index.d.ts.map +1 -1
- package/dist/tbv/core/wasm/index.js.map +1 -1
- package/dist/tbv/index.cjs +1 -1
- package/dist/tbv/index.js +16 -16
- package/dist/toRefundInputs-BSQjDOK9.cjs +2 -0
- package/dist/toRefundInputs-BSQjDOK9.cjs.map +1 -0
- package/dist/{toRefundInputs-DH-1bRNY.js → toRefundInputs-BbbvPb2A.js} +175 -173
- package/dist/toRefundInputs-BbbvPb2A.js.map +1 -0
- package/dist/{types-BC2TGzcp.cjs → types-BnZIbDHb.cjs} +2 -2
- package/dist/types-BnZIbDHb.cjs.map +1 -0
- package/dist/{types-24A9Qoxb.js → types-K_aM5GZO.js} +39 -39
- package/dist/types-K_aM5GZO.js.map +1 -0
- package/dist/{verifyKeyPathSchnorrSignature-IIj3Z2se.js → verifyKeyPathSchnorrSignature-DPXOFOol.js} +2 -2
- package/dist/{verifyKeyPathSchnorrSignature-IIj3Z2se.js.map → verifyKeyPathSchnorrSignature-DPXOFOol.js.map} +1 -1
- package/dist/{verifyKeyPathSchnorrSignature-BRTpEH9X.cjs → verifyKeyPathSchnorrSignature-DcxCojp0.cjs} +2 -2
- package/dist/{verifyKeyPathSchnorrSignature-BRTpEH9X.cjs.map → verifyKeyPathSchnorrSignature-DcxCojp0.cjs.map} +1 -1
- package/dist/verifyScriptPathSchnorrSignature-CgDa9Rcg.cjs +2 -0
- package/dist/verifyScriptPathSchnorrSignature-CgDa9Rcg.cjs.map +1 -0
- package/dist/{verifyScriptPathSchnorrSignature-owu3BfyT.js → verifyScriptPathSchnorrSignature-D-fdi-sG.js} +462 -459
- package/dist/verifyScriptPathSchnorrSignature-D-fdi-sG.js.map +1 -0
- package/package.json +3 -3
- package/dist/BTCVaultRegistry.abi-BH2-LHxN.cjs.map +0 -1
- package/dist/BTCVaultRegistry.abi-BzNTa_EU.js.map +0 -1
- package/dist/PayoutManager-B1Ev0r7o.cjs.map +0 -1
- package/dist/PayoutManager-xEGvTbhL.js.map +0 -1
- package/dist/VaultErrors.abi-Boz4w97c.js +0 -5
- package/dist/VaultErrors.abi-DQ18kM0L.cjs +0 -2
- package/dist/buildAndBroadcastReclaim-CQANDXVJ.js.map +0 -1
- package/dist/buildAndBroadcastReclaim-DPk36Uhp.cjs +0 -2
- package/dist/buildAndBroadcastReclaim-DPk36Uhp.cjs.map +0 -1
- package/dist/challengeAssert-B2otuf7y.js.map +0 -1
- package/dist/challengeAssert-C3eMcM5Y.cjs.map +0 -1
- package/dist/constants-CAm10Qwp.cjs +0 -2
- package/dist/constants-CAm10Qwp.cjs.map +0 -1
- package/dist/constants-CvQZuxKv.js +0 -48
- package/dist/constants-CvQZuxKv.js.map +0 -1
- package/dist/pegin-registration-client-CdRyXP3j.cjs +0 -2
- package/dist/pegin-registration-client-CdRyXP3j.cjs.map +0 -1
- package/dist/pegin-registration-client-Cvjk4ILq.js.map +0 -1
- package/dist/registration-records-DJJC2NiO.js.map +0 -1
- package/dist/registration-records-XQMIKjGV.cjs +0 -2
- package/dist/registration-records-XQMIKjGV.cjs.map +0 -1
- package/dist/toRefundInputs-DH-1bRNY.js.map +0 -1
- package/dist/toRefundInputs-DRmK83fv.cjs +0 -2
- package/dist/toRefundInputs-DRmK83fv.cjs.map +0 -1
- package/dist/types-24A9Qoxb.js.map +0 -1
- package/dist/types-BC2TGzcp.cjs.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-CahYx5Td.cjs +0 -2
- package/dist/verifyScriptPathSchnorrSignature-CahYx5Td.cjs.map +0 -1
- package/dist/verifyScriptPathSchnorrSignature-owu3BfyT.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"toRefundInputs-DRmK83fv.cjs","sources":["../src/tbv/core/deposit-terms/claimSiblings.ts","../src/tbv/core/deposit-terms/depositTermsErrors.ts","../src/tbv/core/deposit-terms/fundedPrePeginFee.ts","../src/tbv/core/deposit-terms/rebuildDepositTermsCore.ts","../src/tbv/core/deposit-terms/rebuildDepositTermsForClaim.ts","../src/tbv/core/wots/errors.ts","../src/tbv/core/pegin-fingerprint/peginFingerprint.ts","../src/tbv/core/recovery/recoveryErrors.ts","../src/tbv/core/recovery/deriveHashlocksFromPrePegin.ts","../src/tbv/core/recovery/peginParamsCandidates.ts","../src/tbv/core/recovery/reconstructPeginParams.ts","../src/tbv/core/recovery/toRefundInputs.ts"],"sourcesContent":["/**\n * Sibling discovery for the claim-time terms rebuild — pure, fail-closed.\n *\n * A batch deposit registers every sibling in one transaction, so the target's\n * registration block holds them all: the siblings are the block's other\n * registrations by the same depositor whose `unsignedPrePeginTx` is the same\n * transaction. Completeness is backstopped by the core's auth-anchor check.\n *\n * @module deposit-terms/claimSiblings\n */\n\nimport { registrationPrePeginTxHash } from \"../clients/eth/registration-records\";\nimport type { PeginRegistrationRecord, VaultData } from \"../clients/eth/types\";\nimport type { RebuildSibling } from \"./rebuildDepositTermsCore\";\n\n/**\n * One batch member: the chain record plus its registration-log ceiling.\n *\n * @experimental\n */\nexport interface ClaimBatchMember {\n vault: VaultData;\n maxAcceptableCommissionBps: number;\n}\n\n/**\n * Fields that must be uniform across the batch: each sibling is stamped by its\n * own `submitPeginRequest`, so governance changes between registrations can\n * stamp them differently — and Gate 1 cannot see fields not encoded in the\n * HTLC outputs (timelocks, commission).\n */\nconst STAMPED_PROTOCOL_FIELDS = [\n \"vaultCoreVersion\",\n \"offchainParamsVersion\",\n \"appVaultKeepersVersion\",\n \"universalChallengersVersion\",\n] as const;\nconst STAMPED_ADDRESS_FIELDS = [\n \"applicationEntryPoint\",\n \"vaultProvider\",\n] as const;\n\n/** @experimental */\nexport function selectSiblingRegistrations(\n records: readonly PeginRegistrationRecord[],\n target: PeginRegistrationRecord,\n): PeginRegistrationRecord[] {\n const depositor = target.depositor.toLowerCase();\n const prePeginTxHash = registrationPrePeginTxHash(target).toLowerCase();\n // Depositor first, so only the depositor's own registrations are ever parsed.\n return records.filter(\n (r) =>\n r.vaultId !== target.vaultId &&\n r.depositor.toLowerCase() === depositor &&\n registrationPrePeginTxHash(r).toLowerCase() === prePeginTxHash,\n );\n}\n\n/** @experimental */\nexport function assertClaimBatchHomogeneous(\n target: ClaimBatchMember,\n siblings: readonly ClaimBatchMember[],\n): void {\n for (const sibling of siblings) {\n for (const field of STAMPED_PROTOCOL_FIELDS) {\n if (sibling.vault.protocol[field] !== target.vault.protocol[field]) {\n throw new Error(\n `Sibling vaults of this Pre-PegIn disagree on ${field} ` +\n `(${sibling.vault.protocol[field]} vs ${target.vault.protocol[field]}); ` +\n `the batch cannot be described by one set of deposit terms.`,\n );\n }\n }\n if (\n sibling.maxAcceptableCommissionBps !== target.maxAcceptableCommissionBps\n ) {\n throw new Error(\n `Sibling vaults of this Pre-PegIn disagree on maxAcceptableCommissionBps ` +\n `(${sibling.maxAcceptableCommissionBps} vs ${target.maxAcceptableCommissionBps}); ` +\n `the batch cannot be described by one set of deposit terms.`,\n );\n }\n for (const field of STAMPED_ADDRESS_FIELDS) {\n if (\n sibling.vault.basic[field].toLowerCase() !==\n target.vault.basic[field].toLowerCase()\n ) {\n throw new Error(\n `Sibling vaults of this Pre-PegIn disagree on ${field} ` +\n `(${sibling.vault.basic[field]} vs ${target.vault.basic[field]}); ` +\n `the batch cannot be described by one set of deposit terms.`,\n );\n }\n }\n }\n}\n\n/**\n * Sort by `htlcVout` and project into the core's sibling shape. htlcVout is\n * derived from array position downstream, so the vector must cover [0, N-1].\n *\n * @experimental\n */\nexport function orderClaimBatchByHtlcVout(\n members: readonly ClaimBatchMember[],\n): RebuildSibling[] {\n const ordered = [...members].sort(\n (a, b) => a.vault.protocol.htlcVout - b.vault.protocol.htlcVout,\n );\n ordered.forEach((member, i) => {\n if (member.vault.protocol.htlcVout !== i) {\n throw new Error(\n `Sibling discovery produced a non-contiguous HTLC vector ` +\n `(${ordered.map((m) => m.vault.protocol.htlcVout).join(\", \")}).`,\n );\n }\n });\n return ordered.map((m) => ({\n hashlock: m.vault.protocol.hashlock,\n amount: m.vault.basic.amount,\n }));\n}\n","/**\n * Typed rejection contract for deposit-terms approval. Providers cannot import\n * this class (no dependency edge between the packages), so the cross-package\n * contract is the error SHAPE on {@link DepositTermsApprover}. Consumers land\n * with the first provider (#2109) and its app error mapping (#2110).\n *\n * @module deposit-terms/depositTermsErrors\n */\n\n/** The `name` value providers must set on envelope rejections (the wire contract). */\nexport const DEPOSIT_TERMS_REJECTED_ERROR_NAME = \"DepositTermsRejectedError\";\n\n/** Why the terms were rejected before approval. */\nexport type DepositTermsRejectionReason = \"device-envelope\";\n\n/** SDK-owned typed rejection thrown when deposit terms fail pre-approval validation. */\nexport class DepositTermsRejectedError extends Error {\n readonly reason: DepositTermsRejectionReason;\n\n constructor(\n message: string,\n reason: DepositTermsRejectionReason = \"device-envelope\",\n ) {\n super(message);\n this.name = DEPOSIT_TERMS_REJECTED_ERROR_NAME;\n this.reason = reason;\n }\n}\n\n/**\n * Guard for app-side error mapping. Matches `instanceof` OR the documented\n * `name` — providers and foreign realms throw structurally-conforming plain\n * errors that `instanceof` cannot see.\n */\nexport function isDepositTermsRejectedError(\n err: unknown,\n): err is DepositTermsRejectedError {\n if (err instanceof DepositTermsRejectedError) return true;\n if (typeof err !== \"object\" || err === null) return false;\n const shaped = err as { name?: unknown; reason?: unknown };\n // The documented provider shape REQUIRES the reason; a name-only match is\n // a contract violation and propagates unnormalized.\n return (\n shaped.name === DEPOSIT_TERMS_REJECTED_ERROR_NAME &&\n shaped.reason === \"device-envelope\"\n );\n}\n","/**\n * Fee of a funded Pre-PegIn: Σ prevouts − Σ outputs, prevouts resolved from\n * the mempool API by display-order txid. Becomes the device's\n * `prepegin_max_fee` bound. Mirrors the vault app's\n * `resolveFundedTxFeeAndUtxos`, without the UTXO record the broadcast reuses.\n *\n * @module deposit-terms/fundedPrePeginFee\n */\n\nimport { Transaction } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\n\nimport { getUtxoInfo } from \"../clients/mempool\";\nimport { stripHexPrefix } from \"../primitives/utils/bitcoin\";\nimport { MAX_REASONABLE_FEE_SATS } from \"../utils/validation\";\n\n/**\n * @throws When the inputs do not cover the outputs, or the fee exceeds\n * `MAX_REASONABLE_FEE_SATS` (a manipulated prevout answer).\n * @experimental\n */\nexport async function computeFundedPrePeginFee(\n fundedPrePeginTxHex: string,\n mempoolApiUrl: string,\n): Promise<bigint> {\n const tx = Transaction.fromHex(stripHexPrefix(fundedPrePeginTxHex));\n const prevouts = await Promise.all(\n tx.ins.map((input) =>\n // Bitcoin stores the prev-txid in reverse (internal) byte order.\n getUtxoInfo(\n Buffer.from(input.hash).reverse().toString(\"hex\"),\n input.index,\n mempoolApiUrl,\n ),\n ),\n );\n const totalIn = prevouts.reduce((sum, u) => sum + BigInt(u.value), 0n);\n const totalOut = tx.outs.reduce((sum, o) => sum + BigInt(o.value), 0n);\n const fee = totalIn - totalOut;\n if (fee <= 0n) {\n throw new Error(\n `The funded Pre-PegIn transaction's inputs do not cover its outputs plus a fee ` +\n `(computed fee: ${fee} sats).`,\n );\n }\n if (fee > MAX_REASONABLE_FEE_SATS) {\n throw new Error(\n `The funded Pre-PegIn transaction's computed fee (${fee} sats) exceeds the maximum ` +\n `reasonable fee (${MAX_REASONABLE_FEE_SATS} sats); the mempool API may have ` +\n `returned manipulated prevout data.`,\n );\n }\n return fee;\n}\n","/**\n * Pure core of the resume-broadcast DepositTerms rebuild (#2220 Part 2).\n *\n * Takes plain chain-derived data (the app orchestrator does the chain reads +\n * sibling discovery) and: (1) asserts sibling completeness against the funded\n * tx's auth-anchor OP_RETURN, (2) recomputes the amount-independent sizing\n * (depositorClaimValue, peginMaxFee, anchor) via WASM, (3) byte-matches each\n * HTLC output's value + scriptPubKey against the funded tx (Gate 1), then (4)\n * projects into DepositTerms. No chain access, no browser state — unit-testable.\n *\n * btc-vault is the protocol source of truth (`compute_min_htlc_value`,\n * `derive_challengers_for`).\n */\n\nimport {\n computeMinClaimValue,\n computeMinPeginFee,\n getPrePeginHtlcConnectorInfo,\n peginP2aAnchorOutput,\n} from \"../wasm\";\nimport { Transaction } from \"bitcoinjs-lib\";\n\nimport { findAuthAnchorOpReturn } from \"../managers/pegin/assertAuthAnchorOpReturn\";\nimport { assertEncodedHtlcOutputsMatch } from \"../primitives/psbt/assertWasmPeginSizing\";\nimport { stripHexPrefix } from \"../primitives/utils/bitcoin\";\nimport { MAX_REASONABLE_PEGIN_VBYTES } from \"../utils/fee/constants\";\nimport { calculateBtcTxHash } from \"../utils/transaction/btcTxHash\";\n\nimport { buildDepositTerms } from \"./buildDepositTerms\";\nimport type { DepositTerms } from \"./depositTerms\";\n\n/** One HTLC in the shared Pre-PegIn tx, ordered by (and contiguous in) htlcVout. */\nexport interface RebuildSibling {\n /** 32-byte hex hashlock (0x prefix optional), per-vault (feeds the HTLC scriptPubKey). */\n hashlock: string;\n /** btc-vault `pegin_amount` for this sibling (satoshis). */\n amount: bigint;\n}\n\nexport interface RebuildDepositTermsCoreInput {\n /** Stamped tx-graph version (NOT chain-active). */\n vaultCoreVersion: number;\n /** Sibling HTLCs ordered by htlcVout; index === htlcVout (asserted by the app). */\n siblings: readonly RebuildSibling[];\n /** Funded Pre-PegIn tx hex. Gate 0 (hash vs prepeginTxid) is SELF-verified below — callers need not pre-verify. */\n fundedPrePeginTxHex: string;\n\n // Stamped-version participant data (already resolved + sorted by the app).\n depositorBtcPubkey: string;\n vaultProviderBtcPubkey: string;\n vaultKeeperBtcPubkeys: readonly string[];\n universalChallengerBtcPubkeys: readonly string[];\n\n // Version-locked scalars.\n protocolFeeRate: bigint;\n minPeginFeeRate: bigint;\n councilQuorum: number;\n councilSize: number;\n timelockPegin: number;\n timelockAssert: number;\n timelockRefund: number;\n\n // Pass-through into DepositTerms.\n prepeginTxid: string;\n /** Funded-tx fee (Σin − Σout), computed by the app; the device's `prepegin_max_fee` bound. */\n prepeginMaxFee: bigint;\n maxAcceptableCommissionBps: number;\n\n /** WASM network descriptor for scriptPubKey derivation. */\n network: Parameters<typeof getPrePeginHtlcConnectorInfo>[0][\"network\"];\n}\n\nexport async function rebuildDepositTermsCore(\n input: RebuildDepositTermsCoreInput,\n): Promise<DepositTerms> {\n const siblingCount = input.siblings.length;\n if (siblingCount === 0) {\n throw new Error(\n \"rebuildDepositTermsCore: at least one sibling is required\",\n );\n }\n for (const [i, sibling] of input.siblings.entries()) {\n if (sibling.amount <= 0n) {\n throw new Error(\n `rebuildDepositTermsCore: sibling[${i}] has non-positive on-chain pegin ` +\n `amount ${sibling.amount}; the chain-read vault record is invalid. Resume refused.`,\n );\n }\n }\n if (input.prepeginMaxFee <= 0n) {\n throw new Error(\n `rebuildDepositTermsCore: prepeginMaxFee must be > 0, got ${input.prepeginMaxFee}`,\n );\n }\n\n // Gate 0, self-verified: everything below trusts these bytes, and a\n // substituted tx replicating the HTLC outputs would pass Gate 1 with a\n // different fee/txid.\n const expectedTxid = stripHexPrefix(input.prepeginTxid).toLowerCase();\n const actualTxid = stripHexPrefix(\n calculateBtcTxHash(input.fundedPrePeginTxHex),\n ).toLowerCase();\n if (actualTxid !== expectedTxid) {\n throw new Error(\n `Funded Pre-PegIn tx hashes to ${actualTxid}, expected ${expectedTxid} ` +\n `(on-chain prepeginTxid). Resume refused.`,\n );\n }\n\n // Completeness anchor: the single auth-anchor OP_RETURN sits at vout === HTLC\n // count — the only guard against an indexer-lagged partial sibling set.\n const found = findAuthAnchorOpReturn(\n stripHexPrefix(input.fundedPrePeginTxHex),\n );\n if (found === undefined) {\n throw new Error(\n `Funded Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN ` +\n `commitment — it either predates auth anchoring or is malformed. The ` +\n `intent resume path requires the anchor to prove sibling completeness. ` +\n `Resume refused.`,\n );\n }\n if (found.vout !== siblingCount) {\n throw new Error(\n `Auth-anchor OP_RETURN at vout ${found.vout} does not match the ` +\n `discovered sibling count ${siblingCount}; the discovered sibling set ` +\n `does not cover this transaction's HTLC outputs (a lagging index can ` +\n `cause this — retry later). Resume refused.`,\n );\n }\n\n // Amount-independent sizing. Depositor-as-claimer: numLocalChallengers ===\n // numVks (VP excluded) — btc-vault graph.rs derive_challengers_for.\n const numVks = input.vaultKeeperBtcPubkeys.length;\n const numUcs = input.universalChallengerBtcPubkeys.length;\n const depositorClaimValue = await computeMinClaimValue(\n input.vaultCoreVersion,\n numVks,\n numUcs,\n input.councilQuorum,\n input.councilSize,\n input.protocolFeeRate,\n );\n const peginMaxFee = await computeMinPeginFee(\n input.vaultCoreVersion,\n numVks,\n numUcs,\n input.minPeginFeeRate,\n );\n const anchor = await peginP2aAnchorOutput(input.vaultCoreVersion);\n const anchorValue = anchor?.value ?? 0n;\n\n // Independent bounds on the WASM outputs (mirrors assertWasmPeginSizing):\n // Gate 1 only proves the DCV+fee+anchor SUM — these constrain the\n // decomposition the device is shown.\n if (depositorClaimValue <= 0n) {\n throw new Error(\n `WASM returned non-positive depositorClaimValue ${depositorClaimValue}; ` +\n `expected > 0. Resume refused.`,\n );\n }\n if (peginMaxFee <= 0n) {\n throw new Error(\n `WASM returned non-positive peginMaxFee ${peginMaxFee}; expected > 0. ` +\n `Resume refused.`,\n );\n }\n // Explicit anchor check: the sum bound alone would let a negative anchor\n // offset an inflated peginMaxFee (kept local, not inherited from the facade).\n if (anchorValue < 0n) {\n throw new Error(\n `WASM returned negative P2A anchor value ${anchorValue}. Resume refused.`,\n );\n }\n const impliedReserve = peginMaxFee + anchorValue;\n const maxImpliedReserve = input.minPeginFeeRate * MAX_REASONABLE_PEGIN_VBYTES;\n if (impliedReserve <= 0n || impliedReserve > maxImpliedReserve) {\n throw new Error(\n `WASM implied PegIn reserve ${impliedReserve} sat is outside ` +\n `(0, ${maxImpliedReserve}] (minPeginFeeRate=${input.minPeginFeeRate} × ` +\n `${MAX_REASONABLE_PEGIN_VBYTES} vbytes). Resume refused.`,\n );\n }\n\n // Gate 1: per sibling, value = amount + DCV + peginMaxFee + anchor (btc-vault\n // compute_min_htlc_value) + scriptPubKey from the on-chain hashlock,\n // byte-matched against outputs 0..N-1.\n const expectedHtlcValues = input.siblings.map(\n (s) => s.amount + depositorClaimValue + peginMaxFee + anchorValue,\n );\n const expectedHtlcScriptPubKeys = await Promise.all(\n input.siblings.map(async (s) => {\n const connector = await getPrePeginHtlcConnectorInfo({\n txGraphVersion: input.vaultCoreVersion,\n depositorPubkey: input.depositorBtcPubkey,\n vaultProviderPubkey: input.vaultProviderBtcPubkey,\n vaultKeeperPubkeys: [...input.vaultKeeperBtcPubkeys],\n universalChallengerPubkeys: [...input.universalChallengerBtcPubkeys],\n hashlock: stripHexPrefix(s.hashlock),\n timelockRefund: input.timelockRefund,\n network: input.network,\n });\n return connector.scriptPubKey;\n }),\n );\n const fundedOutputs = Transaction.fromHex(\n stripHexPrefix(input.fundedPrePeginTxHex),\n ).outs.map((o) => ({ value: o.value, script: o.script }));\n assertEncodedHtlcOutputsMatch(\n fundedOutputs,\n expectedHtlcValues,\n expectedHtlcScriptPubKeys,\n );\n\n return buildDepositTerms({\n vaultCoreVersion: input.vaultCoreVersion,\n protocolFeeRate: input.protocolFeeRate,\n timelockPegin: input.timelockPegin,\n timelockAssert: input.timelockAssert,\n timelockRefund: input.timelockRefund,\n prepeginTxid: input.prepeginTxid,\n prepeginMaxFee: input.prepeginMaxFee,\n vaultProviderBtcPubkey: input.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: input.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys: input.universalChallengerBtcPubkeys,\n maxAcceptableCommissionBps: input.maxAcceptableCommissionBps,\n peginAmounts: input.siblings.map((s) => s.amount),\n depositorClaimValue,\n peginMaxFee,\n });\n}\n","/**\n * Rebuild a {@link DepositTerms} at claim time, from chain and mempool only.\n *\n * The delegated claim can run months after the deposit, with no in-memory\n * terms and possibly no vault provider. An approval wallet still has to load\n * this vault's intent to sign the Assert and the depositor Payout, and the\n * device recomputes the PegIn txid from the intent, so every value here must\n * be the one the deposit was built with: the stamped versions and rosters,\n * the ceiling from the registration log, the siblings from the same log, the\n * funded fee from the transaction the chain saw.\n *\n * Takes the `readDelegatedClaimVaultContext` read rather than a vault id: that\n * read already fetched the vault record, the registration block, the\n * participant keys and the stamped params, and on a public RPC every repeat is\n * another chance of a spurious empty answer. Only the siblings still need a\n * reader.\n *\n * No lifecycle gate: the vault app's resume rebuild refuses non-PENDING\n * vaults and closed ack windows because it is about to finish a deposit; a\n * claimable vault is REDEEMED and long past both. The homogeneity and\n * contiguity checks are kept.\n *\n * @module deposit-terms/rebuildDepositTermsForClaim\n */\n\nimport { registrationPrePeginTxHash } from \"../clients/eth/registration-records\";\nimport type { VaultRegistryReader } from \"../clients/eth/types\";\nimport {\n canonicalizeBtcPubkey,\n stripHexPrefix,\n} from \"../primitives/utils/bitcoin\";\nimport type { DelegatedClaimVaultRead } from \"../services/delegated-claim/readDelegatedClaimVaultContext\";\nimport { calculateBtcTxHash } from \"../utils/transaction/btcTxHash\";\nimport {\n assertClaimBatchHomogeneous,\n orderClaimBatchByHtlcVout,\n selectSiblingRegistrations,\n type ClaimBatchMember,\n} from \"./claimSiblings\";\nimport type { DepositTerms } from \"./depositTerms\";\nimport { computeFundedPrePeginFee } from \"./fundedPrePeginFee\";\nimport {\n rebuildDepositTermsCore,\n type RebuildDepositTermsCoreInput,\n} from \"./rebuildDepositTermsCore\";\n\n/** @experimental */\nexport interface RebuildDepositTermsForClaimParams {\n /** The vault read this rebuild reuses instead of re-reading the chain. */\n read: DelegatedClaimVaultRead;\n /**\n * The connected wallet's own key (compressed or x-only): refused unless it\n * is the vault's depositor. Passing the on-chain key here makes that check\n * vacuous.\n */\n depositorBtcPubkey: string;\n /**\n * Funded Pre-PegIn hex, e.g. `getTxHex(prepeginTxid, mempoolApiUrl)`.\n * Hash-checked against the vault's `prePeginTxHash` here before any mempool\n * lookup, and again by the core (Gate 0).\n */\n fundedPrePeginTxHex: string;\n /** Reads the sibling vaults of the batch; the target is already in `read`. */\n siblingReader: Pick<VaultRegistryReader, \"getVaultData\">;\n /** Mempool API base URL, for the prevouts the fee is computed from. */\n mempoolApiUrl: string;\n network: RebuildDepositTermsCoreInput[\"network\"];\n}\n\n/**\n * @throws When the wallet key is not the depositor's, the hex is not the\n * vault's Pre-PegIn, a sibling is registered against a different\n * Pre-PegIn than its log records, the siblings disagree on a stamped\n * field or are non-contiguous, the fee is out of bounds, or the core\n * refuses (see `rebuildDepositTermsCore`).\n * A sibling registered in another block is missing from this read and\n * surfaces as the core's auth-anchor refusal, whose message suggests a\n * lagging index and a retry: on this path there is no index, and a\n * retry cannot help — that sibling must be registered in the same block.\n * @experimental\n */\nexport async function rebuildDepositTermsForClaim(\n params: RebuildDepositTermsForClaimParams,\n): Promise<DepositTerms> {\n const { read } = params;\n const connectedDepositor = canonicalizeBtcPubkey(params.depositorBtcPubkey);\n if (connectedDepositor !== read.context.depositorBtcPubkey) {\n throw new Error(\n `Connected wallet key is not the vault's depositor key; select the account ` +\n `that made the deposit.`,\n );\n }\n\n const prepeginTxid = stripHexPrefix(read.prePeginTxHash).toLowerCase();\n const actualTxid = stripHexPrefix(\n calculateBtcTxHash(params.fundedPrePeginTxHex),\n ).toLowerCase();\n if (actualTxid !== prepeginTxid) {\n throw new Error(\n `Funded Pre-PegIn tx hashes to ${actualTxid}, expected ${prepeginTxid} (on-chain prePeginTxHash).`,\n );\n }\n\n const siblingMembers: ClaimBatchMember[] = await Promise.all(\n selectSiblingRegistrations(\n read.registrationRecords,\n read.registrationRecord,\n ).map(async (record) => {\n const vault = await params.siblingReader.getVaultData(record.vaultId);\n if (\n vault.protocol.prePeginTxHash.toLowerCase() !==\n registrationPrePeginTxHash(record).toLowerCase()\n ) {\n throw new Error(\n `Sibling ${record.vaultId} is registered against a different Pre-PegIn on chain ` +\n `than its registration log records; refusing an inconsistent node.`,\n );\n }\n return {\n vault,\n maxAcceptableCommissionBps: record.maxAcceptableCommissionBps,\n };\n }),\n );\n const targetMember: ClaimBatchMember = {\n vault: read.vault,\n maxAcceptableCommissionBps:\n read.registrationRecord.maxAcceptableCommissionBps,\n };\n assertClaimBatchHomogeneous(targetMember, siblingMembers);\n const siblings = orderClaimBatchByHtlcVout([targetMember, ...siblingMembers]);\n\n const prepeginMaxFee = await computeFundedPrePeginFee(\n params.fundedPrePeginTxHex,\n params.mempoolApiUrl,\n );\n\n return rebuildDepositTermsCore({\n vaultCoreVersion: read.vault.protocol.vaultCoreVersion,\n siblings,\n fundedPrePeginTxHex: params.fundedPrePeginTxHex,\n depositorBtcPubkey: connectedDepositor,\n vaultProviderBtcPubkey:\n read.participantKeys.vaultProvider.operationBtcPubkey,\n vaultKeeperBtcPubkeys: read.participantKeys.vaultKeeperOperationKeysSorted,\n universalChallengerBtcPubkeys:\n read.participantKeys.universalChallengerOperationKeysSorted,\n protocolFeeRate: read.offchainParams.feeRate,\n minPeginFeeRate: read.offchainParams.minPeginFeeRate,\n councilQuorum: read.offchainParams.councilQuorum,\n councilSize: read.offchainParams.securityCouncilKeys.length,\n timelockPegin: read.context.timelockPegin,\n timelockAssert: read.context.timelockAssert,\n timelockRefund: read.offchainParams.tRefund,\n prepeginTxid,\n prepeginMaxFee,\n // The submitted ceiling, verbatim: the device must see the terms the\n // depositor originally approved.\n maxAcceptableCommissionBps:\n read.registrationRecord.maxAcceptableCommissionBps,\n network: params.network,\n });\n}\n","/**\n * Check whether an error from the vault provider indicates that the\n * submitted WOTS public key hash does not match the on-chain\n * commitment. This signals that the wrong wallet is connected (its\n * `deriveContextHash` produces a different vault root and therefore\n * different WOTS keys).\n */\nexport function isWotsMismatchError(error: unknown): boolean {\n const msg = (\n error instanceof Error\n ? error.message\n : typeof error === \"string\"\n ? error\n : \"\"\n ).toLowerCase();\n\n return (\n msg.includes(\"wots\") &&\n msg.includes(\"hash\") &&\n msg.includes(\"does not match\")\n );\n}\n","/**\n * Canonical peg-in configuration fingerprint: the commitment a depositor sends\n * with a peg-in registration so the registry can prove, at inclusion, that the\n * protocol state it is about to bond the vault to is the state the Bitcoin lock\n * was actually built from.\n *\n * ## Why it exists\n *\n * Seven values are resolved live when a peg-in request is included, and every\n * one of them changes the bytes a depositor must have built: the vault\n * provider's operation-BTC key, the vault-keeper and universal-challenger key\n * epochs, the two roster versions (which members are in the HTLC all-party leaf\n * at all), the off-chain params version (`tRefund` in the refund leaf,\n * `minPeginFeeRate` in the output value) and the vault core version (the PegIn\n * output count, so the P2A anchor term in the value). A rotation, roster change\n * or version bump landing between the depositor's build and inclusion would\n * bond the vault to bytes the funded HTLC does not commit to. The registry\n * recomputes this fingerprint and reverts with `PeginFingerprintChanged` rather\n * than accepting such a request.\n *\n * ## Reproducing the contract exactly\n *\n * The encoding is `abi.encode`, never `abi.encodePacked` — the two produce\n * completely different bytes. Under `abi.encode` every field here is static and\n * occupies one left-padded 32-byte word, so the declared integer *width* never\n * reaches the output: encoding the tuple with all-`uint256` slots yields a\n * byte-identical hash. Only the field ORDER, the field COUNT, and whether a\n * type is static or dynamic can change the result. The widths in\n * {@link PeginFingerprintInput} therefore document the contract's own\n * declarations and bound the accepted inputs; they are not what makes the bytes\n * come out right.\n *\n * Mirrors `_peginFingerprint` in `src/protocol/lib/PeginLogic.sol` of\n * `babylonlabs-io/vault-contracts-aave-v4`. Pinned byte-for-byte against that\n * repository's committed vectors — see\n * `__tests__/peginFingerprint.golden.test.ts`.\n *\n * @module pegin-fingerprint/peginFingerprint\n */\n\nimport {\n encodeAbiParameters,\n isAddress,\n keccak256,\n toHex,\n zeroAddress,\n type Address,\n type Hex,\n} from \"viem\";\n\n/**\n * Domain-separation string hashed into every fingerprint, so the commitment\n * cannot be replayed as a different one. Matches the contract's\n * `PEGIN_FINGERPRINT_DOMAIN` preimage.\n */\nexport const PEGIN_FINGERPRINT_DOMAIN_PREIMAGE = \"TBV.PeginFingerprint.v1\";\n\n/**\n * `keccak256(\"TBV.PeginFingerprint.v1\")`, the first word of the encoded\n * preimage.\n *\n * Derived from {@link PEGIN_FINGERPRINT_DOMAIN_PREIMAGE} rather than pasted as\n * a hex literal, so the string that defines it stays visible. The golden test\n * pins the derived value against the constant the contract's vector file\n * publishes, so a change to either side is still caught.\n */\nexport const PEGIN_FINGERPRINT_DOMAIN: Hex = keccak256(\n toHex(PEGIN_FINGERPRINT_DOMAIN_PREIMAGE),\n);\n\n/** Inclusive upper bound of Solidity `uint16`, the width of all four versions. */\nconst UINT16_MAX = 65_535;\n/** Inclusive upper bound of Solidity `uint64`, the width of both key epochs. */\nconst UINT64_MAX = 2n ** 64n - 1n;\n/** Inclusive upper bound of Solidity `uint256`, the width of `block.chainid`. */\nconst UINT256_MAX = 2n ** 256n - 1n;\n/** A `bytes32` value as viem accepts it: `0x` followed by 64 hex digits. */\nconst BYTES32_PATTERN = /^0x[0-9a-fA-F]{64}$/;\n/**\n * Lowest `vaultCoreVersion` any live contract reports: the setter on\n * `ProtocolParams` rejects 0, so a 0 can only be a mis-decoded read.\n *\n * Mirrors the bound `assertValidVaultCoreVersion` applies in\n * `primitives/vaultCoreVersion.ts`; the two must move together. That function\n * is not called here because it throws a bare `Error`, which would put a second\n * error type into a module whose whole validation surface is\n * {@link PeginFingerprintInputError}.\n */\nconst VAULT_CORE_VERSION_MIN = 1;\n\n/**\n * Protocol state a Pre-PegIn transaction commits to, one field per encoded\n * word.\n *\n * Declared in encoding order so the interface reads as the specification does.\n * Reordering these fields does not change the output — the encoder names each\n * one explicitly — but keeping them aligned makes a divergence from the\n * contract visible on sight.\n */\nexport interface PeginFingerprintInput {\n /** `block.chainid` of the chain the registry is deployed on. */\n chainId: bigint;\n /**\n * The `BTCVaultRegistry` address, which the contract encodes as\n * `address(this)`. EIP-55 checksum casing is irrelevant to the encoded word\n * and is not required here; see {@link encodePeginFingerprintPreimage}.\n */\n registryAddress: Address;\n /**\n * The vault provider's RESOLVED operation-BTC key, 32 bytes, `0x`-prefixed.\n *\n * The resolved key, not an epoch counter: the VP epoch is one registry-wide\n * counter that ANY provider's key or payout append bumps, so committing to it\n * would let any registered provider invalidate every in-flight Pre-PegIn\n * protocol-wide. Only the chosen provider's key reaches the HTLC leaf, so\n * that is what is committed.\n *\n * Note the SDK resolves this key as an x-only pubkey WITHOUT a `0x` prefix\n * (`OnChainBtcPubkey`); callers add the prefix.\n */\n vaultProviderBtcKey: Hex;\n /** Vault-keeper operation-key epoch for this application (`uint64`). */\n appKeeperKeyEpoch: bigint;\n /** Universal-challenger operation-key epoch (`uint64`). */\n ucKeyEpoch: bigint;\n /** Roster version selecting which vault keepers are in the leaf (`uint16`). */\n appVaultKeepersVersion: number;\n /** Roster version selecting which universal challengers are in the leaf (`uint16`). */\n universalChallengersVersion: number;\n /** Off-chain params version: `tRefund` and `minPeginFeeRate` (`uint16`). */\n offchainParamsVersion: number;\n /** Vault core (tx-graph) version: the PegIn output count (`uint16`). */\n vaultCoreVersion: number;\n}\n\n/** An input field is missing, malformed, or outside the width the contract declares for it. */\nexport class PeginFingerprintInputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PeginFingerprintInputError\";\n }\n}\n\n/**\n * Recognise the error above, including across a module boundary.\n *\n * Every message it carries names an internal field and the width it broke, so a\n * consumer needs to be able to catch it and substitute its own copy rather than\n * show the depositor what went wrong internally. `instanceof` alone fails\n * across duplicate module copies and test mocks, so the name is the fallback —\n * the same pattern the deposit-path drift guards use.\n */\nexport function isPeginFingerprintInputError(\n err: unknown,\n): err is PeginFingerprintInputError {\n return (\n err instanceof PeginFingerprintInputError ||\n (err instanceof Error && err.name === \"PeginFingerprintInputError\")\n );\n}\n\n/**\n * The type is checked before the range, and deliberately so.\n *\n * A purely relational guard (`value < 0n || value > max`) is not a guard at\n * all for a non-bigint: every comparison against `undefined`, `null` and `NaN`\n * evaluates `false`, so all three slip through, and `\"7\"` and `true` slip\n * through AND then encode — as 7 and as 1 — producing a well-formed\n * fingerprint from a value nobody supplied. TypeScript does not close this;\n * a JS consumer, a snapshot object missing a key, or an unawaited read all\n * reach here.\n */\nfunction assertUnsignedRange(\n field: string,\n value: bigint,\n max: bigint,\n solidityType: string,\n): void {\n if (typeof value !== \"bigint\") {\n throw new PeginFingerprintInputError(\n `${field} must be a bigint (Solidity ${solidityType}), got ${typeof value}`,\n );\n }\n if (value < 0n || value > max) {\n throw new PeginFingerprintInputError(\n `${field} must fit Solidity ${solidityType} (0..${max}), got ${value}`,\n );\n }\n}\n\nfunction assertUint16(field: string, value: number): void {\n if (!Number.isInteger(value) || value < 0 || value > UINT16_MAX) {\n throw new PeginFingerprintInputError(\n `${field} must be an integer fitting Solidity uint16 (0..${UINT16_MAX}), got ${value}`,\n );\n }\n}\n\n/**\n * Validate a `bytes32` field and return it lowercased.\n *\n * viem echoes the caller's hex casing straight into the encoded output, so an\n * upper-case key would yield a correct fingerprint (keccak hashes bytes, not\n * text) beside a preimage that no longer compares equal to the contract's.\n * That would defeat the one job {@link encodePeginFingerprintPreimage} has.\n */\nfunction normalizeBytes32(field: string, value: Hex): Hex {\n if (!BYTES32_PATTERN.test(value)) {\n throw new PeginFingerprintInputError(\n `${field} must be 32 bytes as 0x-prefixed hex (66 characters), got \"${value}\"`,\n );\n }\n return value.toLowerCase() as Hex;\n}\n\n/**\n * Validate the registry address and return it in the form the ABI word encodes.\n *\n * EIP-55 mixed-case is a display checksum over the same 20 bytes, and Solidity\n * never sees it. viem does: `encodeAbiParameters` rejects a mixed-case address\n * whose checksum does not verify, which would make legitimate inputs — the\n * contract's own `maximum_field_values` vector among them — fail to encode. So\n * the checksum is not enforced and the value is lowercased before encoding.\n *\n * This is normalisation, not a fallback: an address that is not 20 bytes of hex\n * is still rejected, loudly, before anything is encoded, as is the zero address\n * (the shape an unresolved contract-address read takes).\n */\nfunction normalizeRegistryAddress(registryAddress: Address): Address {\n if (!isAddress(registryAddress, { strict: false })) {\n throw new PeginFingerprintInputError(\n `registryAddress must be a 20-byte 0x-prefixed address, got \"${registryAddress}\"`,\n );\n }\n const normalized = registryAddress.toLowerCase() as Address;\n if (normalized === zeroAddress) {\n throw new PeginFingerprintInputError(\n \"registryAddress must not be the zero address; a zero here means the registry address was never resolved\",\n );\n }\n return normalized;\n}\n\n/**\n * The encoded tuple, as one list so the ordering lives in exactly one place.\n *\n * Not re-exported from the module barrel — this is internal, and exists in\n * this shape so the golden test can render it back into the type string the\n * contract's vector file publishes and compare the two. That comparison is a\n * second, independent check on the field order, one that does not depend on\n * the sample values in the vectors.\n */\nexport const PEGIN_FINGERPRINT_ABI_PARAMETERS = [\n { name: \"domain\", type: \"bytes32\" },\n { name: \"chainId\", type: \"uint256\" },\n { name: \"registry\", type: \"address\" },\n { name: \"vaultProviderBtcKey\", type: \"bytes32\" },\n { name: \"appKeeperKeyEpoch\", type: \"uint64\" },\n { name: \"ucKeyEpoch\", type: \"uint64\" },\n { name: \"appVaultKeepersVersion\", type: \"uint16\" },\n { name: \"universalChallengersVersion\", type: \"uint16\" },\n { name: \"offchainParamsVersion\", type: \"uint16\" },\n { name: \"vaultCoreVersion\", type: \"uint16\" },\n] as const;\n\n/**\n * The `abi.encode` preimage the contract hashes — ten 32-byte words, 320 bytes.\n *\n * Exposed alongside {@link computePeginFingerprint} because a fingerprint\n * mismatch is otherwise two opaque hashes: comparing preimages word by word\n * localises the disagreement to a field. The contract's vector file ships the\n * same preimage next to each hash for exactly that reason.\n *\n * Three fields are held to a tighter bound than the contract's own width — a\n * zero `chainId`, a zero `registryAddress`, and a `vaultCoreVersion` below 1 —\n * because for each of them a zero is unreachable on-chain and so can only mean\n * a read that failed or was mis-decoded. No chain has id 0, no registry lives\n * at the zero address, and\n * `activeVaultCoreVersion()` is documented `uint16 >= 1` with a setter that\n * rejects 0. Encoding any of them would produce a well-formed fingerprint that\n * cannot ever match, turning a local mistake into an opaque on-chain revert.\n *\n * The three roster and params versions are NOT tightened: 0 is a legitimate\n * value on those axes.\n *\n * @throws {PeginFingerprintInputError} If any field is missing, malformed, or\n * outside the accepted range, naming the field and what was expected.\n */\nexport function encodePeginFingerprintPreimage(\n input: PeginFingerprintInput,\n): Hex {\n assertUnsignedRange(\"chainId\", input.chainId, UINT256_MAX, \"uint256\");\n if (input.chainId === 0n) {\n throw new PeginFingerprintInputError(\n \"chainId must not be 0; a zero here means the chain id was never resolved\",\n );\n }\n const registry = normalizeRegistryAddress(input.registryAddress);\n const vaultProviderBtcKey = normalizeBytes32(\n \"vaultProviderBtcKey\",\n input.vaultProviderBtcKey,\n );\n assertUnsignedRange(\n \"appKeeperKeyEpoch\",\n input.appKeeperKeyEpoch,\n UINT64_MAX,\n \"uint64\",\n );\n assertUnsignedRange(\"ucKeyEpoch\", input.ucKeyEpoch, UINT64_MAX, \"uint64\");\n assertUint16(\"appVaultKeepersVersion\", input.appVaultKeepersVersion);\n assertUint16(\n \"universalChallengersVersion\",\n input.universalChallengersVersion,\n );\n assertUint16(\"offchainParamsVersion\", input.offchainParamsVersion);\n assertUint16(\"vaultCoreVersion\", input.vaultCoreVersion);\n if (input.vaultCoreVersion < VAULT_CORE_VERSION_MIN) {\n throw new PeginFingerprintInputError(\n `vaultCoreVersion must be at least ${VAULT_CORE_VERSION_MIN}; ` +\n `${input.vaultCoreVersion} means the version was never resolved`,\n );\n }\n\n // Field order is the whole specification. The parameter list, this value\n // list, and the contract's `abi.encode(...)` call move together.\n return encodeAbiParameters(PEGIN_FINGERPRINT_ABI_PARAMETERS, [\n PEGIN_FINGERPRINT_DOMAIN,\n input.chainId,\n registry,\n vaultProviderBtcKey,\n input.appKeeperKeyEpoch,\n input.ucKeyEpoch,\n input.appVaultKeepersVersion,\n input.universalChallengersVersion,\n input.offchainParamsVersion,\n input.vaultCoreVersion,\n ]);\n}\n\n/**\n * The fingerprint to send as `expectedFingerprint` on a peg-in registration.\n *\n * Must equal what the registry recomputes at inclusion, byte for byte — the\n * comparison is exact equality, never \"no older than\", because resolving at a\n * superseded epoch would bond a new vault to a retired key.\n *\n * @throws {PeginFingerprintInputError} If any field is outside the width the\n * contract declares for it.\n */\nexport function computePeginFingerprint(input: PeginFingerprintInput): Hex {\n return keccak256(encodePeginFingerprintPreimage(input));\n}\n","/**\n * Typed failures for Pre-PegIn parameter recovery (#2203).\n *\n * Split by who can act on them. A root mismatch is user-fixable — wrong\n * wallet, wrong account or wrong network — and must be distinguishable from\n * a search that found nothing, which is ours. Without the split both look\n * identical to the caller.\n *\n * @module recovery/recoveryErrors\n */\n\n/**\n * The re-derived vault root does not match the funded Pre-PegIn's auth-anchor\n * OP_RETURN commitment.\n *\n * The root is bound to the wallet seed, the derivation account AND the\n * network (the wallet's `deriveContextHash` folds the connected pubkey and the\n * canonical network name into the HKDF `info`), so all three must match the\n * ones that created the deposit.\n */\nexport class VaultRootMismatchError extends Error {\n constructor(\n readonly derivedAuthAnchorHash: string,\n readonly onChainAuthAnchorHash: string,\n ) {\n super(\n `Re-derived vault root does not match this Pre-PegIn: derived ` +\n `auth-anchor hash ${derivedAuthAnchorHash}, transaction commits to ` +\n `${onChainAuthAnchorHash}. Connect the same wallet, on the same ` +\n `account and the same network, that created the deposit.`,\n );\n this.name = \"VaultRootMismatchError\";\n }\n}\n\n/**\n * The Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN.\n *\n * The anchor sits at `vout === htlcCount`, and it is the only structural\n * signal for how many HTLC outputs the transaction funds. Without it the\n * vault count would have to be guessed, so recovery refuses rather than\n * deriving the wrong number of hashlocks.\n */\nexport class UnanchoredPrePeginError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"UnanchoredPrePeginError\";\n }\n}\n\n/**\n * No candidate parameter set reproduces the funded Pre-PegIn's HTLC outputs.\n *\n * Either the true parameters are outside the enumerated space — an operator\n * roster that rotated more than once has no chain-reachable historical read —\n * or the transaction is not one of ours.\n */\nexport class PeginParamsNotFoundError extends Error {\n constructor(\n readonly candidatesTried: number,\n /** A bounded sample of per-candidate rejection reasons, for diagnosis. */\n readonly sampleRejections: readonly string[],\n /** Versions that could not be read, the likeliest reason for no match. */\n readonly unresolvedLabels: readonly string[] = [],\n ) {\n super(\n `No candidate parameter set reproduces this Pre-PegIn's HTLC outputs ` +\n `(${candidatesTried} candidate(s) tried). ` +\n (unresolvedLabels.length > 0\n ? `${unresolvedLabels.length} version(s) could not be resolved and ` +\n `may hold the answer: ${unresolvedLabels.join(\" | \")}. `\n : \"\") +\n `Sample rejections: ${sampleRejections.join(\" | \")}`,\n );\n this.name = \"PeginParamsNotFoundError\";\n }\n}\n\n/**\n * More than one candidate reproduces the funded Pre-PegIn. Fail closed.\n *\n * Every survivor byte-matched the SAME funded outputs, so they agree on each\n * HTLC scriptPubKey and on the total value of each output, and would produce\n * the same refund transaction. What they disagree on is the SPLIT of that\n * value into `peginAmount` and reserve, and the version stamps that determine\n * it — neither of which the transaction carries any evidence of.\n */\nexport class PeginParamsAmbiguousError extends Error {\n constructor(readonly survivorLabels: readonly string[]) {\n super(\n `${survivorLabels.length} candidate parameter sets reproduce this ` +\n `Pre-PegIn's HTLC outputs, so the vault's stamped versions cannot be ` +\n `determined: ${survivorLabels.join(\" | \")}. Reconstruction refused.`,\n );\n this.name = \"PeginParamsAmbiguousError\";\n }\n}\n\n/**\n * Exactly one candidate matched, but the candidate space was known to be\n * incomplete. Fail closed.\n *\n * Uniqueness only detects a wrong answer when the right answer is ALSO in the\n * space. If the true version could not be read, a different version sharing\n * the same `timelockRefund` and participants matches the transaction just as\n * well — the search subtracts that candidate's reserve and the verifier adds\n * the same reserve back, so it survives — and the sole survivor would be\n * returned with the wrong version stamps and the wrong `peginAmount` split.\n *\n * Resolve the versions below and search again rather than trusting the match.\n */\nexport class PeginParamsIncompleteSpaceError extends Error {\n constructor(\n readonly matchedLabel: string,\n readonly unresolvedLabels: readonly string[],\n ) {\n super(\n `A candidate matched this Pre-PegIn (${matchedLabel}), but ` +\n `${unresolvedLabels.length} version(s) could not be resolved, so the ` +\n `search space did not provably contain the true parameters: ` +\n `${unresolvedLabels.join(\" | \")}. A version sharing the matched ` +\n `timelockRefund and participants is indistinguishable from the true ` +\n `one, so the match cannot be trusted. Reconstruction refused.`,\n );\n this.name = \"PeginParamsIncompleteSpaceError\";\n }\n}\n\n/**\n * A WASM sizing call returned a value no valid parameter set can produce.\n *\n * Raised before the value is consumed, and deliberately NOT treated as a\n * candidate rejection: it indicts the binary rather than the candidate, so it\n * escapes the search instead of being counted as one more parameter set that\n * did not match.\n */\nexport class PeginSizingIntegrityError extends Error {\n constructor(message: string) {\n super(`${message}. Reconstruction refused.`);\n this.name = \"PeginSizingIntegrityError\";\n }\n}\n","/**\n * Re-derive a stranded deposit's per-vault hashlocks from the wallet and the\n * funded Pre-PegIn transaction alone (#2203).\n *\n * An Ethereum reorg that drops the registration takes the vault row with it,\n * so the depositor pubkey, the HTLC vout and the hashlocks are gone. All three\n * are recoverable without a single `vaultId`-keyed read: the depositor pubkey\n * comes from the connected wallet, the vault count from the transaction's\n * auth-anchor OP_RETURN vout, and the hashlocks from the same HKDF pipeline the\n * deposit used.\n *\n * The parameter search that turns these hashlocks back into a refundable\n * template lives in `reconstructPeginParams` and needs no wallet.\n *\n * @module recovery/deriveHashlocksFromPrePegin\n */\n\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport { findAuthAnchorOpReturn } from \"../managers/pegin/assertAuthAnchorOpReturn\";\nimport { expandPerVaultSecrets } from \"../managers/pegin/expandPerVaultSecrets\";\nimport {\n hexToUint8Array,\n processPublicKeyToXOnly,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../primitives/utils/bitcoin\";\nimport {\n deriveVaultRoot,\n expandAuthAnchor,\n parseFundingOutpointsFromTx,\n type DeriveContextHashCapableWallet,\n} from \"../vault-secrets\";\n\nimport {\n UnanchoredPrePeginError,\n VaultRootMismatchError,\n} from \"./recoveryErrors\";\n\nexport interface DeriveHashlocksFromPrePeginInput {\n /** Any wallet implementing `deriveContextHash` — the depositor's own. */\n wallet: DeriveContextHashCapableWallet;\n /**\n * Depositor BTC public key, read from the CONNECTED WALLET. The reorg\n * destroyed the row that would normally supply it, and taking it from any\n * chain read would defeat the recovery.\n *\n * Accepted in whatever form the wallet hands back — x-only, 33-byte\n * compressed or 65-byte uncompressed, `0x` optional — and narrowed to x-only\n * here. Wallets return the compressed form from `getPublicKey`, so requiring\n * x-only would make the common case an error.\n */\n depositorBtcPubkey: string;\n /** Funded (broadcast) Pre-PegIn transaction hex, `0x` optional. */\n fundedPrePeginTxHex: string;\n}\n\nexport interface DeriveHashlocksFromPrePeginResult {\n /** Number of HTLC outputs the transaction funds, from the anchor's vout. */\n vaultCount: number;\n /** 32-byte hex hashlocks (no `0x`), indexed by `htlcVout`. */\n hashlocks: readonly string[];\n /** The transaction's auth-anchor commitment, `SHA256(authAnchor)` as hex. */\n authAnchorHash: string;\n}\n\n/**\n * Derive the per-vault hashlocks committed by a funded Pre-PegIn.\n *\n * Validates the re-derived root against the transaction's auth-anchor\n * OP_RETURN before expanding anything else. That check costs one HKDF call,\n * needs zero protocol parameters, and is what separates \"wrong wallet,\n * account or network\" from \"right wallet, no candidate matched\" — otherwise\n * both surface as a fruitless parameter search.\n *\n * @throws {UnanchoredPrePeginError} If the transaction carries no single,\n * unambiguous auth-anchor OP_RETURN.\n * @throws {VaultRootMismatchError} If the derived root does not commit to the\n * transaction's anchor.\n */\nexport async function deriveHashlocksFromPrePegin(\n input: DeriveHashlocksFromPrePeginInput,\n): Promise<DeriveHashlocksFromPrePeginResult> {\n const { wallet, depositorBtcPubkey, fundedPrePeginTxHex } = input;\n\n const cleanTxHex = stripHexPrefix(fundedPrePeginTxHex);\n const anchor = findAuthAnchorOpReturn(cleanTxHex);\n if (anchor === undefined) {\n throw new UnanchoredPrePeginError(\n `Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN, so the ` +\n `number of HTLC outputs it funds cannot be determined. Legacy ` +\n `pre-anchor deposits are not recoverable by this path.`,\n );\n }\n // The anchor sits immediately after the HTLC outputs, so its vout IS the\n // vault count. At vout 0 it would claim a Pre-PegIn that funds nothing.\n const vaultCount = anchor.vout;\n if (vaultCount === 0) {\n throw new UnanchoredPrePeginError(\n `Pre-PegIn's auth-anchor OP_RETURN is at vout 0, implying zero HTLC ` +\n `outputs; there is nothing to recover.`,\n );\n }\n\n const fundingOutpoints = parseFundingOutpointsFromTx(cleanTxHex);\n\n const root = await deriveVaultRoot(wallet, {\n // The vault context takes the 32-byte x-only key; a wallet's compressed\n // key would otherwise fail a byte-length check deep in the encoder with\n // nothing pointing back at the caller.\n depositorBtcPubkey: hexToUint8Array(\n processPublicKeyToXOnly(depositorBtcPubkey),\n ),\n fundingOutpoints,\n });\n\n // Ordering is load-bearing: `expandPerVaultSecrets` takes ownership of\n // `root` and zeroes it, so the anchor expansion must run first. On any\n // throw in this window nothing else will wipe the root, so wipe it here.\n try {\n const authAnchorBytes = await expandAuthAnchor(root);\n let derivedAuthAnchorHash: string;\n try {\n derivedAuthAnchorHash = uint8ArrayToHex(sha256(authAnchorBytes));\n } finally {\n authAnchorBytes.fill(0);\n }\n if (derivedAuthAnchorHash !== anchor.hash) {\n throw new VaultRootMismatchError(derivedAuthAnchorHash, anchor.hash);\n }\n } catch (err) {\n root.fill(0);\n throw err;\n }\n\n // Shares the deposit-time expansion rather than a hashlock-only variant, so\n // the two can never drift. Its WOTS output is unused here and dropped with\n // the result object; refunding spends the timelock leaf, not the preimage.\n const { hashlocks } = await expandPerVaultSecrets(root, vaultCount);\n\n return { vaultCount, hashlocks, authAnchorHash: anchor.hash };\n}\n","/**\n * The candidate parameter space `reconstructPeginParams` searches (#2203).\n *\n * A reorg destroys the vault row's version stamps but not the versioned data\n * they point at: `getOffchainParamsByVersion`, `getVaultKeepersByVersion` and\n * `getUniversalChallengersByVersion` are keyed by version, not by `vaultId`,\n * and survive. So the stamps are recoverable by enumeration.\n *\n * Two parameters are deliberately NOT axes here.\n *\n * `vaultCoreVersion` is supplied, not searched. The Pre-PegIn carries no\n * evidence of it: `getPrePeginHtlcConnectorInfo` produces a byte-identical\n * scriptPubKey for v1 and v2, and the version's only other effect on the\n * transaction is the size of the reserve folded into the HTLC value — which\n * the search inverts back out of that same value, so it matches by\n * construction. Enumerating it would guarantee an ambiguous result rather than\n * narrow one. See `__tests__/reconstructPeginParams.test.ts`, which pins the\n * identical-scriptPubKey fact so a future graph version that DOES change the\n * connector fails loudly here.\n *\n * The RFC-006 operation-key epochs are not enumerable at all. Every\n * epoch-keyed read needs `getVaultKeyEpochs(vaultId)` — the destroyed row —\n * and no ABI in this repo exposes an epoch history, a counter, or an event.\n * Only the genesis keys and the operators' current keys are reachable, which\n * is why {@link KeyEpochPolicy} has exactly two values and why they apply to\n * the whole participant set at once: a vault whose participants rotated more\n * than once since creation cannot be reconstructed.\n *\n * @module recovery/peginParamsCandidates\n */\n\nimport type { Address } from \"viem\";\n\n/** One versioned offchain-params snapshot, flattened to what a trial needs. */\nexport interface OffchainParamsCandidate {\n /** `offchainParamsVersion` stamp this snapshot would restore. */\n version: number;\n /** `VersionedOffchainParams.feeRate`. */\n protocolFeeRate: bigint;\n minPeginFeeRate: bigint;\n councilQuorum: number;\n /** `VersionedOffchainParams.securityCouncilKeys.length`. */\n councilSize: number;\n /** `getTimelockPeginByVersion(version)` — not a field on the params struct. */\n timelockPegin: number;\n timelockAssert: number;\n /** `VersionedOffchainParams.tRefund` — the only scalar here that reaches the HTLC scriptPubKey. */\n timelockRefund: number;\n}\n\n/**\n * One participant key set: a vault provider plus the two rosters at the\n * versions the vault was stamped with.\n *\n * Every key here must be an RFC-006 **operation** key resolved at that\n * participant's own key epoch, and the two roster arrays must be sorted —\n * exactly what `resolveParticipantKeysAtEpochs` produces as\n * `vaultKeeperOperationKeysSorted` / `universalChallengerOperationKeysSorted`.\n * Registration keys are NOT interchangeable: they only coincide with operation\n * keys while nobody has rotated, so passing them yields a wrong script on every\n * candidate and a not-found that wrongly implies the true set was tried.\n *\n * The three epochs are stamped independently by three registries, so a mixed\n * state — the vault provider rotated before this deposit, a challenger after —\n * is ordinary rather than impossible. That is why epochs are resolved per\n * participant from the `PegInSubmitted` log rather than chosen as one\n * all-genesis or all-current policy.\n */\nexport interface ParticipantKeySetCandidate {\n vaultProvider: Address;\n /** x-only operation-key hex (no `0x`) at the vault's `vpKeyEpoch`. */\n vaultProviderBtcPubkey: string;\n appVaultKeepersVersion: number;\n /** Sorted operation keys at the vault's `appKeeperKeyEpoch`. */\n vaultKeeperBtcPubkeys: readonly string[];\n universalChallengersVersion: number;\n /** Sorted operation keys at the vault's `ucKeyEpoch`. */\n universalChallengerBtcPubkeys: readonly string[];\n}\n\n/** A fully-determined parameter set to trial against the funded Pre-PegIn. */\nexport interface PeginParamsCandidate {\n /**\n * Stamped tx-graph version (NOT the chain-active one). Carried so the result\n * describes itself, but constant across a candidate space — see the module\n * note on why it cannot be searched.\n */\n vaultCoreVersion: number;\n offchainParams: OffchainParamsCandidate;\n participants: ParticipantKeySetCandidate;\n}\n\nexport interface BuildPeginParamsCandidatesInput {\n /**\n * The tx-graph version the stranded deposit was built with. A scalar, not a\n * list: the transaction cannot discriminate it, so this is taken on trust.\n * Read it from the orphaned `PegInSubmitted` log — `activeVaultCoreVersion()`\n * is the current version and is wrong for any deposit that predates a bump.\n */\n vaultCoreVersion: number;\n offchainParams: readonly OffchainParamsCandidate[];\n participantKeySets: readonly ParticipantKeySetCandidate[];\n}\n\n/**\n * Expand the two searchable axes into the flat candidate list\n * `reconstructPeginParams` trials.\n *\n * With the parameters read from the `PegInSubmitted` log this is called with\n * one entry per axis and produces a single candidate to verify. The\n * multi-element form is the fallback search.\n */\nexport function buildPeginParamsCandidates(\n input: BuildPeginParamsCandidatesInput,\n): PeginParamsCandidate[] {\n const { vaultCoreVersion, offchainParams, participantKeySets } = input;\n if (!Number.isInteger(vaultCoreVersion) || vaultCoreVersion < 1) {\n throw new Error(\n `buildPeginParamsCandidates: vaultCoreVersion must be a positive integer, got ${vaultCoreVersion}`,\n );\n }\n if (offchainParams.length === 0) {\n throw new Error(\n \"buildPeginParamsCandidates: at least one offchain-params version is required\",\n );\n }\n if (participantKeySets.length === 0) {\n throw new Error(\n \"buildPeginParamsCandidates: at least one participant key set is required\",\n );\n }\n\n const candidates: PeginParamsCandidate[] = [];\n for (const params of offchainParams) {\n for (const participants of participantKeySets) {\n candidates.push({\n vaultCoreVersion,\n offchainParams: params,\n participants,\n });\n }\n }\n return candidates;\n}\n\n/** Which enumeration a version belongs to. */\nexport type CandidateAxis =\n | \"offchainParams\"\n | \"vaultKeepers\"\n | \"universalChallengers\";\n\n/**\n * A version the caller enumerated over but could not resolve into candidate\n * data — dropped by `fetchAllOffchainParams`'s validation, or reported to a\n * roster loop's `onSkippedVersion` observer.\n *\n * Recorded rather than ignored because an unresolved version is UNRESOLVABLE,\n * not absent: it may be the very version that stamped the stranded vault, and\n * a search space missing its answer can still return a confident look-alike.\n */\nexport interface UnresolvedVersion {\n axis: CandidateAxis;\n version: number;\n reason: string;\n}\n\n/** Compact identity of an unresolved version, for error messages. */\nexport function describeUnresolvedVersion(\n unresolved: UnresolvedVersion,\n): string {\n return `${unresolved.axis} v${unresolved.version} (${unresolved.reason})`;\n}\n\n/** Compact identity of a candidate, for error messages and result labels. */\nexport function describePeginParamsCandidate(\n candidate: PeginParamsCandidate,\n): string {\n const { participants } = candidate;\n return (\n `core=${candidate.vaultCoreVersion} ` +\n `offchain=${candidate.offchainParams.version} ` +\n `keepers=${participants.appVaultKeepersVersion} ` +\n `challengers=${participants.universalChallengersVersion} ` +\n `vp=${participants.vaultProvider}`\n );\n}\n","/**\n * Recover a stranded deposit's destroyed protocol parameters by trialling an\n * enumerated candidate space against the funded Pre-PegIn transaction (#2203).\n *\n * This is a candidate enumerator plus a loop over an EXISTING verifier.\n * `rebuildDepositTermsCore` already answers \"do these parameters and this\n * funded transaction agree?\" — it rebuilds every HTLC scriptPubKey through the\n * WASM oracle and byte-matches script and value against the transaction, from\n * plain inputs with no chain access. Recovery reuses it verbatim so there is\n * exactly one implementation of that judgement in the codebase.\n *\n * No wallet, no `vaultId`, no browser: every input is either supplied by the\n * caller or read off the transaction. Hashlocks come from\n * `deriveHashlocksFromPrePegin`.\n *\n * @module recovery/reconstructPeginParams\n */\n\nimport type { Network } from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Transaction } from \"bitcoinjs-lib\";\n\nimport type { DepositTerms } from \"../deposit-terms/depositTerms\";\nimport { rebuildDepositTermsCore } from \"../deposit-terms/rebuildDepositTermsCore\";\nimport { findAuthAnchorOpReturn } from \"../managers/pegin/assertAuthAnchorOpReturn\";\nimport { HtlcOutputMismatchError } from \"../primitives/psbt/assertWasmPeginSizing\";\nimport {\n processPublicKeyToXOnly,\n stripHexPrefix,\n} from \"../primitives/utils/bitcoin\";\nimport { calculateBtcTxHash } from \"../utils/transaction/btcTxHash\";\nimport {\n computeMinClaimValue,\n computeMinPeginFee,\n peginP2aAnchorOutput,\n} from \"../wasm\";\n\nimport {\n describePeginParamsCandidate,\n describeUnresolvedVersion,\n type PeginParamsCandidate,\n type UnresolvedVersion,\n} from \"./peginParamsCandidates\";\nimport {\n PeginParamsAmbiguousError,\n PeginParamsIncompleteSpaceError,\n PeginParamsNotFoundError,\n PeginSizingIntegrityError,\n UnanchoredPrePeginError,\n} from \"./recoveryErrors\";\n\n/**\n * How many per-candidate reasons an error message carries, for rejections and\n * for unevaluated candidates alike. The full list is one line per candidate and\n * runs to hundreds; a handful is enough to tell \"wrong transaction\" from\n * \"roster not enumerated\". Only the message is capped — the counts that drive\n * the fail-closed decisions stay exact.\n */\nconst MAX_REPORTED_REJECTIONS = 5;\n\nexport interface ReconstructPeginParamsInput {\n /** Hashlocks indexed by `htlcVout`, from `deriveHashlocksFromPrePegin`. */\n hashlocks: readonly string[];\n /** Funded (broadcast) Pre-PegIn transaction hex, `0x` optional. */\n fundedPrePeginTxHex: string;\n /** Depositor x-only BTC pubkey hex, from the connected wallet. */\n depositorBtcPubkey: string;\n /**\n * Funded-transaction fee, `Σin − Σout`. Not derivable from the transaction\n * alone — the input values live in the funding UTXOs — but those are\n * Bitcoin-keyed reads, which a reorg on Ethereum leaves intact.\n */\n prepeginMaxFee: bigint;\n /**\n * Commission ceiling projected into the returned {@link DepositTerms}. Not a\n * search axis: it never reaches the HTLC scriptPubKey or value, so the\n * transaction carries no evidence of it and the caller must supply the bound\n * it is willing to accept.\n */\n maxAcceptableCommissionBps: number;\n network: Network;\n /** The space to search, from `buildPeginParamsCandidates`. */\n candidates: readonly PeginParamsCandidate[];\n /**\n * Versions the caller enumerated over but could not resolve. Required, and\n * `[]` is the explicit claim that the enumeration was complete — so a caller\n * cannot arrive at a trusted answer by forgetting to mention its gaps.\n *\n * A non-empty list turns a sole match into a\n * {@link PeginParamsIncompleteSpaceError}: uniqueness only rules out a wrong\n * answer when the right answer was in the space to begin with.\n */\n unresolvedVersions: readonly UnresolvedVersion[];\n}\n\nexport interface ReconstructPeginParamsResult {\n /** The single candidate whose rebuild matched the funded transaction. */\n candidate: PeginParamsCandidate;\n /**\n * Terms projected from the matched candidate.\n *\n * The transaction pins the participant keys, `timelockRefund`, and each\n * HTLC's scriptPubKey and total value. It does NOT pin how that value splits\n * into `peginAmount`, `depositorClaimValue` and `peginMaxFee` — that split\n * follows from the matched candidate's fee-side parameters, which the\n * transaction carries no evidence of.\n */\n terms: DepositTerms;\n /**\n * Per-vault `peginAmount`, inverted from the observed HTLC output values.\n * Only as sound as the matched candidate's reserve — see {@link terms}.\n */\n peginAmounts: readonly bigint[];\n /** The transaction's `SHA256(authAnchor)` commitment, for the refund rebuild. */\n authAnchorHash: string;\n /** Size of the space actually trialled, for the recovery record. */\n candidatesTried: number;\n /**\n * Every candidate that matched and projected identical terms.\n *\n * More than one is normal rather than suspicious: candidates differing only\n * in fields the transaction cannot express — version labels whose\n * script- and value-relevant content is the same — are indistinguishable by\n * construction and describe the same deposit. They are reported rather than\n * refused; refusal is reserved for survivors whose terms actually differ.\n */\n matchedCandidates: readonly PeginParamsCandidate[];\n}\n\n/**\n * Canonical form of a match's observable content, for equality only.\n *\n * Two survivors agreeing here produce the same refund and the same reported\n * amounts, so the difference between them is a label with no consequence.\n */\nfunction matchFingerprint(\n terms: DepositTerms,\n peginAmounts: readonly bigint[],\n): string {\n return JSON.stringify({ terms, peginAmounts }, (_key, value) =>\n typeof value === \"bigint\" ? `${value}` : value,\n );\n}\n\n/** Amount-independent per-HTLC reserve, recomputed exactly as the verifier does. */\ninterface PeginSizing {\n depositorClaimValue: bigint;\n peginMaxFee: bigint;\n p2aAnchorValue: bigint;\n}\n\n/** Identity of the inputs that determine a candidate's reserve, for memoising it. */\nfunction sizingCacheKey(candidate: PeginParamsCandidate): string {\n const { offchainParams: params, participants } = candidate;\n return [\n candidate.vaultCoreVersion,\n participants.vaultKeeperBtcPubkeys.length,\n participants.universalChallengerBtcPubkeys.length,\n params.councilQuorum,\n params.councilSize,\n params.protocolFeeRate,\n params.minPeginFeeRate,\n ].join(\"|\");\n}\n\n/**\n * Compute the amount-independent reserve for one candidate, asserting the WASM\n * outputs before they are consumed (CLAUDE.md critical path 1).\n *\n * Only binary-integrity invariants are asserted here — a claim value or fee of\n * zero, or a negative anchor, is impossible for ANY valid parameter set, so it\n * indicts the binary rather than the candidate and must escape the search loop\n * instead of being counted as a rejection. The plausibility band on the implied\n * reserve is deliberately NOT duplicated: it depends on the candidate's own\n * `minPeginFeeRate`, so a candidate can legitimately fail it, and the verifier\n * applies it where it belongs — as a candidate filter.\n *\n * An absent anchor reads as `0n` because the facade returns `null` for graph\n * versions whose PegIn carries no anchor and never a zero-valued placeholder,\n * which is the same reading `rebuildDepositTermsCore` takes.\n */\nasync function computePeginSizing(\n candidate: PeginParamsCandidate,\n): Promise<PeginSizing> {\n const { offchainParams: params, participants } = candidate;\n // Depositor-as-claimer: the local-challenger count is the keeper count\n // (the vault provider is excluded) — btc-vault graph.rs derive_challengers_for.\n const numVks = participants.vaultKeeperBtcPubkeys.length;\n const numUcs = participants.universalChallengerBtcPubkeys.length;\n const [depositorClaimValue, peginMaxFee, anchorOutput] = await Promise.all([\n computeMinClaimValue(\n candidate.vaultCoreVersion,\n numVks,\n numUcs,\n params.councilQuorum,\n params.councilSize,\n params.protocolFeeRate,\n ),\n computeMinPeginFee(\n candidate.vaultCoreVersion,\n numVks,\n numUcs,\n params.minPeginFeeRate,\n ),\n peginP2aAnchorOutput(candidate.vaultCoreVersion),\n ]);\n const p2aAnchorValue = anchorOutput?.value ?? 0n;\n\n if (depositorClaimValue <= 0n) {\n throw new PeginSizingIntegrityError(\n `WASM returned non-positive depositorClaimValue ${depositorClaimValue} for graph version ${candidate.vaultCoreVersion}`,\n );\n }\n if (peginMaxFee <= 0n) {\n throw new PeginSizingIntegrityError(\n `WASM returned non-positive peginMaxFee ${peginMaxFee} for graph version ${candidate.vaultCoreVersion}`,\n );\n }\n if (p2aAnchorValue < 0n) {\n throw new PeginSizingIntegrityError(\n `WASM returned negative P2A anchor value ${p2aAnchorValue} for graph version ${candidate.vaultCoreVersion}`,\n );\n }\n\n return { depositorClaimValue, peginMaxFee, p2aAnchorValue };\n}\n\n/**\n * Search the candidate space for the parameter set that reproduces the funded\n * Pre-PegIn, and project it back into {@link DepositTerms}.\n *\n * Per candidate: invert each vault's `peginAmount` from the observed HTLC\n * output value via the protocol identity `htlcValue = peginAmount +\n * depositorClaimValue + peginMaxFee + p2aAnchorValue`, then hand the result to\n * `rebuildDepositTermsCore`, which independently recomputes that same sizing\n * and byte-matches both the value and the scriptPubKey of every HTLC output.\n *\n * Because the amount is inverted from the value it is compared against, the\n * VALUE check cannot discriminate between candidates: it holds for any\n * candidate whose reserve leaves a positive amount. The scriptPubKey does all\n * the discriminating, and `getPrePeginHtlcConnectorInfo` accepts exactly one\n * offchain-params scalar — `timelockRefund`. So two offchain versions sharing\n * a `timelockRefund` are indistinguishable however much their fee rates or\n * council parameters differ, and that is precisely the ambiguity this function\n * refuses to guess through. The value check is still run, by the verifier, as\n * the bound that stops a candidate whose reserve exceeds the funded output.\n *\n * Every candidate is trialled; the loop does not stop at the first match,\n * because detecting ambiguity is the point. Matches are then COMPARED rather\n * than counted — several candidates matching is the ordinary case whenever\n * their differences cannot reach the transaction, and refusing on a count\n * alone would reject a deposit whose refund is fully determined.\n *\n * A candidate is only rejected on a Gate-1 byte mismatch, which is the\n * transaction positively disagreeing with it. Any other failure means the\n * candidate was never really evaluated, so it is recorded as unresolved and\n * feeds the same fail-closed path as a version that could not be read —\n * otherwise an incidental error on the TRUE candidate would remove it silently\n * and hand back a look-alike as a trusted unique answer.\n *\n * @throws {UnanchoredPrePeginError} If the transaction carries no single,\n * unambiguous auth-anchor OP_RETURN.\n * @throws {PeginParamsNotFoundError} If no candidate matched.\n * @throws {PeginParamsAmbiguousError} If matches disagree on the projected terms.\n * @throws {PeginParamsIncompleteSpaceError} If a match is found but the space\n * was known to be incomplete, or a candidate failed to evaluate.\n */\nexport async function reconstructPeginParams(\n input: ReconstructPeginParamsInput,\n): Promise<ReconstructPeginParamsResult> {\n const {\n hashlocks,\n fundedPrePeginTxHex,\n depositorBtcPubkey,\n prepeginMaxFee,\n maxAcceptableCommissionBps,\n network,\n candidates,\n unresolvedVersions,\n } = input;\n\n if (hashlocks.length === 0) {\n throw new Error(\n \"reconstructPeginParams: at least one hashlock is required\",\n );\n }\n if (candidates.length === 0) {\n throw new Error(\"reconstructPeginParams: candidate space is empty\");\n }\n\n // The verifier compares this against WASM-built scripts and does not\n // normalise, while the derivation half accepts a `0x` prefix. Passing one\n // wallet string to both must not make step 1 pass and step 2 fail every\n // candidate, which would present as \"no parameters found\".\n const normalizedDepositorBtcPubkey =\n processPublicKeyToXOnly(depositorBtcPubkey);\n\n const cleanTxHex = stripHexPrefix(fundedPrePeginTxHex);\n const anchor = findAuthAnchorOpReturn(cleanTxHex);\n if (anchor === undefined) {\n throw new UnanchoredPrePeginError(\n `Pre-PegIn carries no single, unambiguous auth-anchor OP_RETURN; the ` +\n `sibling set cannot be proven complete. Reconstruction refused.`,\n );\n }\n // The verifier re-checks this, but catching it here attributes the failure\n // to the hashlock set rather than to every candidate in turn.\n if (anchor.vout !== hashlocks.length) {\n throw new Error(\n `reconstructPeginParams: ${hashlocks.length} hashlock(s) supplied but ` +\n `the auth-anchor OP_RETURN sits at vout ${anchor.vout}, so the ` +\n `transaction funds ${anchor.vout} HTLC output(s). Reconstruction refused.`,\n );\n }\n\n const outputs = Transaction.fromHex(cleanTxHex).outs;\n const observedHtlcValues = hashlocks.map((_, i) => BigInt(outputs[i].value));\n const prepeginTxid = stripHexPrefix(\n calculateBtcTxHash(cleanTxHex),\n ).toLowerCase();\n\n const sizingCache = new Map<string, PeginSizing>();\n const survivors: {\n candidate: PeginParamsCandidate;\n terms: DepositTerms;\n peginAmounts: bigint[];\n fingerprint: string;\n }[] = [];\n const rejections: string[] = [];\n // Count drives the fail-closed decision and must stay exact; only the labels\n // that reach the error message are capped, since in the fallback search every\n // candidate can land here and each entry embeds a full error message.\n const unevaluatedLabels: string[] = [];\n let unevaluatedCount = 0;\n\n for (const candidate of candidates) {\n try {\n const cacheKey = sizingCacheKey(candidate);\n let sizing = sizingCache.get(cacheKey);\n if (sizing === undefined) {\n sizing = await computePeginSizing(candidate);\n sizingCache.set(cacheKey, sizing);\n }\n const reserve =\n sizing.depositorClaimValue + sizing.peginMaxFee + sizing.p2aAnchorValue;\n const peginAmounts = observedHtlcValues.map((value) => value - reserve);\n // A reserve larger than the funded output is the transaction positively\n // disagreeing with this candidate — the value bound doing the one piece\n // of discriminating it can. The verifier would reject it too, but with a\n // generic error that would be misread as \"never evaluated\" and would\n // pollute the space with phantom gaps.\n const shortIndex = peginAmounts.findIndex((amount) => amount <= 0n);\n if (shortIndex !== -1) {\n throw new HtlcOutputMismatchError(\n `HTLC output[${shortIndex}] value ${observedHtlcValues[shortIndex]} ` +\n `is not above this candidate's reserve ${reserve}, so it implies a ` +\n `non-positive pegin amount ${peginAmounts[shortIndex]}.`,\n );\n }\n\n const { offchainParams: params, participants } = candidate;\n const terms = await rebuildDepositTermsCore({\n vaultCoreVersion: candidate.vaultCoreVersion,\n siblings: hashlocks.map((hashlock, i) => ({\n hashlock,\n amount: peginAmounts[i],\n })),\n fundedPrePeginTxHex: cleanTxHex,\n depositorBtcPubkey: normalizedDepositorBtcPubkey,\n vaultProviderBtcPubkey: participants.vaultProviderBtcPubkey,\n vaultKeeperBtcPubkeys: participants.vaultKeeperBtcPubkeys,\n universalChallengerBtcPubkeys:\n participants.universalChallengerBtcPubkeys,\n protocolFeeRate: params.protocolFeeRate,\n minPeginFeeRate: params.minPeginFeeRate,\n councilQuorum: params.councilQuorum,\n councilSize: params.councilSize,\n timelockPegin: params.timelockPegin,\n timelockAssert: params.timelockAssert,\n timelockRefund: params.timelockRefund,\n prepeginTxid,\n prepeginMaxFee,\n maxAcceptableCommissionBps,\n network,\n });\n\n survivors.push({\n candidate,\n terms,\n peginAmounts,\n fingerprint: matchFingerprint(terms, peginAmounts),\n });\n } catch (err) {\n // A malformed WASM sizing output is not a property of the candidate, so\n // counting it as a rejection would bury a broken binary under \"no\n // candidate matched\". Let it out.\n if (err instanceof PeginSizingIntegrityError) {\n throw err;\n }\n const label = describePeginParamsCandidate(candidate);\n const reason = err instanceof Error ? err.message : String(err);\n if (err instanceof HtlcOutputMismatchError) {\n // The transaction positively disagrees with this candidate — the\n // expected outcome for all but one, so it cannot propagate. Recorded,\n // and a sample reaches the not-found error to keep it diagnosable.\n if (rejections.length < MAX_REPORTED_REJECTIONS) {\n rejections.push(`[${label}] ${reason}`);\n }\n } else {\n // Anything else says nothing about the transaction: this candidate was\n // never actually evaluated. Treating it as a rejection would let an\n // incidental failure on the true candidate hand back a look-alike.\n unevaluatedCount++;\n if (unevaluatedLabels.length < MAX_REPORTED_REJECTIONS) {\n unevaluatedLabels.push(`${label} (${reason})`);\n }\n }\n }\n }\n\n // A candidate that could not be evaluated is a hole in the space in exactly\n // the same way an unreadable version is, so the two are reported together.\n const gapCount = unresolvedVersions.length + unevaluatedCount;\n const gaps = [\n ...unresolvedVersions.map(describeUnresolvedVersion),\n ...unevaluatedLabels,\n ];\n\n if (survivors.length === 0) {\n throw new PeginParamsNotFoundError(candidates.length, rejections, gaps);\n }\n\n // Compare, do not count. Survivors all byte-matched the same funded outputs,\n // so they already agree on every HTLC scriptPubKey and total value; if they\n // also project identical terms there is nothing to choose between them and\n // nothing is at stake in choosing.\n const distinct = new Set(survivors.map((s) => s.fingerprint));\n if (distinct.size > 1) {\n throw new PeginParamsAmbiguousError(\n survivors.map((s) => describePeginParamsCandidate(s.candidate)),\n );\n }\n\n // Reported after ambiguity: disagreeing survivors are the more specific\n // diagnosis, and that error already names them.\n if (gapCount > 0) {\n throw new PeginParamsIncompleteSpaceError(\n describePeginParamsCandidate(survivors[0].candidate),\n gaps,\n );\n }\n\n return {\n candidate: survivors[0].candidate,\n terms: survivors[0].terms,\n peginAmounts: survivors[0].peginAmounts,\n authAnchorHash: anchor.hash,\n candidatesTried: candidates.length,\n matchedCandidates: survivors.map((s) => s.candidate),\n };\n}\n","/**\n * Close the loop from a verified reconstruction to the ordinary refund path\n * (#2203).\n *\n * `buildAndBroadcastRefund` takes its two reads — the vault row and the\n * version-pinned Pre-PegIn context — as injected callbacks rather than\n * performing them itself. That is the whole seam recovery needs: a stranded\n * deposit has no row to read, but it does have a reconstruction that was\n * byte-verified against the funded transaction, and those are exactly the\n * fields the callbacks are expected to return.\n *\n * So recovery does not need a parallel refund implementation, and must not\n * have one. It supplies the same shapes from a different source and reuses the\n * orchestrator verbatim, which keeps the refund-fee cap, the abort checks, the\n * `htlcVout` contiguity invariant and the bitcoind error classification in one\n * place for both paths.\n *\n * @module recovery/toRefundInputs\n */\n\nimport type { Network } from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport type { Address, Hex } from \"viem\";\n\nimport { ensureHexPrefix } from \"../primitives/utils/bitcoin\";\nimport type {\n RefundPrePeginContext,\n VaultRefundData,\n} from \"../services/refund/buildAndBroadcastRefund\";\n\nimport type { ReconstructPeginParamsResult } from \"./reconstructPeginParams\";\n\nexport interface ToRefundInputsOptions {\n /**\n * Which sibling of the Pre-PegIn to refund, as an index into the\n * reconstruction's hashlocks and amounts. Equal to the vault's `htlcVout`\n * by construction — `PeginManager` asserts `perVault[i].htlcVout === i`.\n */\n htlcVout: number;\n /**\n * Depositor BTC pubkey, the same value the reconstruction was run with.\n * Passed through rather than re-derived so the refund is built against the\n * key that was actually verified.\n *\n * Deliberately NOT narrowed to x-only here. `VaultRefundData.depositorBtcPubkey`\n * accepts \"32 or 33 bytes of hex\", and `buildAndBroadcastRefund` narrows it\n * with `processPublicKeyToXOnly` before it reaches the PSBT builder — so a\n * wallet's compressed key flows through unchanged, which is what wallets\n * actually return. Narrowing early would discard the parity byte the\n * orchestrator's own validation accepts.\n */\n depositorBtcPubkey: string;\n /**\n * The vault provider's application entry point. Not recoverable from the\n * Bitcoin transaction and not part of the verified parameter set — it is a\n * field of the vault-provider registry row, which is address-keyed and\n * survives the reorg untouched.\n */\n applicationEntryPoint: Address;\n /** Funded Pre-PegIn transaction hex, `0x` optional. */\n fundedPrePeginTxHex: string;\n /** Hashlocks indexed by `htlcVout`, as passed to the reconstruction. */\n hashlocks: readonly string[];\n /**\n * The Bitcoin network the reconstruction was verified against. An input to\n * the search rather than an output of it, so it is restated here; passing a\n * different one would build the refund against a different script tree than\n * the one that was proven to match.\n */\n network: Network;\n}\n\nexport interface RefundInputsFromRecovery {\n vault: VaultRefundData;\n context: RefundPrePeginContext;\n}\n\n/**\n * Project a verified reconstruction into the two shapes\n * `buildAndBroadcastRefund` injects.\n *\n * Every value here comes from a parameter set that has already been\n * byte-matched against the funded transaction's HTLC outputs, so this is a\n * projection and not a second validation pass. The orchestrator re-checks the\n * parts it owns regardless.\n *\n * @throws If `htlcVout` does not index the reconstructed batch, or the\n * hashlock vector disagrees with the reconstructed amounts.\n */\nexport function toRefundInputs(\n result: ReconstructPeginParamsResult,\n options: ToRefundInputsOptions,\n): RefundInputsFromRecovery {\n const {\n htlcVout,\n depositorBtcPubkey,\n applicationEntryPoint,\n fundedPrePeginTxHex,\n hashlocks,\n network,\n } = options;\n\n const { candidate, peginAmounts } = result;\n const { offchainParams, participants } = candidate;\n\n if (hashlocks.length !== peginAmounts.length) {\n throw new Error(\n `toRefundInputs: ${hashlocks.length} hashlock(s) but ` +\n `${peginAmounts.length} reconstructed amount(s); the reconstruction ` +\n `and the hashlock vector describe different transactions.`,\n );\n }\n if (\n !Number.isInteger(htlcVout) ||\n htlcVout < 0 ||\n htlcVout >= peginAmounts.length\n ) {\n throw new Error(\n `toRefundInputs: htlcVout ${htlcVout} is outside the reconstructed ` +\n `batch of ${peginAmounts.length} vault(s).`,\n );\n }\n\n // The orchestrator requires the complete vout-ordered batch, not just the\n // target: its anchor check is fail-closed, so refunding one sibling of a\n // multi-vault Pre-PegIn without the others is rejected outright.\n const batch = peginAmounts.map((amount, index) => ({\n hashlock: ensureHexPrefix(hashlocks[index]),\n amount,\n htlcVout: index,\n }));\n\n const vault: VaultRefundData = {\n vaultCoreVersion: candidate.vaultCoreVersion,\n hashlock: batch[htlcVout].hashlock as Hex,\n htlcVout,\n offchainParamsVersion: offchainParams.version,\n appVaultKeepersVersion: participants.appVaultKeepersVersion,\n universalChallengersVersion: participants.universalChallengersVersion,\n vaultProvider: participants.vaultProvider,\n applicationEntryPoint,\n amount: peginAmounts[htlcVout],\n unsignedPrePeginTxHex: fundedPrePeginTxHex,\n depositorBtcPubkey,\n batch,\n };\n\n const context: RefundPrePeginContext = {\n vaultProviderPubkey: participants.vaultProviderBtcPubkey,\n vaultKeeperPubkeys: participants.vaultKeeperBtcPubkeys,\n universalChallengerPubkeys: participants.universalChallengerBtcPubkeys,\n timelockRefund: offchainParams.timelockRefund,\n feeRate: offchainParams.protocolFeeRate,\n minPeginFeeRate: offchainParams.minPeginFeeRate,\n // Depositor-as-claimer: the local-challenger count is the keeper count,\n // the vault provider excluded — btc-vault graph.rs derive_challengers.\n numLocalChallengers: participants.vaultKeeperBtcPubkeys.length,\n councilQuorum: offchainParams.councilQuorum,\n councilSize: offchainParams.councilSize,\n network,\n };\n\n return { vault, context };\n}\n"],"names":["STAMPED_PROTOCOL_FIELDS","STAMPED_ADDRESS_FIELDS","selectSiblingRegistrations","records","target","depositor","prePeginTxHash","registrationPrePeginTxHash","r","assertClaimBatchHomogeneous","siblings","sibling","field","orderClaimBatchByHtlcVout","members","ordered","a","b","member","i","m","DEPOSIT_TERMS_REJECTED_ERROR_NAME","DepositTermsRejectedError","message","reason","__publicField","isDepositTermsRejectedError","err","shaped","computeFundedPrePeginFee","fundedPrePeginTxHex","mempoolApiUrl","tx","Transaction","stripHexPrefix","totalIn","input","getUtxoInfo","Buffer","sum","u","totalOut","o","fee","MAX_REASONABLE_FEE_SATS","rebuildDepositTermsCore","siblingCount","expectedTxid","actualTxid","calculateBtcTxHash","found","findAuthAnchorOpReturn","numVks","numUcs","depositorClaimValue","computeMinClaimValue","peginMaxFee","computeMinPeginFee","anchor","peginP2aAnchorOutput","anchorValue","impliedReserve","maxImpliedReserve","MAX_REASONABLE_PEGIN_VBYTES","expectedHtlcValues","s","expectedHtlcScriptPubKeys","getPrePeginHtlcConnectorInfo","fundedOutputs","assertEncodedHtlcOutputsMatch","buildDepositTerms","rebuildDepositTermsForClaim","params","read","connectedDepositor","canonicalizeBtcPubkey","prepeginTxid","siblingMembers","record","vault","targetMember","prepeginMaxFee","isWotsMismatchError","error","msg","PEGIN_FINGERPRINT_DOMAIN_PREIMAGE","PEGIN_FINGERPRINT_DOMAIN","keccak256","toHex","UINT16_MAX","UINT64_MAX","UINT256_MAX","BYTES32_PATTERN","VAULT_CORE_VERSION_MIN","PeginFingerprintInputError","isPeginFingerprintInputError","assertUnsignedRange","value","max","solidityType","assertUint16","normalizeBytes32","normalizeRegistryAddress","registryAddress","isAddress","normalized","zeroAddress","PEGIN_FINGERPRINT_ABI_PARAMETERS","encodePeginFingerprintPreimage","registry","vaultProviderBtcKey","encodeAbiParameters","computePeginFingerprint","VaultRootMismatchError","derivedAuthAnchorHash","onChainAuthAnchorHash","UnanchoredPrePeginError","PeginParamsNotFoundError","candidatesTried","sampleRejections","unresolvedLabels","PeginParamsAmbiguousError","survivorLabels","PeginParamsIncompleteSpaceError","matchedLabel","PeginSizingIntegrityError","deriveHashlocksFromPrePegin","wallet","depositorBtcPubkey","cleanTxHex","vaultCount","fundingOutpoints","parseFundingOutpointsFromTx","root","deriveVaultRoot","hexToUint8Array","processPublicKeyToXOnly","authAnchorBytes","expandAuthAnchor","uint8ArrayToHex","sha256","hashlocks","expandPerVaultSecrets","buildPeginParamsCandidates","vaultCoreVersion","offchainParams","participantKeySets","candidates","participants","describeUnresolvedVersion","unresolved","describePeginParamsCandidate","candidate","MAX_REPORTED_REJECTIONS","matchFingerprint","terms","peginAmounts","_key","sizingCacheKey","computePeginSizing","anchorOutput","p2aAnchorValue","reconstructPeginParams","maxAcceptableCommissionBps","network","unresolvedVersions","normalizedDepositorBtcPubkey","outputs","observedHtlcValues","_","sizingCache","survivors","rejections","unevaluatedLabels","unevaluatedCount","cacheKey","sizing","reserve","shortIndex","amount","HtlcOutputMismatchError","hashlock","label","gapCount","gaps","toRefundInputs","result","options","htlcVout","applicationEntryPoint","batch","index","ensureHexPrefix","context"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-24A9Qoxb.js","sources":["../src/tbv/core/clients/eth/protocol-params-reader.ts","../src/tbv/core/clients/eth/types.ts"],"sourcesContent":["/**\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. btc-vault carries the PegIn timelock as\n * a `NonZeroU16` (`transactions/pegin.rs:33` @ ac4954e7), so a larger\n * `timelockAssert` has no protocol-side representation.\n */\nconst UINT16_MAX = 65535;\n\n// Decodes deployments that predate `maxFundingInputCount`, including those that also predate `peginActivationDelay`; delete it once every network returns 8 fields.\nconst PRE_FUNDING_INPUT_CAP_TBV_PARAMS_ABI = [\n {\n type: \"function\",\n name: \"getTBVProtocolParams\",\n inputs: [],\n outputs: [\n {\n name: \"\",\n type: \"tuple\",\n internalType: \"struct IProtocolParams.TBVProtocolParams\",\n components: [\n {\n name: \"minimumPegInAmount\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"maxPegInAmount\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"pegInAckTimeout\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"pegInActivationTimeout\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"maxHtlcOutputCount\",\n type: \"uint8\",\n internalType: \"uint8\",\n },\n {\n name: \"expiredPegInGraceBlocks\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n ],\n },\n ],\n stateMutability: \"view\",\n },\n] as const;\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 maxFundingInputCount: number;\n}\n\ntype RawPreFundingInputCapTBVParams = Omit<\n RawTBVParams,\n \"maxFundingInputCount\"\n>;\n\ntype MulticallEntry =\n | { status: \"success\"; result: unknown }\n | { status: \"failure\"; error: Error };\n\nfunction requireSuccess(entry: MulticallEntry): unknown {\n if (entry.status === \"failure\") {\n throw entry.error;\n }\n return entry.result;\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(\n result: RawPreFundingInputCapTBVParams,\n maxFundingInputCount: number | null,\n): 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 maxFundingInputCount,\n };\n}\n\nfunction resolveTBVParams(\n withFundingInputCap: MulticallEntry,\n preFundingInputCap: MulticallEntry,\n): TBVProtocolParams {\n if (withFundingInputCap.status === \"success\") {\n const raw = withFundingInputCap.result as RawTBVParams;\n return mapTBVParams(raw, raw.maxFundingInputCount);\n }\n if (preFundingInputCap.status === \"success\") {\n return mapTBVParams(\n preFundingInputCap.result as RawPreFundingInputCapTBVParams,\n null,\n );\n }\n throw withFundingInputCap.error;\n}\n\n/**\n * Derive timelockPegin from timelockAssert.\n *\n * btc-vault uses `timelock_assert` as the PegIn timelock (vaultd\n * `pegin_babe_setup.rs:794` @ ac4954e7) and carries it as a `NonZeroU16`\n * (`transactions/pegin.rs:33`).\n * `ProtocolParams.sol:510-512` @ c559f5c2 rejects a zero or above-uint16\n * `timelockAssert` on write; the upper bound is enforced again here so a bad\n * read fails early instead of truncating.\n *\n * @throws if timelockAssert exceeds uint16 max (65535)\n */\nexport function 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 [withFundingInputCap, preFundingInputCap] =\n await this.publicClient.multicall({\n contracts: this.tbvParamsCalls(),\n allowFailure: true,\n });\n\n const params = resolveTBVParams(withFundingInputCap, preFundingInputCap);\n validateTBVProtocolParams(params);\n return params;\n }\n\n private tbvParamsCalls() {\n return [\n {\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getTBVProtocolParams\",\n },\n {\n address: this.contractAddress,\n abi: PRE_FUNDING_INPUT_CAP_TBV_PARAMS_ABI,\n functionName: \"getTBVProtocolParams\",\n },\n ] as const;\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 * Returned as `bigint` with no `Number` narrowing: the registry compares it\n * against `block.number`, so callers must do the same arithmetic the\n * contract does. `0` is the documented \"disabled\" case and is returned as\n * `0n`. A missing getter or a non-bigint payload throws — never coerced to\n * `0`, which would fail open and skip the observation window.\n *\n * @throws If the deployment does not expose `peginActivationDelay()`, or\n * the decoded payload is not a `bigint`.\n */\n async getPeginActivationDelay(): Promise<bigint> {\n const raw: unknown = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"peginActivationDelay\",\n });\n if (typeof raw !== \"bigint\") {\n throw new Error(\n `Invalid peginActivationDelay from contract: must be a bigint, got ${typeof raw}`,\n );\n }\n return raw;\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 * That guarantee holds only within this multicall. A caller that also reads\n * participant keys — every fresh peg-in build does — must pass the same\n * `blockNumber` here and to those reads, or the two describe different\n * blocks and the pairing above buys nothing across the seam.\n */\n async getPegInConfiguration(\n blockNumber?: bigint,\n ): Promise<PegInConfiguration> {\n const results = await this.publicClient.multicall({\n blockNumber,\n contracts: [\n ...this.tbvParamsCalls(),\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 address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"activeVaultCoreVersion\",\n },\n ],\n allowFailure: true,\n });\n\n const tbvParams = resolveTBVParams(results[0], results[1]);\n const offchainParams = mapOffchainParams(\n requireSuccess(results[2]) as RawOffchainParams,\n );\n const offchainParamsVersion = Number(requireSuccess(results[3]));\n const activeVaultCoreVersion = Number(requireSuccess(results[4]));\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 maxFundingInputCount: tbvParams.maxFundingInputCount,\n timelockPegin: deriveTimelockPegin(offchainParams.timelockAssert),\n timelockRefund: offchainParams.tRefund,\n minVpCommissionBps: offchainParams.minVpCommissionBps,\n offchainParams,\n offchainParamsVersion,\n activeVaultCoreVersion,\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 * 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 an on-chain\n * registry. Minted only by `assertOnChainBtcPubkey`, which is the shared\n * validator behind both producers:\n * {@link VaultRegistryReader.getVaultProviderGenesisBtcPubKey} (the fixed\n * registration key) and {@link OperationKeyReader} (RFC-006 operation keys,\n * resolved current or at a vault's frozen epoch).\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 /**\n * ETH block number stamped at the Pending→Verified transition.\n * Compared against `block.number` (inclusive:\n * `block.number >= verifiedAt + peginActivationDelay`), never a unix timestamp.\n */\n verifiedAt: bigint;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n depositorPopSignature: Hex;\n prePeginTxHash: Hex;\n vaultProviderCommissionBps: number;\n /**\n * Last ETH block (inclusive) at which `claimExpiredVault` is accepted for\n * this vault. Frozen when the vault is reported expired, as that block plus\n * `expiredPegInGraceBlocks`; zero until then. Only meaningful for a vault\n * that expired after reaching Verified (`verifiedAt > 0`) — the contract\n * rejects the claim for any other.\n */\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/**\n * One vault's `PegInSubmittedV2` registration log, decoded.\n *\n * The registry discards several of these values after using them\n * (`maxAcceptableCommissionBps` is bound-checked and dropped), so the log is\n * their only on-chain source. Decoded leniently — no transaction is parsed and\n * no script is bound-checked here, so one malformed registration elsewhere in\n * the block cannot fail an unrelated caller's read; the strict per-record\n * checks live in `registration-records.ts` and run on selected records only.\n * That leniency stops at duplicates: a vault registers once, so two logs for\n * any vault id are an inconsistent node and fail the whole block's read\n * closed.\n *\n * @experimental\n */\nexport interface PeginRegistrationRecord {\n /** Lowercase, `0x`-prefixed. */\n vaultId: Hex;\n depositor: Address;\n vaultProvider: Address;\n /** btc-vault `pegin_amount`, satoshis. */\n amount: bigint;\n vaultCoreVersion: number;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n proverCircuitVersion: number;\n offchainParamsVersion: number;\n /**\n * The event's own `peginTxHash`: the txid of this vault's depositor-signed\n * PegIn, which with `depositor` re-derives the vault id. Per-vault, unlike\n * {@link PeginRegistrationRecord.unsignedPrePeginTx}, which siblings share.\n */\n peginTxHash: Hex;\n /**\n * The event's `depositorPayoutBtcAddress` bytes: the depositor's payout\n * scriptPubKey as `submitPeginRequest` received it (BTCVaultRegistry.sol\n * documents the parameter as \"BTC payout address (scriptPubKey)\"; the SDK\n * registers the validated scriptPubKey there). Lowercase, `0x`-prefixed.\n */\n depositorPayoutScriptPubKey: Hex;\n /**\n * The log's `unsignedPrePeginTx`, verbatim. Its txid\n * (`registrationPrePeginTxHash`) equals\n * {@link VaultProtocolInfo.prePeginTxHash}; siblings of one batch share it,\n * while the event's own `peginTxHash` is the per-vault PegIn id.\n */\n unsignedPrePeginTx: Hex;\n maxAcceptableCommissionBps: number;\n blockNumber: bigint;\n}\n\n/**\n * A vault's finalized `VaultClaimableBy` log for one claimer key.\n *\n * `blockNumber` is what the artifacts file records as\n * `claimable_event_block_number`, the block the prover proves against.\n *\n * @experimental\n */\nexport interface VaultClaimableByEvent {\n blockNumber: bigint;\n /** The `claimerPK` topic, validated as an x-only key. */\n claimerPk: OnChainBtcPubkey;\n peginTxHash: Hex;\n vaultCoreVersion: number;\n proverCircuitVersion: number;\n offchainParamsVersion: number;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n}\n\n/**\n * RFC-006 operation-key epochs a vault froze at `submitPeginRequest`.\n *\n * Each registry keeps a monotonic epoch counter that every key/payout setter\n * pre-increments. A vault stamps the counters live at its creation, and every\n * participant resolves \"which key did this vault bond?\" by asking the registry\n * for the key whose appended version is the latest stamped `<=` this epoch. A\n * rotation after the vault was created therefore never moves its keys.\n *\n * `uint64` — kept as `bigint` end-to-end and passed straight back to the\n * `...AtEpoch` getters, never narrowed through `Number`.\n *\n * Only ever read through {@link VaultRegistryReader.getVaultKeyEpochs}, which\n * uses the extended ABI. See `BTCVaultRegistryKeyEpochs.abi.ts` for why that\n * read is quarantined to its own ABI.\n */\nexport interface KeyEpochs {\n vpKeyEpoch: bigint;\n appKeeperKeyEpoch: bigint;\n ucKeyEpoch: bigint;\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 /**\n * Read a vault provider's *genesis* (registration) BTC key — the key bonded\n * at version 0, which never moves when the operator rotates.\n *\n * Used only as the genesis fallback for epoch-based resolution and as a\n * candidate when cross-checking an indexer hint. Never the key to build a\n * Bitcoin lock with; that comes from `OperationKeyReader`.\n *\n * Resolves via `getOperationBtcKeyAtEpoch` at epoch 0, so it requires an\n * RFC-006 registry — as does every caller.\n */\n getVaultProviderGenesisBtcPubKey(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey>;\n /**\n * Read the vault provider operation key selected by an RFC-006 epoch.\n * Existing-vault consumers pass the vault's frozen `vpKeyEpoch` here so a\n * later rotation cannot move the result.\n */\n getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress: Address,\n epoch: bigint,\n blockNumber?: bigint,\n ): 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 a vault's frozen RFC-006 key epochs.\n *\n * Uses the extended `getBtcVaultProtocolInfo` ABI. Against a registry whose\n * `BTCVaultProtocolInfo` struct is not extended this returns silent garbage\n * for a populated vault rather than throwing, so it must only be called\n * against an RFC-006 registry — a deployment invariant, not something this\n * call can detect. A registry missing the operation-key getters altogether is\n * the safer case: key resolution reverts downstream and these epochs are never\n * used. See `BTCVaultRegistryKeyEpochs.abi.ts`.\n */\n getVaultKeyEpochs(vaultId: Hex): Promise<KeyEpochs>;\n /** {@link getVaultKeyEpochs} for many vaults in one multicall. */\n getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]>;\n /**\n * Read a vault provider's *current* RFC-006 operation BTC key — the key its\n * server uses for the JSON-RPC token subject. Falls back to the registration\n * key when the provider has never rotated.\n */\n getCurrentVaultProviderOperationBtcKey(\n vpAddress: Address,\n ): Promise<OnChainBtcPubkey>;\n /**\n * Read the depositor's commission ceiling (`maxAcceptableCommissionBps`)\n * for vaults registered in the same block `createdAt`, from their\n * `PegInSubmittedV2` logs, in `vaultIds` order. The contract discards the\n * ceiling after bound-checking it, so the log is its only on-chain source.\n *\n * @throws {RegistrationLogsUnavailableError} (transient, retry) when the\n * node answers with no registration logs for the block at all, with none\n * for a vault asked for, or with V1 logs only — the registry emits both\n * shapes together, so every one of those can be a partial answer.\n * @throws when a vault has more than one V2 log.\n */\n getMaxAcceptableCommissionBpsBatch(\n vaultIds: readonly Hex[],\n createdAt: bigint,\n ): Promise<number[]>;\n /**\n * Decode every `PegInSubmittedV2` registration in block `createdAt`, the\n * `block.number` stamped on the vault at registration. One query at exactly\n * that block, so no range scan is needed and public-RPC range caps do not\n * apply. Records are keyed by lowercase vault id; use\n * `findRegistrationRecord` to pick one.\n *\n * @throws {RegistrationLogsUnavailableError} (transient, retry) when the\n * node answers with no registration logs for the block at all, or with V1\n * registrations only — the registry emits both shapes together, so either\n * can be a partial answer.\n * @throws when a vault has more than one V2 log. Records are decoded\n * leniently: no transaction is parsed and no script is bound-checked here\n * (see `registration-records.ts`).\n */\n getRegistrationRecordsAtBlock(\n createdAt: bigint,\n ): Promise<PeginRegistrationRecord[]>;\n /**\n * The vault's finalized `VaultClaimableBy` log for `claimerPk` — the\n * redemption that authorized that key to claim, and the block the prover\n * proves against.\n *\n * The event's block is not stored in contract state, so it is found by\n * scanning `eth_getLogs` newest-first from the finalized block\n * (`eth_getBlockByNumber(\"finalized\")`) down to the vault's `createdAt`, in\n * chunks of `VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS`, filtered on the indexed\n * `vaultId` and `claimerPK` topics. A redeem in the last chunk costs one\n * request; an older one costs one request per chunk. The bound is\n * finalized, not latest, because the block returned is what the prover\n * proves against (`claimable_event_block_number`) and an unfinalized redeem\n * can reorg away — the same bound btc-vault's reader uses\n * (`eth-client/src/client.rs:5989-6040`, `FinalityLevel::Finalized` default\n * `config.rs:11-21`).\n *\n * A REDEEMED vault can legitimately have no log for the depositor:\n * `redeemForAVK` (RedeemLogic.sol) authorizes the vault keeper alone.\n *\n * @throws {VaultClaimableByNotFoundError} (typed) when no log exists in\n * `createdAt..finalized` — the vault is not redeemed for that key, the\n * redeem is not finalized yet, or the node did not serve the block. The\n * last case is indistinguishable here, so a caller that knows the vault is\n * redeemed for this key owns the retry (as\n * `getMaxAcceptableCommissionBpsFromChainWithGrace` does in the vault app);\n * point the read at a node that serves whole blocks, not a load balancer.\n * @throws when matching logs span more than one transaction (a vault is\n * redeemed once), or `claimerPk` is not an x-only key on the curve.\n */\n getVaultClaimableBy(\n vaultId: Hex,\n claimerPk: Hex,\n createdAt: bigint,\n ): Promise<VaultClaimableByEvent>;\n /**\n * Read the application entry point a vault provider is registered for.\n *\n * The peg-in submit path resolves this internally and uses it to pick the\n * keeper roster, the roster version and the keeper key epoch a deposit is\n * bonded to. Pass `blockNumber` when the result will shape a Bitcoin lock,\n * so it describes the same block as the roster reads that follow it.\n */\n getVaultProviderApplication(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<Address>;\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`, except\n * `peginActivationDelay`, which is surfaced via `getPeginActivationDelay()`\n * rather than on this type.\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 * Maximum number of funding inputs one Pre-PegIn may spend; the contract\n * rejects a Pre-PegIn with more. Source:\n * `IProtocolParams.TBVProtocolParams.maxFundingInputCount`. `null` means the\n * deployed ProtocolParams predates `maxFundingInputCount` and enforces no\n * funding-input bound.\n */\n maxFundingInputCount: number | null;\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 maxFundingInputCount: number | null;\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 * Currently-active vault core (tx-graph) version\n * (`ProtocolParams.activeVaultCoreVersion()`, uint16 ≥ 1). Stamped onto\n * every new vault at peg-in submission; fresh deposits must build this\n * graph version. Read in the same multicall so a governance version bump\n * can't land between reading the params and reading the version.\n */\n activeVaultCoreVersion: 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 /**\n * Pass `blockNumber` when the result will shape a Bitcoin lock, so this\n * multicall and the participant-key reads describe the same block. Omit it\n * for display-only reads, where a slightly stale value is harmless.\n */\n getPegInConfiguration(blockNumber?: bigint): Promise<PegInConfiguration>;\n /**\n * Observation window enforced between a vault's final ACK and its\n * activation, in ETH blocks measured from `verifiedAt`. `0` disables it.\n *\n * @throws If the deployment does not expose `peginActivationDelay()`, or\n * the decoded payload is not a `bigint`.\n */\n getPeginActivationDelay(): Promise<bigint>;\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/**\n * Interface for reading vault keepers from the ApplicationRegistry contract.\n *\n * The reads used to build a peg-in — here and on the sibling reader interfaces\n * — take an optional `blockNumber` that pins them to one block instead of\n * `latest`. Omitting it, the historical behaviour, is correct for every read\n * that resolves against a vault's already-frozen epochs, because those are\n * immutable once stamped. It is NOT correct for a fresh peg-in build: the\n * participant keys, roster versions and protocol params that shape the Bitcoin\n * lock must all describe the same block, or the lock commits to a mixture of\n * chain states that never existed at once. See\n * `services/deposit/validateOnChainParticipantKeys`.\n *\n * The `getCurrent*` roster reads are the exception and take no block. Nothing\n * on the build path uses them — it resolves rosters by version instead — so\n * they were left alone rather than given a pin no caller would pass.\n */\nexport interface VaultKeeperReader {\n getVaultKeepersByVersion(\n appEntryPoint: Address,\n version: number,\n blockNumber?: bigint,\n ): Promise<AddressBTCKeyPair[]>;\n getCurrentVaultKeepers(appEntryPoint: Address): Promise<AddressBTCKeyPair[]>;\n getCurrentVaultKeepersVersion(\n appEntryPoint: Address,\n blockNumber?: bigint,\n ): Promise<number>;\n /**\n * Read the application's current vault-keeper operation-key epoch.\n *\n * One counter for the whole application, bumped by any keeper's\n * operation-key or payout-script append. The peg-in config fingerprint\n * commits to it in place of the N resolved keeper keys, so it must be read\n * at the same block as the roster it labels. Returned as `bigint`; the\n * contract encodes it as `uint64` and a `Number` would truncate.\n */\n getCurrentAppKeeperKeyEpoch(\n appEntryPoint: Address,\n blockNumber?: bigint,\n ): Promise<bigint>;\n}\n\n/** Interface for reading universal challengers from the ProtocolParams contract. */\nexport interface UniversalChallengerReader {\n getUniversalChallengersByVersion(\n version: number,\n blockNumber?: bigint,\n ): Promise<AddressBTCKeyPair[]>;\n getCurrentUniversalChallengers(): Promise<AddressBTCKeyPair[]>;\n getLatestUniversalChallengersVersion(blockNumber?: bigint): Promise<number>;\n /**\n * Read the protocol's current universal-challenger operation-key epoch.\n *\n * The challenger-axis counterpart to\n * {@link VaultKeeperReader.getCurrentAppKeeperKeyEpoch}: one protocol-wide\n * counter the fingerprint commits to in place of the M resolved challenger\n * keys. Returned as `bigint` for the same `uint64` reason.\n */\n getCurrentUcKeyEpoch(blockNumber?: bigint): Promise<bigint>;\n}\n\n// ============================================================================\n// RFC-006 Operation-Key Types\n// ============================================================================\n\n/**\n * The participants whose operation keys are being resolved, and the roster\n * they are resolved against.\n *\n * A roster entry's `ethAddress` is the operator's **admin** address — the\n * lookup key for its key history — and its `btcPubKey` is the operator's\n * **genesis** key. Both are needed: the `...AtEpochOrGenesis` getters take the\n * roster key explicitly because the correct genesis for a keeper/challenger is\n * its key in the vault's *frozen membership version*, which an operator that\n * was later dropped from the roster no longer has a current entry for.\n */\nexport interface OperationKeyQuery {\n vaultProviderEthAddress: Address;\n /**\n * The VP's genesis (registration) key, from\n * {@link VaultRegistryReader.getVaultProviderGenesisBtcPubKey}.\n *\n * The VP has no roster entry to carry a genesis key the way keepers and\n * challengers do, so it is supplied here. Every call site already reads it:\n * it is what the indexer hint is compared against, and what makes the VP's\n * `rotated` flag mean the same thing as everyone else's.\n */\n vaultProviderGenesisBtcPubkey: Hex;\n applicationEntryPoint: Address;\n /** Keeper roster at the membership version being resolved against. */\n vaultKeepers: readonly AddressBTCKeyPair[];\n /** Challenger roster at the membership version being resolved against. */\n universalChallengers: readonly AddressBTCKeyPair[];\n}\n\n/** Raw registry-returned operation keys, index-aligned with the query rosters. */\nexport interface RawOperationKeys {\n vaultProvider: Hex;\n vaultKeepers: Hex[];\n universalChallengers: Hex[];\n}\n\n/**\n * Registry-returned payout scriptPubKeys, index-aligned with the query\n * rosters. `universalChallengers` has no counterpart: a UC is never a claimer,\n * so it has no payout script.\n */\nexport interface RawPayoutScripts {\n vaultProvider: Hex;\n vaultKeepers: Hex[];\n}\n\n/**\n * Reads RFC-006 operation keys and payout scripts across all three registries\n * (BTCVaultRegistry, ApplicationRegistry, ProtocolParams).\n *\n * Every method resolves the whole participant set in a **single** multicall so\n * the keys are pinned to one block. That atomicity is load-bearing: a rotation\n * landing between two `eth_call`s would yield a self-inconsistent key set that\n * builds a lock no counterparty agrees with.\n */\nexport interface OperationKeyReader {\n /**\n * Resolve every participant's *current* operation key.\n *\n * Used for new peg-ins. The VP-only current getter separately supplies the\n * JSON-RPC auth pin. Needs no epoch read at all — each registry's\n * `getCurrentOperationBtcKey` resolves its own genesis fallback, so an\n * operator that never rotated yields its registration key.\n */\n getCurrentOperationKeys(\n query: OperationKeyQuery,\n blockNumber?: bigint,\n ): Promise<RawOperationKeys>;\n /**\n * Resolve every participant's operation key bonded at a vault's frozen\n * epochs. Used for every existing-vault path (resume, payout, refund).\n */\n getOperationKeysAtEpochs(\n query: OperationKeyQuery,\n epochs: KeyEpochs,\n ): Promise<RawOperationKeys>;\n /**\n * Resolve the VP's commission payout script and each keeper's payout script\n * at a vault's frozen epochs.\n *\n * The registry backfills BIP-86 P2TR of the epoch's operation key for any\n * operator that never called `setPayoutScript`, so this returns byte-identical\n * results to local BIP-86 derivation until an operator registers a custom\n * script.\n */\n getPayoutScriptsAtEpochs(\n query: OperationKeyQuery,\n epochs: KeyEpochs,\n ): Promise<RawPayoutScripts>;\n}\n"],"names":["UINT16_MAX","PRE_FUNDING_INPUT_CAP_TBV_PARAMS_ABI","requireSuccess","entry","mapOffchainParams","result","mapTBVParams","maxFundingInputCount","resolveTBVParams","withFundingInputCap","preFundingInputCap","raw","deriveTimelockPegin","timelockAssert","ViemProtocolParamsReader","publicClient","contractAddress","params","validateTBVProtocolParams","ProtocolParamsABI","validateOffchainParams","version","assertValidOffchainParamsVersion","blockNumber","results","tbvParams","offchainParams","offchainParamsVersion","activeVaultCoreVersion","config","validatePegInConfiguration","onSkippedVersion","latestVersion","versions","_","i","contracts","v","byVersion","error","OnChainBtcVaultStatus"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-BC2TGzcp.cjs","sources":["../src/tbv/core/clients/eth/protocol-params-reader.ts","../src/tbv/core/clients/eth/types.ts"],"sourcesContent":["/**\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. btc-vault carries the PegIn timelock as\n * a `NonZeroU16` (`transactions/pegin.rs:33` @ ac4954e7), so a larger\n * `timelockAssert` has no protocol-side representation.\n */\nconst UINT16_MAX = 65535;\n\n// Decodes deployments that predate `maxFundingInputCount`, including those that also predate `peginActivationDelay`; delete it once every network returns 8 fields.\nconst PRE_FUNDING_INPUT_CAP_TBV_PARAMS_ABI = [\n {\n type: \"function\",\n name: \"getTBVProtocolParams\",\n inputs: [],\n outputs: [\n {\n name: \"\",\n type: \"tuple\",\n internalType: \"struct IProtocolParams.TBVProtocolParams\",\n components: [\n {\n name: \"minimumPegInAmount\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"maxPegInAmount\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"pegInAckTimeout\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"pegInActivationTimeout\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n {\n name: \"maxHtlcOutputCount\",\n type: \"uint8\",\n internalType: \"uint8\",\n },\n {\n name: \"expiredPegInGraceBlocks\",\n type: \"uint64\",\n internalType: \"uint64\",\n },\n ],\n },\n ],\n stateMutability: \"view\",\n },\n] as const;\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 maxFundingInputCount: number;\n}\n\ntype RawPreFundingInputCapTBVParams = Omit<\n RawTBVParams,\n \"maxFundingInputCount\"\n>;\n\ntype MulticallEntry =\n | { status: \"success\"; result: unknown }\n | { status: \"failure\"; error: Error };\n\nfunction requireSuccess(entry: MulticallEntry): unknown {\n if (entry.status === \"failure\") {\n throw entry.error;\n }\n return entry.result;\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(\n result: RawPreFundingInputCapTBVParams,\n maxFundingInputCount: number | null,\n): 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 maxFundingInputCount,\n };\n}\n\nfunction resolveTBVParams(\n withFundingInputCap: MulticallEntry,\n preFundingInputCap: MulticallEntry,\n): TBVProtocolParams {\n if (withFundingInputCap.status === \"success\") {\n const raw = withFundingInputCap.result as RawTBVParams;\n return mapTBVParams(raw, raw.maxFundingInputCount);\n }\n if (preFundingInputCap.status === \"success\") {\n return mapTBVParams(\n preFundingInputCap.result as RawPreFundingInputCapTBVParams,\n null,\n );\n }\n throw withFundingInputCap.error;\n}\n\n/**\n * Derive timelockPegin from timelockAssert.\n *\n * btc-vault uses `timelock_assert` as the PegIn timelock (vaultd\n * `pegin_babe_setup.rs:794` @ ac4954e7) and carries it as a `NonZeroU16`\n * (`transactions/pegin.rs:33`).\n * `ProtocolParams.sol:510-512` @ c559f5c2 rejects a zero or above-uint16\n * `timelockAssert` on write; the upper bound is enforced again here so a bad\n * read fails early instead of truncating.\n *\n * @throws if timelockAssert exceeds uint16 max (65535)\n */\nexport function 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 [withFundingInputCap, preFundingInputCap] =\n await this.publicClient.multicall({\n contracts: this.tbvParamsCalls(),\n allowFailure: true,\n });\n\n const params = resolveTBVParams(withFundingInputCap, preFundingInputCap);\n validateTBVProtocolParams(params);\n return params;\n }\n\n private tbvParamsCalls() {\n return [\n {\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"getTBVProtocolParams\",\n },\n {\n address: this.contractAddress,\n abi: PRE_FUNDING_INPUT_CAP_TBV_PARAMS_ABI,\n functionName: \"getTBVProtocolParams\",\n },\n ] as const;\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 * Returned as `bigint` with no `Number` narrowing: the registry compares it\n * against `block.number`, so callers must do the same arithmetic the\n * contract does. `0` is the documented \"disabled\" case and is returned as\n * `0n`. A missing getter or a non-bigint payload throws — never coerced to\n * `0`, which would fail open and skip the observation window.\n *\n * @throws If the deployment does not expose `peginActivationDelay()`, or\n * the decoded payload is not a `bigint`.\n */\n async getPeginActivationDelay(): Promise<bigint> {\n const raw: unknown = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"peginActivationDelay\",\n });\n if (typeof raw !== \"bigint\") {\n throw new Error(\n `Invalid peginActivationDelay from contract: must be a bigint, got ${typeof raw}`,\n );\n }\n return raw;\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 * That guarantee holds only within this multicall. A caller that also reads\n * participant keys — every fresh peg-in build does — must pass the same\n * `blockNumber` here and to those reads, or the two describe different\n * blocks and the pairing above buys nothing across the seam.\n */\n async getPegInConfiguration(\n blockNumber?: bigint,\n ): Promise<PegInConfiguration> {\n const results = await this.publicClient.multicall({\n blockNumber,\n contracts: [\n ...this.tbvParamsCalls(),\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 address: this.contractAddress,\n abi: ProtocolParamsABI,\n functionName: \"activeVaultCoreVersion\",\n },\n ],\n allowFailure: true,\n });\n\n const tbvParams = resolveTBVParams(results[0], results[1]);\n const offchainParams = mapOffchainParams(\n requireSuccess(results[2]) as RawOffchainParams,\n );\n const offchainParamsVersion = Number(requireSuccess(results[3]));\n const activeVaultCoreVersion = Number(requireSuccess(results[4]));\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 maxFundingInputCount: tbvParams.maxFundingInputCount,\n timelockPegin: deriveTimelockPegin(offchainParams.timelockAssert),\n timelockRefund: offchainParams.tRefund,\n minVpCommissionBps: offchainParams.minVpCommissionBps,\n offchainParams,\n offchainParamsVersion,\n activeVaultCoreVersion,\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 * 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 an on-chain\n * registry. Minted only by `assertOnChainBtcPubkey`, which is the shared\n * validator behind both producers:\n * {@link VaultRegistryReader.getVaultProviderGenesisBtcPubKey} (the fixed\n * registration key) and {@link OperationKeyReader} (RFC-006 operation keys,\n * resolved current or at a vault's frozen epoch).\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 /**\n * ETH block number stamped at the Pending→Verified transition.\n * Compared against `block.number` (inclusive:\n * `block.number >= verifiedAt + peginActivationDelay`), never a unix timestamp.\n */\n verifiedAt: bigint;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n depositorPopSignature: Hex;\n prePeginTxHash: Hex;\n vaultProviderCommissionBps: number;\n /**\n * Last ETH block (inclusive) at which `claimExpiredVault` is accepted for\n * this vault. Frozen when the vault is reported expired, as that block plus\n * `expiredPegInGraceBlocks`; zero until then. Only meaningful for a vault\n * that expired after reaching Verified (`verifiedAt > 0`) — the contract\n * rejects the claim for any other.\n */\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/**\n * One vault's `PegInSubmittedV2` registration log, decoded.\n *\n * The registry discards several of these values after using them\n * (`maxAcceptableCommissionBps` is bound-checked and dropped), so the log is\n * their only on-chain source. Decoded leniently — no transaction is parsed and\n * no script is bound-checked here, so one malformed registration elsewhere in\n * the block cannot fail an unrelated caller's read; the strict per-record\n * checks live in `registration-records.ts` and run on selected records only.\n * That leniency stops at duplicates: a vault registers once, so two logs for\n * any vault id are an inconsistent node and fail the whole block's read\n * closed.\n *\n * @experimental\n */\nexport interface PeginRegistrationRecord {\n /** Lowercase, `0x`-prefixed. */\n vaultId: Hex;\n depositor: Address;\n vaultProvider: Address;\n /** btc-vault `pegin_amount`, satoshis. */\n amount: bigint;\n vaultCoreVersion: number;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n proverCircuitVersion: number;\n offchainParamsVersion: number;\n /**\n * The event's own `peginTxHash`: the txid of this vault's depositor-signed\n * PegIn, which with `depositor` re-derives the vault id. Per-vault, unlike\n * {@link PeginRegistrationRecord.unsignedPrePeginTx}, which siblings share.\n */\n peginTxHash: Hex;\n /**\n * The event's `depositorPayoutBtcAddress` bytes: the depositor's payout\n * scriptPubKey as `submitPeginRequest` received it (BTCVaultRegistry.sol\n * documents the parameter as \"BTC payout address (scriptPubKey)\"; the SDK\n * registers the validated scriptPubKey there). Lowercase, `0x`-prefixed.\n */\n depositorPayoutScriptPubKey: Hex;\n /**\n * The log's `unsignedPrePeginTx`, verbatim. Its txid\n * (`registrationPrePeginTxHash`) equals\n * {@link VaultProtocolInfo.prePeginTxHash}; siblings of one batch share it,\n * while the event's own `peginTxHash` is the per-vault PegIn id.\n */\n unsignedPrePeginTx: Hex;\n maxAcceptableCommissionBps: number;\n blockNumber: bigint;\n}\n\n/**\n * A vault's finalized `VaultClaimableBy` log for one claimer key.\n *\n * `blockNumber` is what the artifacts file records as\n * `claimable_event_block_number`, the block the prover proves against.\n *\n * @experimental\n */\nexport interface VaultClaimableByEvent {\n blockNumber: bigint;\n /** The `claimerPK` topic, validated as an x-only key. */\n claimerPk: OnChainBtcPubkey;\n peginTxHash: Hex;\n vaultCoreVersion: number;\n proverCircuitVersion: number;\n offchainParamsVersion: number;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n}\n\n/**\n * RFC-006 operation-key epochs a vault froze at `submitPeginRequest`.\n *\n * Each registry keeps a monotonic epoch counter that every key/payout setter\n * pre-increments. A vault stamps the counters live at its creation, and every\n * participant resolves \"which key did this vault bond?\" by asking the registry\n * for the key whose appended version is the latest stamped `<=` this epoch. A\n * rotation after the vault was created therefore never moves its keys.\n *\n * `uint64` — kept as `bigint` end-to-end and passed straight back to the\n * `...AtEpoch` getters, never narrowed through `Number`.\n *\n * Only ever read through {@link VaultRegistryReader.getVaultKeyEpochs}, which\n * uses the extended ABI. See `BTCVaultRegistryKeyEpochs.abi.ts` for why that\n * read is quarantined to its own ABI.\n */\nexport interface KeyEpochs {\n vpKeyEpoch: bigint;\n appKeeperKeyEpoch: bigint;\n ucKeyEpoch: bigint;\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 /**\n * Read a vault provider's *genesis* (registration) BTC key — the key bonded\n * at version 0, which never moves when the operator rotates.\n *\n * Used only as the genesis fallback for epoch-based resolution and as a\n * candidate when cross-checking an indexer hint. Never the key to build a\n * Bitcoin lock with; that comes from `OperationKeyReader`.\n *\n * Resolves via `getOperationBtcKeyAtEpoch` at epoch 0, so it requires an\n * RFC-006 registry — as does every caller.\n */\n getVaultProviderGenesisBtcPubKey(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey>;\n /**\n * Read the vault provider operation key selected by an RFC-006 epoch.\n * Existing-vault consumers pass the vault's frozen `vpKeyEpoch` here so a\n * later rotation cannot move the result.\n */\n getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress: Address,\n epoch: bigint,\n blockNumber?: bigint,\n ): 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 a vault's frozen RFC-006 key epochs.\n *\n * Uses the extended `getBtcVaultProtocolInfo` ABI. Against a registry whose\n * `BTCVaultProtocolInfo` struct is not extended this returns silent garbage\n * for a populated vault rather than throwing, so it must only be called\n * against an RFC-006 registry — a deployment invariant, not something this\n * call can detect. A registry missing the operation-key getters altogether is\n * the safer case: key resolution reverts downstream and these epochs are never\n * used. See `BTCVaultRegistryKeyEpochs.abi.ts`.\n */\n getVaultKeyEpochs(vaultId: Hex): Promise<KeyEpochs>;\n /** {@link getVaultKeyEpochs} for many vaults in one multicall. */\n getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]>;\n /**\n * Read a vault provider's *current* RFC-006 operation BTC key — the key its\n * server uses for the JSON-RPC token subject. Falls back to the registration\n * key when the provider has never rotated.\n */\n getCurrentVaultProviderOperationBtcKey(\n vpAddress: Address,\n ): Promise<OnChainBtcPubkey>;\n /**\n * Read the depositor's commission ceiling (`maxAcceptableCommissionBps`)\n * for vaults registered in the same block `createdAt`, from their\n * `PegInSubmittedV2` logs, in `vaultIds` order. The contract discards the\n * ceiling after bound-checking it, so the log is its only on-chain source.\n *\n * @throws {RegistrationLogsUnavailableError} (transient, retry) when the\n * node answers with no registration logs for the block at all, with none\n * for a vault asked for, or with V1 logs only — the registry emits both\n * shapes together, so every one of those can be a partial answer.\n * @throws when a vault has more than one V2 log.\n */\n getMaxAcceptableCommissionBpsBatch(\n vaultIds: readonly Hex[],\n createdAt: bigint,\n ): Promise<number[]>;\n /**\n * Decode every `PegInSubmittedV2` registration in block `createdAt`, the\n * `block.number` stamped on the vault at registration. One query at exactly\n * that block, so no range scan is needed and public-RPC range caps do not\n * apply. Records are keyed by lowercase vault id; use\n * `findRegistrationRecord` to pick one.\n *\n * @throws {RegistrationLogsUnavailableError} (transient, retry) when the\n * node answers with no registration logs for the block at all, or with V1\n * registrations only — the registry emits both shapes together, so either\n * can be a partial answer.\n * @throws when a vault has more than one V2 log. Records are decoded\n * leniently: no transaction is parsed and no script is bound-checked here\n * (see `registration-records.ts`).\n */\n getRegistrationRecordsAtBlock(\n createdAt: bigint,\n ): Promise<PeginRegistrationRecord[]>;\n /**\n * The vault's finalized `VaultClaimableBy` log for `claimerPk` — the\n * redemption that authorized that key to claim, and the block the prover\n * proves against.\n *\n * The event's block is not stored in contract state, so it is found by\n * scanning `eth_getLogs` newest-first from the finalized block\n * (`eth_getBlockByNumber(\"finalized\")`) down to the vault's `createdAt`, in\n * chunks of `VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS`, filtered on the indexed\n * `vaultId` and `claimerPK` topics. A redeem in the last chunk costs one\n * request; an older one costs one request per chunk. The bound is\n * finalized, not latest, because the block returned is what the prover\n * proves against (`claimable_event_block_number`) and an unfinalized redeem\n * can reorg away — the same bound btc-vault's reader uses\n * (`eth-client/src/client.rs:5989-6040`, `FinalityLevel::Finalized` default\n * `config.rs:11-21`).\n *\n * A REDEEMED vault can legitimately have no log for the depositor:\n * `redeemForAVK` (RedeemLogic.sol) authorizes the vault keeper alone.\n *\n * @throws {VaultClaimableByNotFoundError} (typed) when no log exists in\n * `createdAt..finalized` — the vault is not redeemed for that key, the\n * redeem is not finalized yet, or the node did not serve the block. The\n * last case is indistinguishable here, so a caller that knows the vault is\n * redeemed for this key owns the retry (as\n * `getMaxAcceptableCommissionBpsFromChainWithGrace` does in the vault app);\n * point the read at a node that serves whole blocks, not a load balancer.\n * @throws when matching logs span more than one transaction (a vault is\n * redeemed once), or `claimerPk` is not an x-only key on the curve.\n */\n getVaultClaimableBy(\n vaultId: Hex,\n claimerPk: Hex,\n createdAt: bigint,\n ): Promise<VaultClaimableByEvent>;\n /**\n * Read the application entry point a vault provider is registered for.\n *\n * The peg-in submit path resolves this internally and uses it to pick the\n * keeper roster, the roster version and the keeper key epoch a deposit is\n * bonded to. Pass `blockNumber` when the result will shape a Bitcoin lock,\n * so it describes the same block as the roster reads that follow it.\n */\n getVaultProviderApplication(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<Address>;\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`, except\n * `peginActivationDelay`, which is surfaced via `getPeginActivationDelay()`\n * rather than on this type.\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 * Maximum number of funding inputs one Pre-PegIn may spend; the contract\n * rejects a Pre-PegIn with more. Source:\n * `IProtocolParams.TBVProtocolParams.maxFundingInputCount`. `null` means the\n * deployed ProtocolParams predates `maxFundingInputCount` and enforces no\n * funding-input bound.\n */\n maxFundingInputCount: number | null;\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 maxFundingInputCount: number | null;\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 * Currently-active vault core (tx-graph) version\n * (`ProtocolParams.activeVaultCoreVersion()`, uint16 ≥ 1). Stamped onto\n * every new vault at peg-in submission; fresh deposits must build this\n * graph version. Read in the same multicall so a governance version bump\n * can't land between reading the params and reading the version.\n */\n activeVaultCoreVersion: 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 /**\n * Pass `blockNumber` when the result will shape a Bitcoin lock, so this\n * multicall and the participant-key reads describe the same block. Omit it\n * for display-only reads, where a slightly stale value is harmless.\n */\n getPegInConfiguration(blockNumber?: bigint): Promise<PegInConfiguration>;\n /**\n * Observation window enforced between a vault's final ACK and its\n * activation, in ETH blocks measured from `verifiedAt`. `0` disables it.\n *\n * @throws If the deployment does not expose `peginActivationDelay()`, or\n * the decoded payload is not a `bigint`.\n */\n getPeginActivationDelay(): Promise<bigint>;\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/**\n * Interface for reading vault keepers from the ApplicationRegistry contract.\n *\n * The reads used to build a peg-in — here and on the sibling reader interfaces\n * — take an optional `blockNumber` that pins them to one block instead of\n * `latest`. Omitting it, the historical behaviour, is correct for every read\n * that resolves against a vault's already-frozen epochs, because those are\n * immutable once stamped. It is NOT correct for a fresh peg-in build: the\n * participant keys, roster versions and protocol params that shape the Bitcoin\n * lock must all describe the same block, or the lock commits to a mixture of\n * chain states that never existed at once. See\n * `services/deposit/validateOnChainParticipantKeys`.\n *\n * The `getCurrent*` roster reads are the exception and take no block. Nothing\n * on the build path uses them — it resolves rosters by version instead — so\n * they were left alone rather than given a pin no caller would pass.\n */\nexport interface VaultKeeperReader {\n getVaultKeepersByVersion(\n appEntryPoint: Address,\n version: number,\n blockNumber?: bigint,\n ): Promise<AddressBTCKeyPair[]>;\n getCurrentVaultKeepers(appEntryPoint: Address): Promise<AddressBTCKeyPair[]>;\n getCurrentVaultKeepersVersion(\n appEntryPoint: Address,\n blockNumber?: bigint,\n ): Promise<number>;\n /**\n * Read the application's current vault-keeper operation-key epoch.\n *\n * One counter for the whole application, bumped by any keeper's\n * operation-key or payout-script append. The peg-in config fingerprint\n * commits to it in place of the N resolved keeper keys, so it must be read\n * at the same block as the roster it labels. Returned as `bigint`; the\n * contract encodes it as `uint64` and a `Number` would truncate.\n */\n getCurrentAppKeeperKeyEpoch(\n appEntryPoint: Address,\n blockNumber?: bigint,\n ): Promise<bigint>;\n}\n\n/** Interface for reading universal challengers from the ProtocolParams contract. */\nexport interface UniversalChallengerReader {\n getUniversalChallengersByVersion(\n version: number,\n blockNumber?: bigint,\n ): Promise<AddressBTCKeyPair[]>;\n getCurrentUniversalChallengers(): Promise<AddressBTCKeyPair[]>;\n getLatestUniversalChallengersVersion(blockNumber?: bigint): Promise<number>;\n /**\n * Read the protocol's current universal-challenger operation-key epoch.\n *\n * The challenger-axis counterpart to\n * {@link VaultKeeperReader.getCurrentAppKeeperKeyEpoch}: one protocol-wide\n * counter the fingerprint commits to in place of the M resolved challenger\n * keys. Returned as `bigint` for the same `uint64` reason.\n */\n getCurrentUcKeyEpoch(blockNumber?: bigint): Promise<bigint>;\n}\n\n// ============================================================================\n// RFC-006 Operation-Key Types\n// ============================================================================\n\n/**\n * The participants whose operation keys are being resolved, and the roster\n * they are resolved against.\n *\n * A roster entry's `ethAddress` is the operator's **admin** address — the\n * lookup key for its key history — and its `btcPubKey` is the operator's\n * **genesis** key. Both are needed: the `...AtEpochOrGenesis` getters take the\n * roster key explicitly because the correct genesis for a keeper/challenger is\n * its key in the vault's *frozen membership version*, which an operator that\n * was later dropped from the roster no longer has a current entry for.\n */\nexport interface OperationKeyQuery {\n vaultProviderEthAddress: Address;\n /**\n * The VP's genesis (registration) key, from\n * {@link VaultRegistryReader.getVaultProviderGenesisBtcPubKey}.\n *\n * The VP has no roster entry to carry a genesis key the way keepers and\n * challengers do, so it is supplied here. Every call site already reads it:\n * it is what the indexer hint is compared against, and what makes the VP's\n * `rotated` flag mean the same thing as everyone else's.\n */\n vaultProviderGenesisBtcPubkey: Hex;\n applicationEntryPoint: Address;\n /** Keeper roster at the membership version being resolved against. */\n vaultKeepers: readonly AddressBTCKeyPair[];\n /** Challenger roster at the membership version being resolved against. */\n universalChallengers: readonly AddressBTCKeyPair[];\n}\n\n/** Raw registry-returned operation keys, index-aligned with the query rosters. */\nexport interface RawOperationKeys {\n vaultProvider: Hex;\n vaultKeepers: Hex[];\n universalChallengers: Hex[];\n}\n\n/**\n * Registry-returned payout scriptPubKeys, index-aligned with the query\n * rosters. `universalChallengers` has no counterpart: a UC is never a claimer,\n * so it has no payout script.\n */\nexport interface RawPayoutScripts {\n vaultProvider: Hex;\n vaultKeepers: Hex[];\n}\n\n/**\n * Reads RFC-006 operation keys and payout scripts across all three registries\n * (BTCVaultRegistry, ApplicationRegistry, ProtocolParams).\n *\n * Every method resolves the whole participant set in a **single** multicall so\n * the keys are pinned to one block. That atomicity is load-bearing: a rotation\n * landing between two `eth_call`s would yield a self-inconsistent key set that\n * builds a lock no counterparty agrees with.\n */\nexport interface OperationKeyReader {\n /**\n * Resolve every participant's *current* operation key.\n *\n * Used for new peg-ins. The VP-only current getter separately supplies the\n * JSON-RPC auth pin. Needs no epoch read at all — each registry's\n * `getCurrentOperationBtcKey` resolves its own genesis fallback, so an\n * operator that never rotated yields its registration key.\n */\n getCurrentOperationKeys(\n query: OperationKeyQuery,\n blockNumber?: bigint,\n ): Promise<RawOperationKeys>;\n /**\n * Resolve every participant's operation key bonded at a vault's frozen\n * epochs. Used for every existing-vault path (resume, payout, refund).\n */\n getOperationKeysAtEpochs(\n query: OperationKeyQuery,\n epochs: KeyEpochs,\n ): Promise<RawOperationKeys>;\n /**\n * Resolve the VP's commission payout script and each keeper's payout script\n * at a vault's frozen epochs.\n *\n * The registry backfills BIP-86 P2TR of the epoch's operation key for any\n * operator that never called `setPayoutScript`, so this returns byte-identical\n * results to local BIP-86 derivation until an operator registers a custom\n * script.\n */\n getPayoutScriptsAtEpochs(\n query: OperationKeyQuery,\n epochs: KeyEpochs,\n ): Promise<RawPayoutScripts>;\n}\n"],"names":["UINT16_MAX","PRE_FUNDING_INPUT_CAP_TBV_PARAMS_ABI","requireSuccess","entry","mapOffchainParams","result","mapTBVParams","maxFundingInputCount","resolveTBVParams","withFundingInputCap","preFundingInputCap","raw","deriveTimelockPegin","timelockAssert","ViemProtocolParamsReader","publicClient","contractAddress","params","validateTBVProtocolParams","ProtocolParamsABI","validateOffchainParams","version","assertValidOffchainParamsVersion","blockNumber","results","tbvParams","offchainParams","offchainParamsVersion","activeVaultCoreVersion","config","validatePegInConfiguration","onSkippedVersion","latestVersion","versions","_","i","contracts","v","byVersion","error","OnChainBtcVaultStatus"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
"use strict";const l=require("bitcoinjs-lib"),v=require("./tbv/core/wasm/index.cjs"),k=require("./fundPeginTransaction-54-Rwb2k.cjs"),c=require("./bitcoin-D-O2GjbC.cjs"),Pe=require("./secp256k1-DDHQ1_za.cjs"),a=require("buffer"),h=require("./constants-CAm10Qwp.cjs"),pe=require("@bitcoin-js/tiny-secp256k1-asmjs"),U=require("./validation-C6XTfZak.cjs");function he(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const r in e)if(r!=="default"){const o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:()=>e[r]})}}return t.default=e,Object.freeze(t)}const ee=he(pe);function m(e){return c.processPublicKeyToXOnly(e).toLowerCase()}function de(e,t,r){const o=new Set;o.add(m(e));for(const i of t)o.add(m(i));return o.delete(m(r)),o.size}function te(e){const t=m(e.claimerBtcPubkey),r=m(e.depositorBtcPubkey),o=e.vaultKeeperBtcPubkeys.map(m);if(t===r){const n=o.filter(u=>u!==r);if(n.length===0)throw new Error("Cannot derive localChallengers: vault keeper set is empty (or contains only the depositor)");if(new Set(n).size!==n.length)throw new Error("Cannot derive localChallengers: duplicate vaultKeeper key — signing context is misconfigured");return n}const s=[...new Set([m(e.vaultProviderBtcPubkey),...o])].sort().filter(n=>n!==t);if(s.length===0)throw new Error(`Cannot derive localChallengers: no vault provider or vault keeper remains after excluding claimer ${t}`);return s}const fe=32,ge=65535,Ee=2;function I(e,t){const r=c.stripHexPrefix(e).toLowerCase();if(!/^[0-9a-f]{64}$/.test(r))throw new Error(`${t} must be a 32-byte x-only public key.`);try{Pe.secp256k1.Point.fromBytes(a.Buffer.concat([a.Buffer.from([Ee]),a.Buffer.from(r,"hex")]))}catch{throw new Error(`${t} is not a secp256k1 x-coordinate.`)}return r}function O(e,t){if(e.length===0)throw new Error(`${t} must not be empty.`);const r=e.map((o,i)=>I(o,`${t}[${i}]`)).sort();if(new Set(r).size!==r.length)throw new Error(`${t} must not contain duplicate keys.`);return r}function R(e,t){const r=[];return e.forEach((o,i)=>{r.push(a.Buffer.from(o,"hex"),i===0?l.opcodes.OP_CHECKSIG:l.opcodes.OP_CHECKSIGADD)}),r.push(l.script.number.encode(e.length),t?l.opcodes.OP_NUMEQUALVERIFY:l.opcodes.OP_NUMEQUAL),r}function re(e,t){var w;c.assertEccInitialized();const r=I(e.depositorPubkey,"depositorPubkey"),o=I(e.vaultProviderPubkey,"vaultProviderPubkey"),i=O(e.vaultKeeperPubkeys,"vaultKeeperPubkeys"),s=O(e.universalChallengerPubkeys,"universalChallengerPubkeys"),n=c.stripHexPrefix(t).toLowerCase();if(!/^[0-9a-f]{64}$/.test(n))throw new Error("hashlock must be 32 bytes.");if(!Number.isInteger(e.timelockRefund)||e.timelockRefund<1||e.timelockRefund>ge)throw new Error("timelockRefund must be an integer from 1 to 65535.");const u=l.script.compile([l.opcodes.OP_SIZE,l.script.number.encode(fe),l.opcodes.OP_EQUALVERIFY,l.opcodes.OP_SHA256,a.Buffer.from(n,"hex"),l.opcodes.OP_EQUALVERIFY,a.Buffer.from(r,"hex"),l.opcodes.OP_CHECKSIGVERIFY,a.Buffer.from(o,"hex"),l.opcodes.OP_CHECKSIGVERIFY,...R(i,!0),...R(s,!1)]),d=l.script.compile([a.Buffer.from(r,"hex"),l.opcodes.OP_CHECKSIGVERIFY,l.script.number.encode(e.timelockRefund),l.opcodes.OP_CHECKSEQUENCEVERIFY]),p=[{output:u,version:c.TAPSCRIPT_LEAF_VERSION},{output:d,version:c.TAPSCRIPT_LEAF_VERSION}],{hash:f,output:P,witness:E}=l.payments.p2tr({internalPubkey:a.Buffer.from(v.tapInternalPubkey),scriptTree:p,redeem:{output:u,redeemVersion:c.TAPSCRIPT_LEAF_VERSION}}),g=E==null?void 0:E[E.length-1],S=l.payments.p2tr({internalPubkey:a.Buffer.from(v.tapInternalPubkey),scriptTree:p,redeem:{output:d,redeemVersion:c.TAPSCRIPT_LEAF_VERSION}}),y=(w=S.witness)==null?void 0:w[S.witness.length-1];if(!f||!P||!g||!y)throw new Error("Failed to derive the expected Pre-PegIn HTLC output.");return{hashlockScript:u,hashlockControlBlock:g,refundScript:d,refundControlBlock:y,scriptPubKey:P,tapMerkleRoot:f}}function we(e,t){c.assertEccInitialized();const r=I(e.depositorPubkey,"depositorPubkey"),o=I(e.vaultProviderPubkey,"vaultProviderPubkey"),i=O(e.vaultKeeperPubkeys,"vaultKeeperPubkeys"),s=O(e.universalChallengerPubkeys,"universalChallengerPubkeys"),n=l.script.compile([a.Buffer.from(r,"hex"),l.opcodes.OP_CHECKSIGVERIFY,a.Buffer.from(o,"hex"),l.opcodes.OP_CHECKSIGVERIFY,...R(i,!0),...R(s,!0),l.script.number.encode(t),l.opcodes.OP_CHECKSEQUENCEVERIFY]),{output:u}=l.payments.p2tr({internalPubkey:a.Buffer.from(v.tapInternalPubkey),scriptTree:{output:n,version:c.TAPSCRIPT_LEAF_VERSION}});if(!u)throw new Error("Failed to derive the expected PegIn payout output.");return u}async function ye(e,t){const r=t.pegInAmounts.length;if(t.hashlocks.length!==r)throw new Error(`Pre-PegIn has ${t.hashlocks.length} hashlock(s), expected ${r} (one per requested deposit).`);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 o=await v.computeMinClaimValue(t.vaultCoreVersion,t.numLocalChallengers,t.universalChallengerPubkeys.length,t.councilQuorum,t.councilSize,t.feeRate);if(e.depositorClaimValue!==o)throw new Error(`WASM Pre-PegIn depositorClaimValue ${e.depositorClaimValue} does not match the independently computed minimum claim value ${o} (vaultCoreVersion=${t.vaultCoreVersion}, numLocalChallengers=${t.numLocalChallengers}, numUniversalChallengers=${t.universalChallengerPubkeys.length}, councilQuorum=${t.councilQuorum}, councilSize=${t.councilSize}, feeRate=${t.feeRate}).`);const i=await v.peginP2aAnchorOutput(t.vaultCoreVersion),s=(i==null?void 0:i.value)??0n,n=await v.computeMinPeginFee(t.vaultCoreVersion,t.vaultKeeperPubkeys.length,t.universalChallengerPubkeys.length,t.minPeginFeeRate),u=n+s,d=t.minPeginFeeRate*k.MAX_REASONABLE_PEGIN_VBYTES;for(let p=0;p<r;p++){const f=t.pegInAmounts[p],P=e.peginAmounts[p],E=e.htlcValues[p];if(P!==f)throw new Error(`WASM Pre-PegIn peginAmount[${p}] ${P} does not match the requested amount ${f}; refusing to build a tx whose recorded amount differs from the depositor's request.`);if(P<=0n)throw new Error(`WASM Pre-PegIn peginAmount[${p}] is non-positive (${P}); expected > 0.`);if(E<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${p}] is non-positive (${E}); expected > 0.`);const g=E-P-e.depositorClaimValue;if(g<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${p}] ${E} does not strictly cover peginAmount ${P} + depositorClaimValue ${e.depositorClaimValue} + a PegIn reserve (implied reserve ${g}).`);if(g>d)throw new Error(`WASM Pre-PegIn implied reserve for HTLC[${p}] (${g} sat) exceeds the plausibility cap ${d} sat (minPeginFeeRate=${t.minPeginFeeRate} × ${k.MAX_REASONABLE_PEGIN_VBYTES} vbytes); htlcValue ${E} appears grossly inflated.`);if(g!==u)throw new Error(`WASM Pre-PegIn htlcValue[${p}] ${E} implies a PegIn fee+anchor reserve of ${g} sat, expected exactly ${u} sat (minPeginFee ${n} + p2aAnchor ${s} for vaultCoreVersion ${t.vaultCoreVersion}, vaultKeepers=${t.vaultKeeperPubkeys.length}, universalChallengers=${t.universalChallengerPubkeys.length}, minPeginFeeRate=${t.minPeginFeeRate}).`)}return n}class C extends Error{constructor(t){super(t),this.name="HtlcOutputMismatchError"}}function oe(e,t,r){if(e.length<t.length)throw new C(`Encoded Pre-PegIn tx has ${e.length} output(s), fewer than the ${t.length} HTLC output(s) the cross-check validated.`);for(let o=0;o<t.length;o++){const i=BigInt(e[o].value);if(i!==t[o])throw new C(`Encoded Pre-PegIn HTLC output[${o}] value ${i} does not match the cross-checked htlcValue ${t[o]}; the funded/signed tx would not pay the validated amount.`);const s=e[o].script.toString("hex").toLowerCase(),n=r[o].toLowerCase();if(s!==n)throw new C(`Encoded Pre-PegIn HTLC output[${o}] scriptPubKey ${s} does not match the cross-checked htlcScriptPubKey ${n}.`)}}function ve(e,t,r,o,i,s,n){if(s!==h.PRE_PEGIN_TX_VERSION)throw new Error(`WASM Pre-PegIn transaction version ${s}; expected ${h.PRE_PEGIN_TX_VERSION}.`);if(n!==h.PRE_PEGIN_TX_LOCKTIME)throw new Error(`WASM Pre-PegIn transaction locktime ${n}; expected ${h.PRE_PEGIN_TX_LOCKTIME}.`);if(t.length<h.PRE_PEGIN_MIN_HTLC_OUTPUT_COUNT)throw new Error(`WASM Pre-PegIn output layout has ${t.length} HTLC output(s); expected at least ${h.PRE_PEGIN_MIN_HTLC_OUTPUT_COUNT}.`);const u=t.length,d=u+ +(i!==void 0),p=k.peginOutputCount(t.length,i!==void 0);if(e.length!==p)throw new Error(`WASM Pre-PegIn output layout has ${e.length} output(s); expected exactly ${p}.`);oe(e,t,r);for(let g=0;g<t.length;g++){const S=re(o,o.hashlocks[g]).scriptPubKey;if(!e[g].script.equals(S))throw new C(`Pre-PegIn HTLC output[${g}] does not match the independently derived scriptPubKey.`)}if(i!==void 0){const g=e[u];if(g.value!==h.PRE_PEGIN_AUTH_OUTPUT_VALUE_SATS)throw new Error(`WASM Pre-PegIn auth output[${u}] value ${g.value} sat; expected exactly ${h.PRE_PEGIN_AUTH_OUTPUT_VALUE_SATS} sat.`);const S=g.script.toString("hex").toLowerCase(),y=h.PRE_PEGIN_AUTH_SCRIPT_PREFIX+i.toLowerCase();if(S!==y)throw new Error(`WASM Pre-PegIn auth output[${u}] scriptPubKey ${S}; expected ${y}.`)}const f=e[d];if(f.value!==h.PRE_PEGIN_CPFP_VALUE_SATS)throw new Error(`WASM Pre-PegIn CPFP output[${d}] value ${f.value} sat; expected exactly ${h.PRE_PEGIN_CPFP_VALUE_SATS} sat.`);const P=f.script.toString("hex").toLowerCase(),E=c.stripHexPrefix(c.deriveBip86ScriptPubKeyHex(o.depositorPubkey)).toLowerCase();if(P!==E)throw new Error(`WASM Pre-PegIn CPFP output[${d}] scriptPubKey ${P}; expected depositor BIP-86 script ${E}.`)}const ne=1;function ie(e){const t=c.stripHexPrefix(e);if(!/^[0-9a-fA-F]{64}$/.test(t))throw new Error("Invalid depositor pubkey for the depositor-claim script: must be an x-only key of 64 hex characters (32 bytes).");const r=l.script.compile([a.Buffer.from(c.hexToUint8Array(t)),l.opcodes.OP_CHECKSIG]),o=a.Buffer.from(v.tapInternalPubkey),i={output:r,redeemVersion:c.TAPSCRIPT_LEAF_VERSION},{output:s,witness:n}=l.payments.p2tr({internalPubkey:o,scriptTree:{output:r},redeem:i});if(!s)throw new Error("Failed to derive the depositor-claim P2TR scriptPubKey for PegIn output validation");const u=n==null?void 0:n[n.length-1];if(!u)throw new Error("Failed to derive the depositor-claim tapleaf control block; refusing to build an unspendable input");return{scriptPubKey:s,leafScript:r,controlBlock:u,internalKey:o}}function se(e){return ie(e).scriptPubKey}const K=64,Se=/^[0-9a-fA-F]+$/,M=65535;async function xe(e){const t=H(e.authAnchorHash),r=await v.createPrePeginTransaction({txGraphVersion:e.vaultCoreVersion,depositorPubkey:e.depositorPubkey,vaultProviderPubkey:e.vaultProviderPubkey,vaultKeeperPubkeys:e.vaultKeeperPubkeys,universalChallengerPubkeys:e.universalChallengerPubkeys,hashlocks:[...e.hashlocks],timelockRefund:e.timelockRefund,pegInAmounts:[...e.pegInAmounts],feeRate:e.feeRate,minPeginFeeRate:e.minPeginFeeRate,numLocalChallengers:e.numLocalChallengers,councilQuorum:e.councilQuorum,councilSize:e.councilSize,network:e.network,authAnchorHash:t}),o=await ye(r,e),i=k.parseUnfundedWasmTransaction(r.txHex);ve(i.outputs,r.htlcValues,r.htlcScriptPubKeys,e,t,i.version,i.locktime);const s=i.outputs.reduce((u,d)=>u+BigInt(d.value),0n),n=t!==void 0?r.htlcValues.length:null;return{psbtHex:r.txHex,totalOutputValue:s,htlcValues:r.htlcValues,htlcScriptPubKeys:r.htlcScriptPubKeys,htlcAddresses:r.htlcAddresses,peginAmounts:r.peginAmounts,depositorClaimValue:r.depositorClaimValue,authAnchorVout:n,minPeginFee:o}}function H(e){if(e===void 0)return;const t=e.startsWith("0x")||e.startsWith("0X")?e.slice(2):e;if(t.length!==K||!Se.test(t))throw new Error(`authAnchorHash must be 32-byte hex (${K} chars, no 0x prefix); got length ${t.length}`);return t.toLowerCase()}async function _e(e){if(!Number.isInteger(e.timelockPegin)||e.timelockPegin<1||e.timelockPegin>M)throw new Error(`PegIn timelock ${e.timelockPegin} must be a whole number of blocks from 1 to ${M}.`);const t=await v.buildPeginTxFromPrePegin({txGraphVersion:e.prePeginParams.vaultCoreVersion,depositorPubkey:e.prePeginParams.depositorPubkey,vaultProviderPubkey:e.prePeginParams.vaultProviderPubkey,vaultKeeperPubkeys:e.prePeginParams.vaultKeeperPubkeys,universalChallengerPubkeys:e.prePeginParams.universalChallengerPubkeys,hashlocks:[...e.prePeginParams.hashlocks],timelockRefund:e.prePeginParams.timelockRefund,pegInAmounts:[...e.prePeginParams.pegInAmounts],feeRate:e.prePeginParams.feeRate,minPeginFeeRate:e.prePeginParams.minPeginFeeRate,numLocalChallengers:e.prePeginParams.numLocalChallengers,councilQuorum:e.prePeginParams.councilQuorum,councilSize:e.prePeginParams.councilSize,network:e.prePeginParams.network,authAnchorHash:H(e.prePeginParams.authAnchorHash)},e.timelockPegin,e.fundedPrePeginTxHex,e.htlcVout);return await me(t,e),{txHex:t.txHex,txid:t.txid,vaultScriptPubKey:t.vaultScriptPubKey,vaultValue:t.vaultValue}}const $e=2;async function me(e,t){const r=t.prePeginParams.vaultCoreVersion,o=r===1?h.PEGIN_TX_VERSION_CORE_1:r===2||r===3?h.PEGIN_TX_VERSION_CORE_2_AND_3:void 0;if(o===void 0)throw new Error(`Unsupported vaultCoreVersion ${r} for PegIn tx.`);await v.validatePeginP2aAnchor(r,e.txHex);const i=await v.peginP2aAnchorOutput(r),s=$e+(i?1:0),n=l.Transaction.fromHex(c.stripHexPrefix(e.txHex));if(n.version!==o)throw new Error(`PegIn tx version ${n.version} does not match vaultCoreVersion ${r}; expected ${o}.`);if(n.locktime!==h.PEGIN_TX_LOCKTIME)throw new Error(`PegIn tx locktime ${n.locktime} does not match the canonical locktime ${h.PEGIN_TX_LOCKTIME}.`);if(n.ins.length!==1)throw new Error(`PegIn tx has ${n.ins.length} input(s), expected exactly 1 (the Pre-PegIn HTLC outpoint).`);const u=l.Transaction.fromHex(c.stripHexPrefix(t.fundedPrePeginTxHex)).getId(),d=c.uint8ArrayToHex(new Uint8Array(n.ins[0].hash).slice().reverse());if(d!==u)throw new Error(`PegIn input spends txid ${d}, expected the funded Pre-PegIn ${u}.`);if(n.ins[0].index!==t.htlcVout)throw new Error(`PegIn input spends Pre-PegIn output ${n.ins[0].index}, expected the requested HTLC vout ${t.htlcVout}.`);if(n.ins[0].sequence!==h.PEGIN_INPUT_SEQUENCE)throw new Error(`PegIn input sequence ${n.ins[0].sequence} does not match the canonical sequence ${h.PEGIN_INPUT_SEQUENCE}.`);if(n.ins[0].script.length!==0)throw new Error("PegIn input scriptSig must be empty.");if(n.ins[0].witness.length!==0)throw new Error("PegIn input witness must be empty before signing.");if(n.outs.length!==s)throw new Error(`PegIn tx has ${n.outs.length} output(s), expected exactly ${s} for vaultCoreVersion ${r} (vault + depositor claim${i?" + P2A anchor":""}).`);const p=t.prePeginParams.pegInAmounts[t.htlcVout];if(e.vaultValue!==p)throw new Error(`PegIn vault output value ${e.vaultValue} does not match the requested peg-in amount ${p} for HTLC ${t.htlcVout}; refusing to sign a vault that locks a different amount than requested.`);const f=n.outs[0];if(BigInt(f.value)!==e.vaultValue)throw new Error(`Encoded PegIn vault output value ${f.value} does not match the WASM-reported vaultValue ${e.vaultValue}.`);const P=we(t.prePeginParams,t.timelockPegin).toString("hex");if(c.stripHexPrefix(e.vaultScriptPubKey).toLowerCase()!==P)throw new Error(`WASM-reported PegIn vaultScriptPubKey ${e.vaultScriptPubKey} does not match the independently derived payout scriptPubKey ${P}.`);const E=f.script.toString("hex");if(E!==P)throw new Error(`Encoded PegIn vault output scriptPubKey ${E} does not match the independently derived payout scriptPubKey ${P}.`);const g=n.getId();if(g!==c.stripHexPrefix(e.txid).toLowerCase())throw new Error(`Encoded PegIn txid ${g} does not match the WASM-reported txid ${e.txid}.`);const S=await v.computeMinClaimValue(r,t.prePeginParams.numLocalChallengers,t.prePeginParams.universalChallengerPubkeys.length,t.prePeginParams.councilQuorum,t.prePeginParams.councilSize,t.prePeginParams.feeRate),y=n.outs[ne];if(BigInt(y.value)!==S)throw new Error(`Encoded PegIn depositor-claim output value ${y.value} does not match the independently computed claim value ${S} for vaultCoreVersion ${r}.`);const w=se(t.prePeginParams.depositorPubkey);if(!y.script.equals(w))throw new Error(`Encoded PegIn depositor-claim output scriptPubKey ${y.script.toString("hex")} does not pay to the depositor's claim script (expected ${w.toString("hex")}).`)}async function ue(e){const t=await v.createPayoutConnector({txGraphVersion:e.vaultCoreVersion,depositor:e.depositor,vaultProvider:e.vaultProvider,vaultKeepers:e.vaultKeepers,universalChallengers:e.universalChallengers,timelockPegin:e.timelockPegin},e.network);return{payoutScript:t.payoutScript,taprootScriptHash:t.taprootScriptHash,scriptPubKey:t.scriptPubKey,address:t.address,payoutControlBlock:t.payoutControlBlock}}const F=253,Ce=254,Ie=65535,be=4294967295,Te="TapLeaf",Ae="TapBranch",ke="TapTweak",T=33,A=32,q=128,Oe=1,Re=254,Le=a.Buffer.from([81,32]);function Ve(e){if(e<F)return a.Buffer.from([e]);if(e<=Ie){const t=a.Buffer.alloc(2);return t.writeUInt16LE(e),a.Buffer.concat([a.Buffer.from([F]),t])}if(e<=be){const t=a.Buffer.alloc(4);return t.writeUInt32LE(e),a.Buffer.concat([a.Buffer.from([Ce]),t])}throw new Error(`Script too large to encode as CompactSize: ${e} bytes`)}function N(e,t){const r=a.Buffer.concat([a.Buffer.from([e]),Ve(t.length),a.Buffer.from(t)]);return l.crypto.taggedHash(Te,r)}function He(e){const{leafVersion:t,script:r,controlBlock:o}=e,i=o.length-T;if(i<0||i%A!==0||i/A>q)throw new Error(`Malformed Taproot control block: length ${o.length} must be ${T} + 32*m with 0 <= m <= ${q}`);const s=o[0]ℜif(s!==t)throw new Error(`Taproot control block leaf version 0x${s.toString(16)} does not match the tapLeafScript leaf version 0x${t.toString(16)}`);const n=a.Buffer.from(o.subarray(1,T));let u=N(t,r);for(let P=T;P<o.length;P+=A){const E=a.Buffer.from(o.subarray(P,P+A));u=l.crypto.taggedHash(Ae,a.Buffer.compare(u,E)<=0?a.Buffer.concat([u,E]):a.Buffer.concat([E,u]))}const d=l.crypto.taggedHash(ke,a.Buffer.concat([n,u])),p=ee.xOnlyPointAddTweak(n,d);if(p===null)throw new Error("Taproot control block does not yield a valid output key (tweak is off-curve)");const f=o[0]&Oe;if(p.parity!==f)throw new Error(`Taproot output key parity ${p.parity} contradicts the control block's parity bit ${f}`);return a.Buffer.concat([Le,a.Buffer.from(p.xOnlyPubkey)])}const Ne=256,Be=1500,X=256,G=0xffffffffn,Ue=500,Ke=55,Me=34;function ce(e){if(typeof e.protocolFeeRate!="bigint"||e.protocolFeeRate<=0n||e.protocolFeeRate>G)throw new Error(`protocolFeeRate must be in [1, ${G}] sat/vB, got ${e.protocolFeeRate}`);for(const[t,r,o,i]of[["keepers",e.numVaultKeepers,Ne,"fee-floor model limit"],["challengers",e.numUniversalChallengers,Be,"protocol maximum"]])if(!Number.isInteger(r)||r<1||r>o)throw new Error(`Participant count for ${t} (${r}) is outside the supported range [1, ${o}]${r>o?` (${i})`:""}.`);if(!Number.isInteger(e.councilSize)||e.councilSize<1||e.councilSize>X)throw new Error(`councilSize must be an integer in [1, ${X}], got ${e.councilSize}`)}async function ae(e,t){const{implicitFeeSats:r,out0Len:o,out1Len:i}=t,s=e.numVaultKeepers+e.numUniversalChallengers,n=BigInt(r),u=Math.max(0,o-Me),d=Ue+Ke*s+u,p=e.protocolFeeRate*BigInt(d);if(n>p)throw new Error(`Payout implicit fee ${r} sats exceeds the safety cap of ${p} sats (${e.protocolFeeRate} sat/vB x ${d} vB for ${s} participants); refusing to sign payout.`);const f=await v.computePayoutFeeFloor(e.vaultCoreVersion,e.numVaultKeepers,e.numUniversalChallengers,e.numVaultKeepers,e.councilSize,o,i,e.protocolFeeRate);if(n<f)throw new Error(`Payout implicit fee ${r} sats is below the floor of ${f} sats (the smallest fee any known vault-provider build produces for this shape); refusing to sign payout.`)}const Fe=22,qe=34,Xe=34,Ge=25,We=23;function Ye(e){return e.length===Fe*2&&e.startsWith("0014")}function De(e){return e.length===qe*2&&e.startsWith("0020")}function ze(e){return e.length===Xe*2&&e.startsWith("5120")}function Qe(e){return e.length===Ge*2&&e.startsWith("76a914")&&e.endsWith("88ac")}function Ze(e){return e.length===We*2&&e.startsWith("a914")&&e.endsWith("87")}function W(e,t){const r=c.stripHexPrefix(e).toLowerCase();if(r.length===0)throw new Error(`${t} is empty`);if(!/^[0-9a-f]+$/.test(r)||r.length%2!==0)throw new Error(`${t} is not valid hex`);if(r.startsWith("6a"))throw new Error(`${t} is an OP_RETURN output, which is provably unspendable`);if(!ze(r)&&!Ye(r)&&!De(r)&&!Qe(r)&&!Ze(r))throw new Error(`${t} is not a standard scriptPubKey (expected P2TR, P2WPKH, P2WSH, P2PKH, or P2SH; got ${r.length/2} bytes: ${r})`)}const Y=3;async function je(e){const t={vaultCoreVersion:e.vaultCoreVersion,numVaultKeepers:e.vaultKeeperBtcPubkeys.length,numUniversalChallengers:e.universalChallengerBtcPubkeys.length,councilSize:e.councilMembers.length,protocolFeeRate:e.protocolFeeRate};ce(t);const r=l.Transaction.fromHex(c.stripHexPrefix(e.payoutTxHex)),o=l.Transaction.fromHex(c.stripHexPrefix(e.peginTxHex)),i=l.Transaction.fromHex(c.stripHexPrefix(e.assertTxHex));if(r.ins.length!==h.DEPOSITOR_PAYOUT_INPUT_COUNT)throw new Error(`Payout transaction must have exactly ${h.DEPOSITOR_PAYOUT_INPUT_COUNT} inputs, got ${r.ins.length}`);if(r.version!==h.PAYOUT_TX_VERSION)throw new Error(`Payout transaction version ${r.version} must be ${h.PAYOUT_TX_VERSION}; refusing to sign payout.`);if(r.locktime!==h.PAYOUT_TX_LOCKTIME)throw new Error(`Payout transaction locktime ${r.locktime} must be ${h.PAYOUT_TX_LOCKTIME}; refusing to sign payout.`);const s=D(r.ins[0],0,o,"PegIn",h.PEGIN_VAULT_OUTPUT_INDEX);if(r.ins[0].sequence!==e.timelockPegin)throw new Error(`Payout input 0 sequence ${r.ins[0].sequence} must equal the PegIn CSV timelock ${e.timelockPegin}; refusing to sign payout.`);const n=D(r.ins[1],1,i,"Assert",h.ASSERT_PAYOUT_OUTPUT_INDEX);if(r.ins[1].sequence!==e.timelockAssert)throw new Error(`Payout input 1 sequence ${r.ins[1].sequence} must equal the Assert CSV timelock ${e.timelockAssert}; refusing to sign payout.`);const{out0Len:u,out1Len:d}=tt(r,s.value,e),p=s.value+n.value;let f=0;for(const S of r.outs)f+=S.value;if(f>p)throw new Error(`Payout outputs (${f} sats) exceed inputs (${p} sats); invalid transaction.`);const P=p-f;await ae(t,{implicitFeeSats:P,out0Len:u,out1Len:d});const E=await ue({vaultCoreVersion:e.vaultCoreVersion,depositor:e.depositorBtcPubkey,vaultProvider:e.vaultProviderBtcPubkey,vaultKeepers:e.vaultKeeperBtcPubkeys,universalChallengers:e.universalChallengerBtcPubkeys,timelockPegin:e.timelockPegin,network:e.network}),g=await Je(e,n);return{psbtHex:et(r,s,n,E,g)}}async function Je(e,t){const{payoutScript:r,payoutControlBlock:o}=await v.getAssertPayoutScriptInfo({txGraphVersion:e.vaultCoreVersion,claimer:c.stripHexPrefix(e.claimerBtcPubkey).toLowerCase(),localChallengers:te({claimerBtcPubkey:e.claimerBtcPubkey,depositorBtcPubkey:e.depositorBtcPubkey,vaultProviderBtcPubkey:e.vaultProviderBtcPubkey,vaultKeeperBtcPubkeys:e.vaultKeeperBtcPubkeys}),universalChallengers:e.universalChallengerBtcPubkeys.map(u=>c.stripHexPrefix(u).toLowerCase()),timelockAssert:e.timelockAssert,councilMembers:e.councilMembers.map(u=>c.stripHexPrefix(u).toLowerCase()),councilQuorum:e.councilQuorum}),i=c.hexToUint8Array(r),s=c.hexToUint8Array(o),n=He({leafVersion:c.TAPSCRIPT_LEAF_VERSION,script:i,controlBlock:s});if(!t.script.equals(n))throw new Error(`Rebuilt Assert:0 payout leaf does not spend the Assert output being referenced: leaf binds to ${n.toString("hex")}, Assert:${h.ASSERT_PAYOUT_OUTPUT_INDEX} pays ${t.script.toString("hex")}; refusing to sign payout.`);return{script:i,controlBlock:s}}function D(e,t,r,o,i){const s=c.uint8ArrayToHex(new Uint8Array(e.hash).slice().reverse()),n=r.getId();if(s!==n||e.index!==i)throw new Error(`Input ${t} must spend ${o}:${i}. Expected ${n}:${i}, got ${s}:${e.index}`);const u=r.outs[e.index];if(!u)throw new Error(`Previous output not found for input ${t} (txid: ${s}, index: ${e.index})`);return u}function et(e,t,r,o,i){const s=new l.Psbt;s.setVersion(e.version),s.setLocktime(e.locktime);const[n,u]=e.ins;s.addInput({hash:n.hash,index:n.index,sequence:n.sequence,witnessUtxo:{script:t.script,value:t.value},tapLeafScript:[{leafVersion:c.TAPSCRIPT_LEAF_VERSION,script:a.Buffer.from(c.hexToUint8Array(o.payoutScript)),controlBlock:a.Buffer.from(c.hexToUint8Array(o.payoutControlBlock))}],tapInternalKey:a.Buffer.from(v.tapInternalPubkey)}),s.addInput({hash:u.hash,index:u.index,sequence:u.sequence,witnessUtxo:{script:r.script,value:r.value},tapLeafScript:[{leafVersion:c.TAPSCRIPT_LEAF_VERSION,script:a.Buffer.from(i.script),controlBlock:a.Buffer.from(i.controlBlock)}],tapInternalKey:a.Buffer.from(v.tapInternalPubkey)});for(const d of e.outs)s.addOutput({script:d.script,value:d.value});return s.toHex()}function z(e,t){const r=c.stripHexPrefix(e).toLowerCase(),o=c.stripHexPrefix(c.deriveBip86ScriptPubKeyHex(t)).toLowerCase();return r===o?[r]:[r,o]}function Q(e,t){return t.some(r=>e.equals(a.Buffer.from(r,"hex")))}function tt(e,t,r){const{claimerBtcPubkey:o,vaultProviderBtcPubkey:i,depositorBtcPubkey:s,vaultKeeperBtcPubkeys:n,registeredPayoutScriptPubKey:u,commissionBps:d,vkClaimerPayoutScriptPubKeys:p,vpCommissionScriptPubKey:f}=r;if(!c.isValidHex(u))throw new Error("Invalid registeredPayoutScriptPubKey: not valid hex");const P=c.stripHexPrefix(o).toLowerCase(),E=c.stripHexPrefix(i).toLowerCase(),g=c.stripHexPrefix(s).toLowerCase(),S=n.map($=>c.stripHexPrefix($).toLowerCase());let y,w,_;if(P===E)y="vp-claimer",w=h.VP_CLAIMER_PAYOUT_OUTPUT_COUNT,_=[c.stripHexPrefix(u)];else if(P===g)y="depositor-as-claimer",w=h.NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT,_=[c.stripHexPrefix(u)];else if(S.includes(P)){y="vk-claimer",w=h.NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT;const $=p[P];if($===void 0)throw new Error(`No registered payout script resolved for vault keeper claimer ${P}`);W($,`Vault keeper payout script for claimer ${P}`),_=z($,P)}else throw new Error(`Unknown claimer pubkey ${P}: not VP, depositor, or a registered vault keeper`);if(e.outs.length!==w)throw new Error(`Payout transaction has ${e.outs.length} output(s), expected exactly ${w} for role ${y}.`);if(!Q(e.outs[0].script,_))throw new Error(`Payout transaction output 0 does not pay the expected scriptPubKey for role ${y}. Accepted: ${_.join(" or ")}; got ${e.outs[0].script.toString("hex")}`);const L=w-1;if(e.outs[L].value!==h.PAYOUT_ANCHOR_DUST_SATS)throw new Error(`Payout CPFP anchor (out ${L}) value ${e.outs[L].value} sats must equal ${h.PAYOUT_ANCHOR_DUST_SATS} sats`);if(y==="vp-claimer"){W(f,"Vault provider commission payout script");const $=z(f,E);if(!Q(e.outs[1].script,$))throw new Error(`Payout transaction output 1 does not pay the vault provider's commission scriptPubKey. Accepted: ${$.join(" or ")}; got ${e.outs[1].script.toString("hex")}`);if(!Number.isInteger(d)||d<0||d>=h.MAX_VP_COMMISSION_BPS_EXCLUSIVE)throw new Error(`commissionBps must be an integer in [0, ${h.MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${d}`);const B=Math.floor(t*d/h.BPS_DENOMINATOR);if(e.outs[1].value>B)throw new Error(`Payout VP commission (out 1) value ${e.outs[1].value} sats exceeds cap ${B} sats (${d} bps of peginValue=${t})`)}const b=e.outs[0].script.length;if(b===0||b>h.MAX_PAYOUT_SCRIPT_LEN)throw new Error(`Payout receiver scriptPubKey length ${b} is outside the contract's registration cap [1, ${h.MAX_PAYOUT_SCRIPT_LEN}]; refusing to sign payout.`);const le=y==="vp-claimer"?e.outs[1].script.length:void 0;return{out0Len:b,out1Len:le}}function rt(e,t,r=0){const o=l.Psbt.fromHex(e);if(r>=o.data.inputs.length)throw new Error(`Input index ${r} out of range (${o.data.inputs.length} inputs)`);const i=o.data.inputs[r];if(i.tapScriptSig&&i.tapScriptSig.length>0){const s=c.hexToUint8Array(t);for(const n of i.tapScriptSig)if(n.pubkey.equals(a.Buffer.from(s)))return Z(n.signature,r);throw new Error(`No signature found for depositor pubkey: ${t} at input ${r}`)}if(i.finalScriptWitness&&i.finalScriptWitness.length>0){const s=ot(i.finalScriptWitness);if(s.length!==Y)throw new Error(`Unexpected finalized witness stack size at input ${r}: expected ${Y} items (signature, script, controlBlock), got ${s.length}`);return Z(s[0],r)}throw new Error(`No tapScriptSig or finalScriptWitness found in signed PSBT at input ${r}`)}function Z(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 ot(e){const t=[];let r=0;const o=n=>{if(r+n>e.length)throw new Error(`Malformed witness data: need ${n} byte(s) at offset ${r}, only ${e.length-r} remaining`)},i=()=>{o(1);const n=e[r++];if(n<253)return n;if(n===253){o(2);const u=(e[r]|e[r+1]<<8)>>>0;return r+=2,u}if(n===254){o(4);const u=(e[r]|e[r+1]<<8|e[r+2]<<16|e[r+3]<<24)>>>0;return r+=4,u}throw new Error(`Malformed witness data: 8-byte varint (0xff) not supported at offset ${r-1}`)},s=i();for(let n=0;n<s;n++){const u=i();o(u),t.push(a.Buffer.from(e.subarray(r,r+u))),r+=u}if(r!==e.length)throw new Error(`Malformed witness data: ${e.length-r} trailing byte(s) after parsing ${s} item(s)`);return t}class x extends Error{constructor(t){super(`Wallet returned a PSBT for a different transaction: ${t}`),this.name="PsbtSubstitutionError"}}function j(e,t){try{return l.Psbt.fromHex(t)}catch(r){const o=r instanceof Error?r.message:String(r);throw new Error(`Failed to parse ${e} PSBT: ${o}`)}}const nt=8;function V(e){return`${e.toString("hex").slice(0,nt)}…`}function J(e){const t=a.Buffer.from(e).reverse();return V(t)}function it(e){const t=j("requested",e.requestedPsbtHex),r=j("returned",e.returnedPsbtHex);if(t.version!==r.version)throw new x(`tx version differs (requested=${t.version}, returned=${r.version})`);if(t.locktime!==r.locktime)throw new x(`tx locktime differs (requested=${t.locktime}, returned=${r.locktime})`);if(t.txInputs.length!==r.txInputs.length)throw new x(`input count differs (requested=${t.txInputs.length}, returned=${r.txInputs.length})`);if(t.txOutputs.length!==r.txOutputs.length)throw new x(`output count differs (requested=${t.txOutputs.length}, returned=${r.txOutputs.length})`);for(let o=0;o<t.txInputs.length;o++){const i=t.txInputs[o],s=r.txInputs[o];if(!i.hash.equals(s.hash))throw new x(`input ${o} prevout txid differs (requested=${J(i.hash)}, returned=${J(s.hash)})`);if(i.index!==s.index)throw new x(`input ${o} prevout vout differs (requested=${i.index}, returned=${s.index})`);if(i.sequence!==s.sequence)throw new x(`input ${o} sequence differs (requested=${i.sequence}, returned=${s.sequence})`)}for(let o=0;o<t.txOutputs.length;o++){const i=t.txOutputs[o],s=r.txOutputs[o];if(!i.script.equals(s.script))throw new x(`output ${o} scriptPubKey differs (requested=${V(i.script)}, returned=${V(s.script)})`);if(i.value!==s.value)throw new x(`output ${o} value differs (requested=${i.value}, returned=${s.value})`)}}function st(e){const{requestedPsbtHex:t,signatureHex:r,signerXOnlyPubkeyHex:o,inputIndex:i}=e,s=c.stripHexPrefix(r);if(s.length!==c.SCHNORR_SIG_HEX_LEN)throw new Error(`Schnorr signature for input ${i} must be ${c.SCHNORR_SIG_HEX_LEN} hex chars (64 bytes), got ${s.length}.`);const n=c.stripHexPrefix(o);if(n.length!==U.X_ONLY_PUBKEY_HEX_LEN)throw new Error(`Signer x-only pubkey for input ${i} must be ${U.X_ONLY_PUBKEY_HEX_LEN} hex chars (32 bytes), got ${n.length}.`);const u=l.Psbt.fromHex(t);if(i<0||i>=u.data.inputs.length)throw new Error(`Input index ${i} out of range (${u.data.inputs.length} inputs).`);const d=[],p=[];for(let w=0;w<u.data.inputs.length;w++){const _=u.data.inputs[w].witnessUtxo;if(!_)throw new Error(`Cannot verify signature: input ${w} of the requested PSBT has no witnessUtxo (required to recompute the Taproot sighash).`);d.push(_.script),p.push(_.value)}const f=u.data.inputs[i].tapLeafScript;if(!f||f.length!==1)throw new Error(`Cannot verify signature: input ${i} 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 ${i} tapLeafScript has leaf version 0x${P.leafVersion.toString(16)}, expected 0x${c.TAPSCRIPT_LEAF_VERSION.toString(16)}.`);const E=N(P.leafVersion,P.script),g=new l.Transaction;g.version=u.version,g.locktime=u.locktime;for(const w of u.txInputs)g.addInput(w.hash,w.index,w.sequence);for(const w of u.txOutputs)g.addOutput(w.script,w.value);const S=g.hashForWitnessV1(i,d,p,l.Transaction.SIGHASH_DEFAULT,E);if(!ee.verifySchnorr(S,c.hexToUint8Array(n),c.hexToUint8Array(s)))throw new Error(`Schnorr signature for input ${i} (signer ${n}) does not verify against the expected Taproot script-path sighash. The wallet may have signed with the tweaked key, signed a different transaction, or returned an invalid signature.`)}exports.HtlcOutputMismatchError=C;exports.PEGIN_DEPOSITOR_CLAIM_VOUT=ne;exports.PsbtSubstitutionError=x;exports.assertEncodedHtlcOutputsMatch=oe;exports.assertPayoutFeeBandDomain=ce;exports.assertPayoutFeeInBand=ae;exports.assertPsbtUnsignedTxMatches=it;exports.assertScriptPathSchnorrSignature=st;exports.buildPayoutPsbt=je;exports.buildPeginTxFromFundedPrePegin=_e;exports.buildPrePeginPsbt=xe;exports.computeNumLocalChallengers=de;exports.computeTapLeafHash=N;exports.createPayoutScript=ue;exports.deriveDepositorClaimDescriptor=ie;exports.deriveDepositorClaimScriptPubKey=se;exports.deriveExpectedPrePeginHtlc=re;exports.deriveLocalChallengers=te;exports.extractPayoutSignature=rt;exports.normalizeAuthAnchorHash=H;
|
|
2
|
-
//# sourceMappingURL=verifyScriptPathSchnorrSignature-CahYx5Td.cjs.map
|