@babylonlabs-io/ts-sdk 6.0.2 → 6.2.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.
Files changed (86) hide show
  1. package/dist/{BTCVaultRegistry.abi-DnP4UkB5.js → BTCVaultRegistry.abi-C19m1l4i.js} +42 -1
  2. package/dist/{BTCVaultRegistry.abi-DnP4UkB5.js.map → BTCVaultRegistry.abi-C19m1l4i.js.map} +1 -1
  3. package/dist/{BTCVaultRegistry.abi-DzbfZ9_s.cjs → BTCVaultRegistry.abi-C4bQi-H9.cjs} +2 -2
  4. package/dist/{BTCVaultRegistry.abi-DzbfZ9_s.cjs.map → BTCVaultRegistry.abi-C4bQi-H9.cjs.map} +1 -1
  5. package/dist/PayoutManager-3-MzBVLj.js.map +1 -1
  6. package/dist/PayoutManager-PQqeqX41.cjs.map +1 -1
  7. package/dist/{PeginManager-D_ZUfbIy.cjs → PeginManager-BNJUATq2.cjs} +2 -2
  8. package/dist/PeginManager-BNJUATq2.cjs.map +1 -0
  9. package/dist/{PeginManager-m3IlM4wS.js → PeginManager-p88tE5r2.js} +4 -4
  10. package/dist/PeginManager-p88tE5r2.js.map +1 -0
  11. package/dist/ProtocolParams.abi-DzjpPHcl.cjs +2 -0
  12. package/dist/ProtocolParams.abi-DzjpPHcl.cjs.map +1 -0
  13. package/dist/{ProtocolParams.abi-CuDl7AuC.js → ProtocolParams.abi-vMl0TZ2q.js} +6 -1
  14. package/dist/ProtocolParams.abi-vMl0TZ2q.js.map +1 -0
  15. package/dist/VaultErrors.abi-BIY0p6Wn.js +5 -0
  16. package/dist/{VaultErrors.abi-Dc3UnB_h.js.map → VaultErrors.abi-BIY0p6Wn.js.map} +1 -1
  17. package/dist/VaultErrors.abi-BV0qeG6M.cjs +2 -0
  18. package/dist/{VaultErrors.abi-Hjn1CdLs.cjs.map → VaultErrors.abi-BV0qeG6M.cjs.map} +1 -1
  19. package/dist/{buildAndBroadcastReclaim-CMjlyooo.cjs → buildAndBroadcastReclaim-Blxt7B0K.cjs} +2 -2
  20. package/dist/{buildAndBroadcastReclaim-D8l-QJWo.js.map → buildAndBroadcastReclaim-Blxt7B0K.cjs.map} +1 -1
  21. package/dist/{buildAndBroadcastReclaim-D8l-QJWo.js → buildAndBroadcastReclaim-C2CkzCVn.js} +3 -3
  22. package/dist/buildAndBroadcastReclaim-C2CkzCVn.js.map +1 -0
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.js +9 -9
  25. package/dist/{pegin-registration-client-BlrXyZpF.js → pegin-registration-client-B8A4P-Vv.js} +232 -205
  26. package/dist/pegin-registration-client-B8A4P-Vv.js.map +1 -0
  27. package/dist/pegin-registration-client-JtZkosZQ.cjs +2 -0
  28. package/dist/pegin-registration-client-JtZkosZQ.cjs.map +1 -0
  29. package/dist/{signer-set-reader-Csz8RXQi.js → signer-set-reader-BJ3g6rid.js} +3 -3
  30. package/dist/{signer-set-reader-Csz8RXQi.js.map → signer-set-reader-BJ3g6rid.js.map} +1 -1
  31. package/dist/{signer-set-reader-CNEfzwuA.cjs → signer-set-reader-C8xSyTMb.cjs} +2 -2
  32. package/dist/{signer-set-reader-CNEfzwuA.cjs.map → signer-set-reader-C8xSyTMb.cjs.map} +1 -1
  33. package/dist/tbv/core/clients/eth/index.cjs +1 -1
  34. package/dist/tbv/core/clients/eth/index.js +3 -3
  35. package/dist/tbv/core/clients/eth/pegin-registration-client.d.ts.map +1 -1
  36. package/dist/tbv/core/clients/eth/protocol-params-reader.d.ts +1 -1
  37. package/dist/tbv/core/clients/eth/protocol-params-reader.d.ts.map +1 -1
  38. package/dist/tbv/core/clients/eth/types.d.ts +11 -1
  39. package/dist/tbv/core/clients/eth/types.d.ts.map +1 -1
  40. package/dist/tbv/core/clients/index.cjs +1 -1
  41. package/dist/tbv/core/clients/index.js +3 -3
  42. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts +34 -0
  43. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts.map +1 -1
  44. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts +4 -0
  45. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts.map +1 -1
  46. package/dist/tbv/core/contracts/abis/vaultErrors.abi.json.d.ts +1 -1
  47. package/dist/tbv/core/contracts/index.cjs +1 -1
  48. package/dist/tbv/core/contracts/index.js +3 -3
  49. package/dist/tbv/core/deposit-terms/depositTerms.d.ts +3 -3
  50. package/dist/tbv/core/deposit-terms/prePeginApproval.d.ts +2 -2
  51. package/dist/tbv/core/index.cjs +1 -1
  52. package/dist/tbv/core/index.js +9 -9
  53. package/dist/tbv/core/managers/index.cjs +1 -1
  54. package/dist/tbv/core/managers/index.js +1 -1
  55. package/dist/tbv/core/primitives/psbt/__tests__/depositorClaim.test.d.ts +1 -1
  56. package/dist/tbv/core/primitives/psbt/payout.d.ts +2 -1
  57. package/dist/tbv/core/primitives/psbt/payout.d.ts.map +1 -1
  58. package/dist/tbv/core/services/index.cjs +1 -1
  59. package/dist/tbv/core/services/index.js +1 -1
  60. package/dist/tbv/index.cjs +1 -1
  61. package/dist/tbv/index.js +9 -9
  62. package/dist/{toRefundInputs-D5tx3eeA.js → toRefundInputs-CZ9aqp2o.js} +2 -2
  63. package/dist/{toRefundInputs-D5tx3eeA.js.map → toRefundInputs-CZ9aqp2o.js.map} +1 -1
  64. package/dist/{toRefundInputs-Df6eRITl.cjs → toRefundInputs-CzZujjq-.cjs} +2 -2
  65. package/dist/{toRefundInputs-Df6eRITl.cjs.map → toRefundInputs-CzZujjq-.cjs.map} +1 -1
  66. package/dist/types-Bt1FM6d8.cjs +2 -0
  67. package/dist/types-Bt1FM6d8.cjs.map +1 -0
  68. package/dist/{types-K_aM5GZO.js → types-D7p5jFlm.js} +135 -62
  69. package/dist/types-D7p5jFlm.js.map +1 -0
  70. package/dist/verifyScriptPathSchnorrSignature-BVGPEZXW.js.map +1 -1
  71. package/dist/verifyScriptPathSchnorrSignature-p3sVoWQi.cjs.map +1 -1
  72. package/package.json +1 -1
  73. package/dist/PeginManager-D_ZUfbIy.cjs.map +0 -1
  74. package/dist/PeginManager-m3IlM4wS.js.map +0 -1
  75. package/dist/ProtocolParams.abi-CuDl7AuC.js.map +0 -1
  76. package/dist/ProtocolParams.abi-DWfIh6VH.cjs +0 -2
  77. package/dist/ProtocolParams.abi-DWfIh6VH.cjs.map +0 -1
  78. package/dist/VaultErrors.abi-Dc3UnB_h.js +0 -5
  79. package/dist/VaultErrors.abi-Hjn1CdLs.cjs +0 -2
  80. package/dist/buildAndBroadcastReclaim-CMjlyooo.cjs.map +0 -1
  81. package/dist/pegin-registration-client-BlrXyZpF.js.map +0 -1
  82. package/dist/pegin-registration-client-DOb-Iznp.cjs +0 -2
  83. package/dist/pegin-registration-client-DOb-Iznp.cjs.map +0 -1
  84. package/dist/types-BnZIbDHb.cjs +0 -2
  85. package/dist/types-BnZIbDHb.cjs.map +0 -1
  86. package/dist/types-K_aM5GZO.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"pegin-registration-client-BlrXyZpF.js","sources":["../src/tbv/core/deposit-terms/commissionCeiling.ts","../src/tbv/core/clients/eth/vault-registry-reader.ts","../src/tbv/core/clients/eth/pegin-registration-client.ts"],"sourcesContent":["/**\n * The depositor's commission ceiling (`maxAcceptableCommissionBps`) policy:\n * quoted VP commission + drift headroom, capped below the contract's\n * exclusive bound. Shared by `PeginManager` (the approved terms) and the\n * registration calldata so both carry the same ceiling; a resume rebuild reads\n * that submitted value back from the `PegInSubmitted` log instead.\n *\n * @module deposit-terms/commissionCeiling\n */\n\n/*\n * Commission-check map (each guards a DIFFERENT boundary — do not consolidate):\n * 1. assertVpCommissionInProtocolRange (vault app, vaultPayoutSignatureService)\n * — chain-read trust boundary; mirrors VPKeyRegistryLogic.sol bounds.\n * 2. capMaxAcceptableCommissionBps (here) — depositor quote → ceiling policy;\n * mirrors PeginLogic.sol's strict > check via the +25bps headroom.\n * 3. buildDepositTerms range check — public-API precondition on the projection\n * that mints the device-enforced commissionFee.\n * 4. payout.ts commission cap — the VP-built tx's output value vs bps at the\n * signing site (CLAUDE.md Critical Path #3).\n * 5. envelope.ts dust/cross-field gates (ledger-vault-signer) — firmware-only\n * constants, pre-device-I/O (Critical Path #7).\n */\n\nimport { MAX_VP_COMMISSION_BPS_EXCLUSIVE } from \"../primitives/psbt/constants\";\n\n/**\n * Headroom (in basis points) added to the current VP commission to compute\n * `maxAcceptableCommissionBps` at submit time. Lets the VP raise its\n * commission by up to this amount between read and submit without forcing\n * a re-quote. Capped by {@link MAX_ACCEPTABLE_COMMISSION_BPS_CAP}.\n *\n * Contract check is strict `>` (PeginLogic.sol `VaultProviderCommissionExceeded`\n * revert), so +25 allows up\n * to +25 bps of drift.\n */\nexport const COMMISSION_BPS_HEADROOM = 25;\n\n/**\n * Hard ceiling for `maxAcceptableCommissionBps`. The contract enforces\n * `commissionBps < 10000`, so any value at/above that is unreachable;\n * `9999` is the maximum useful cap.\n */\nexport const MAX_ACCEPTABLE_COMMISSION_BPS_CAP = 9999;\n\n/**\n * The commission ceiling submitted as registration calldata and mirrored\n * into `DepositTerms.commissionFee`: quoted + drift headroom, capped.\n * Single source for both consumers — feed it the SAME quoted bps at prepare\n * and register time so device-accept stays coextensive with contract-accept.\n */\nexport function capMaxAcceptableCommissionBps(bps: number): number {\n // Validate the raw quote before headroom shifts its domain — a negative\n // quote must throw here, not become a small \"legal\" ceiling.\n // Reject an out-of-range quote outright — clamping it to 9999 would turn a\n // bad read into a 99.99% ceiling, the exact failure the cap exists to stop.\n if (\n !Number.isInteger(bps) ||\n bps < 0 ||\n bps >= MAX_VP_COMMISSION_BPS_EXCLUSIVE\n ) {\n throw new Error(\n `Quoted commissionBps must be an integer in ` +\n `[0, ${MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${bps}`,\n );\n }\n return Math.min(\n bps + COMMISSION_BPS_HEADROOM,\n MAX_ACCEPTABLE_COMMISSION_BPS_CAP,\n );\n}\n","/**\n * Concrete BTCVaultRegistry reader using viem's readContract.\n *\n * This is an optional utility — callers can use their own implementation\n * of the VaultRegistryReader interface.\n */\n\nimport type { Abi, Address, Hex, PublicClient } from \"viem\";\nimport { getAbiItem } from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\nimport { BTCVaultRegistryKeyEpochsABI } from \"../../contracts/abis/BTCVaultRegistryKeyEpochs.abi\";\nimport { VaultClaimableByNotFoundError } from \"./claimable-event-error\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\nimport { assertValidOffchainParamsVersion } from \"./protocol-params-validation\";\nimport { RegistrationLogsUnavailableError } from \"./registration-logs-error\";\nimport { findRegistrationRecord } from \"./registration-records\";\nimport type {\n KeyEpochs,\n OnChainBtcPubkey,\n PeginRegistrationRecord,\n VaultBasicInfo,\n VaultClaimableByEvent,\n VaultData,\n VaultProtocolInfo,\n VaultRegistryReader,\n} from \"./types\";\n\n/**\n * Inclusive upper bound the BTCVaultRegistry contract enforces on a vault\n * provider's commission (the contract check is `< 10000`).\n */\nconst MAX_VP_COMMISSION_BPS = 9999;\n\n/** Raw `getBtcVaultBasicInfo` tuple as decoded by viem. */\ntype RawVaultBasicInfo = {\n depositor: Address;\n depositorBtcPubKey: Hex;\n amount: bigint;\n vaultProvider: Address;\n status: number;\n applicationEntryPoint: Address;\n createdAt: bigint;\n};\n\n/**\n * Raw `getBtcVaultProtocolInfo` tuple as decoded by viem.\n *\n * Mirrors the ABI's components. The trailing key epochs are read through the\n * separate key-epochs ABI, so this prefix stops at `vaultCoreVersion`.\n */\ntype RawVaultProtocolInfo = {\n depositorSignedPeginTx: Hex;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n offchainParamsVersion: number;\n verifiedAt: bigint;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n depositorPopSignature: Hex;\n prePeginTxHash: Hex;\n vaultProviderCommissionBps: number;\n claimExpiredUntil: bigint;\n vaultCoreVersion: number;\n};\n\n/** Raw `getBtcVaultProtocolInfo` tuple as decoded by the key-epochs ABI. */\ntype RawVaultKeyEpochsInfo = RawVaultProtocolInfo & KeyEpochs;\n\nfunction mapVaultBasicInfo(result: RawVaultBasicInfo): VaultBasicInfo {\n return {\n depositor: result.depositor,\n depositorBtcPubKey: result.depositorBtcPubKey,\n amount: result.amount,\n vaultProvider: result.vaultProvider,\n status: result.status,\n applicationEntryPoint: result.applicationEntryPoint,\n createdAt: result.createdAt,\n };\n}\n\nfunction mapVaultProtocolInfo(result: RawVaultProtocolInfo): VaultProtocolInfo {\n const offchainParamsVersion = Number(result.offchainParamsVersion);\n assertValidOffchainParamsVersion(offchainParamsVersion);\n return {\n depositorSignedPeginTx: result.depositorSignedPeginTx,\n universalChallengersVersion: result.universalChallengersVersion,\n appVaultKeepersVersion: result.appVaultKeepersVersion,\n offchainParamsVersion,\n verifiedAt: result.verifiedAt,\n depositorWotsPkHash: result.depositorWotsPkHash,\n hashlock: result.hashlock,\n htlcVout: result.htlcVout,\n depositorPopSignature: result.depositorPopSignature,\n prePeginTxHash: result.prePeginTxHash,\n vaultProviderCommissionBps: result.vaultProviderCommissionBps,\n claimExpiredUntil: result.claimExpiredUntil,\n vaultCoreVersion: result.vaultCoreVersion,\n };\n}\n\n/**\n * Exclusive upper bound for a `uint64` epoch.\n *\n * viem does not range-check a decoded `uint64`, so a misaligned decode can\n * hand back a value far larger than the field can hold. Rejecting those is\n * cheap defence in depth against a mis-decode of the extended ABI.\n *\n * The state this is load-bearing for is narrower than \"a registry that predates\n * RFC-006\". Against a *fully* pre-RFC-006 registry the path fails closed on its\n * own: `resolveParticipantKeysAtEpochs` goes on to call\n * `getOperationBtcKeyAtEpochOrGenesis` on ApplicationRegistry and\n * ProtocolParams, which do not exist there, so the multicall reverts and these\n * epochs are never used. The reachable gap is a registry that *has* the\n * operation-key getters but whose `BTCVaultProtocolInfo` struct is not\n * extended — there the tail-data epochs resolve with no error at all, and this\n * range check is the only thing looking at them.\n *\n * Even for that case it is only a backstop, and a weak one: a misaligned decode\n * can land on a small, plausible-looking integer this range accepts. Correctness\n * rests on only ever pointing at an RFC-006 registry, which is a deployment\n * precondition rather than something this call can establish — see\n * https://github.com/babylonlabs-io/babylon-toolkit/issues/2192 for where that\n * check is owned, and `BTCVaultRegistryKeyEpochs.abi.ts` for the decode hazard.\n */\nconst UINT64_EXCLUSIVE_UPPER_BOUND = 1n << 64n;\n\n/**\n * The epoch a vault provider's registration key is bonded at.\n *\n * A provider's operation-key history is append-only and every appended version\n * is stamped at epoch 1 or later, so epoch 0 always resolves to the key set at\n * registration. This is what lets `getOperationBtcKeyAtEpoch` stand in for the\n * removed `getVaultProviderBTCKey` getter.\n */\nconst VP_GENESIS_KEY_EPOCH = 0n;\n\nconst PEGIN_SUBMITTED_EVENT = getAbiItem({\n abi: BTCVaultRegistryABI,\n name: \"PegInSubmitted\",\n});\n\nconst VAULT_CLAIMABLE_BY_EVENT = getAbiItem({\n abi: BTCVaultRegistryABI,\n name: \"VaultClaimableBy\",\n});\n\n/**\n * Block span of one `VaultClaimableBy` query: btc-vault's own scan chunk\n * (`EVENT_QUERY_CHUNK_BLOCKS = 7200`, `crates/eth-client/src/client.rs:793`\n * @ ac4954e7), about a day of Ethereum blocks, so a recent redeem costs one\n * request. Not every provider serves a range this wide — an Alchemy free key\n * caps `eth_getLogs` at 10 blocks\n * (https://www.alchemy.com/docs/reference/eth-getlogs) — and a provider that\n * answered a wide range short instead of erroring would make this scan report\n * not-found, so confirming the RPC honours 7,200-block ranges is a\n * prerequisite of a claim run.\n */\nconst VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS = 7_200n;\n\nfunction maxBigint(a: bigint, b: bigint): bigint {\n return a > b ? a : b;\n}\n\n/** A `PegInSubmitted` log's decoded args, as viem's strict `getLogs` hands them back. */\ninterface PegInSubmittedArgs {\n vaultId: Hex;\n peginTxHash: Hex;\n depositor: Address;\n vaultProvider: Address;\n amount: bigint;\n vaultCoreVersion: number;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n proverCircuitVersion: number;\n offchainParamsVersion: number;\n depositorPayoutBtcAddress: Hex;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n unsignedPrePeginTx: Hex;\n maxAcceptableCommissionBps: number;\n}\n\nfunction mapRegistrationRecord(\n args: PegInSubmittedArgs,\n blockNumber: bigint,\n): PeginRegistrationRecord {\n // A plain decode of every registration log in the block, strangers'\n // included: nothing here parses a transaction or bound-checks a script, so\n // one malformed registration elsewhere in the block cannot fail the\n // caller's read. The strict per-record checks live in\n // registration-records.ts. A duplicate vault id is not covered: a vault\n // registers once, so two logs for one id are an inconsistent node and fail\n // the read closed (see the caller).\n return {\n vaultId: args.vaultId.toLowerCase() as Hex,\n depositor: args.depositor,\n vaultProvider: args.vaultProvider,\n amount: args.amount,\n vaultCoreVersion: args.vaultCoreVersion,\n universalChallengersVersion: args.universalChallengersVersion,\n appVaultKeepersVersion: args.appVaultKeepersVersion,\n proverCircuitVersion: args.proverCircuitVersion,\n offchainParamsVersion: args.offchainParamsVersion,\n peginTxHash: args.peginTxHash.toLowerCase() as Hex,\n depositorPayoutScriptPubKey:\n args.depositorPayoutBtcAddress.toLowerCase() as Hex,\n unsignedPrePeginTx: args.unsignedPrePeginTx,\n maxAcceptableCommissionBps: args.maxAcceptableCommissionBps,\n blockNumber,\n };\n}\n\nfunction assertEpochInRange(\n value: bigint,\n field: string,\n vaultId: Hex,\n): bigint {\n if (value < 0n || value >= UINT64_EXCLUSIVE_UPPER_BOUND) {\n throw new Error(\n `getBtcVaultProtocolInfo returned ${field}=${value} for vault ${vaultId}, ` +\n `outside the uint64 range — the registry may predate RFC-006`,\n );\n }\n return value;\n}\n\n/** Matched by substring (\"not found on-chain\") in the vault app's `isVaultRecordEmptyError`. */\nconst VAULT_RECORD_NOT_FOUND_MESSAGE =\n \"not found on-chain or has no pegin transaction\";\n\nfunction assertVaultRecordPresent(\n record: { depositorSignedPeginTx: Hex },\n vaultId: Hex,\n): void {\n if (\n !record.depositorSignedPeginTx ||\n record.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(`Vault ${vaultId} ${VAULT_RECORD_NOT_FOUND_MESSAGE}`);\n }\n}\n\nfunction mapKeyEpochs(result: RawVaultKeyEpochsInfo, vaultId: Hex): KeyEpochs {\n // An upgraded registry decodes an unknown or not-yet-indexed vault to a zero\n // struct whose epochs read as {0,0,0} (genesis keys), so check the record\n // exists first.\n assertVaultRecordPresent(result, vaultId);\n return {\n vpKeyEpoch: assertEpochInRange(result.vpKeyEpoch, \"vpKeyEpoch\", vaultId),\n appKeeperKeyEpoch: assertEpochInRange(\n result.appKeeperKeyEpoch,\n \"appKeeperKeyEpoch\",\n vaultId,\n ),\n ucKeyEpoch: assertEpochInRange(result.ucKeyEpoch, \"ucKeyEpoch\", vaultId),\n };\n}\n\n/**\n * Concrete vault registry reader using viem.\n *\n * Usage:\n * ```ts\n * const reader = new ViemVaultRegistryReader(publicClient, registryAddress);\n * const data = await reader.getVaultData(vaultId);\n * ```\n */\nexport class ViemVaultRegistryReader implements VaultRegistryReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n /**\n * Read the VP's **genesis** (registration) x-only BTC pubkey — the key bonded\n * at version 0, which never moves when the operator rotates.\n *\n * Resolved as \"the operation key at epoch 0\" rather than through the\n * dedicated `getVaultProviderBTCKey` getter, which\n * https://github.com/babylonlabs-io/vault-contracts-aave-v4/pull/539 removes.\n * Epoch 0 predates any rotation — appended versions are stamped at epoch 1 or\n * later — so it resolves to the registration key, and the contracts team has\n * confirmed that is a property we can rely on rather than an implementation\n * detail. The devnet comparison behind that claim — both getters returning the\n * identical key for a provider that *has* rotated, while\n * `getCurrentOperationBtcKey` differed — is recorded in\n * https://github.com/babylonlabs-io/babylon-toolkit/issues/2188.\n *\n * This makes the read RFC-006-only, where the removed getter also existed on a\n * legacy registry. That costs nothing: every caller of this method already\n * resolves participant keys through `OperationKeyReader`, so all of them\n * require an RFC-006 registry regardless.\n *\n * Validates length, hex form, and secp256k1 curve membership before minting\n * the brand. Returns 64-char lowercase hex without the `0x` prefix.\n */\n async getVaultProviderGenesisBtcPubKey(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey> {\n return this.getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress,\n VP_GENESIS_KEY_EPOCH,\n blockNumber,\n );\n }\n\n /**\n * Read the VP operation key selected by `epoch`.\n *\n * This is public rather than hidden inside `OperationKeyReader` because\n * subject-specific VP authentication needs exactly one participant: the\n * gRPC bootstrap is signed by the key frozen into the vault, while the\n * JSON-RPC bootstrap is signed by the provider's live key.\n */\n async getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress: Address,\n epoch: bigint,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getOperationBtcKeyAtEpoch\",\n args: [vpAddress, epoch],\n blockNumber,\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getOperationBtcKeyAtEpoch (vp=${vpAddress}, epoch=${epoch})`,\n );\n }\n\n /**\n * Read the application entry point a vault provider is registered for.\n *\n * This is the registry's own `vaultProviders[vp].applicationEntryPoint`, and\n * it is the value the peg-in submit path resolves internally — it selects\n * which application's vault-keeper roster, roster version and keeper key\n * epoch a deposit is bonded to. The dApp separately carries an entry point\n * from its own configuration; the two agree today, but they are different\n * sources of truth, so the build path reads this one and asserts the\n * configured value matches it rather than trusting either alone.\n */\n async getVaultProviderApplication(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<Address> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderApplication\",\n args: [vpAddress],\n blockNumber,\n })) as Address;\n }\n\n /**\n * Read a vault provider's *current* RFC-006 operation BTC key.\n *\n * Falls back on-chain to the registration key when the provider has never\n * rotated, so this returns the same value as\n * `getVaultProviderGenesisBtcPubKey` until the first rotation.\n *\n * This is the key the VP's server uses for JSON-RPC-subject authentication.\n * The gRPC-subject bootstrap is instead bound to the existing vault's frozen\n * epoch and resolves through `getVaultProviderOperationBtcKeyAtEpoch`.\n */\n async getCurrentVaultProviderOperationBtcKey(\n vpAddress: Address,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getCurrentOperationBtcKey\",\n args: [vpAddress],\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getCurrentOperationBtcKey (vp=${vpAddress})`,\n );\n }\n\n /**\n * Read a vault's frozen RFC-006 operation-key epochs.\n *\n * Reads `getBtcVaultProtocolInfo` through the **extended** ABI, which is only\n * valid against an RFC-006 registry: against one whose `BTCVaultProtocolInfo`\n * struct is not extended this call does not fail for a populated vault, it\n * silently returns three words of tail data as epochs. Nothing here can detect\n * that, so the guarantee is a deployment one — every network this ships to has\n * the RFC-006 getters, and mainnet is a fresh RFC-006 deploy.\n *\n * A registry missing the operation-key getters entirely is the *safer* of the\n * two cases: `resolveParticipantKeysAtEpochs` reverts downstream and these\n * epochs never reach key resolution. See {@link UINT64_EXCLUSIVE_UPPER_BOUND}\n * for which state the range check actually guards, and\n * `BTCVaultRegistryKeyEpochs.abi.ts` for the decode hazard.\n */\n async getVaultKeyEpochs(vaultId: Hex): Promise<KeyEpochs> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultKeyEpochsInfo;\n\n return mapKeyEpochs(result, vaultId);\n }\n\n async getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) =>\n mapKeyEpochs(info as RawVaultKeyEpochsInfo, vaultIds[i]),\n );\n }\n\n async getVaultBasicInfo(vaultId: Hex): Promise<VaultBasicInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as RawVaultBasicInfo;\n\n return mapVaultBasicInfo(result);\n }\n\n async getVaultProtocolInfo(vaultId: Hex): Promise<VaultProtocolInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultProtocolInfo;\n\n return mapVaultProtocolInfo(result);\n }\n\n async getProtocolInfoBatch(\n vaultIds: readonly Hex[],\n ): Promise<VaultProtocolInfo[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) => {\n const result = info as unknown as RawVaultProtocolInfo;\n // An empty record is not proof the vault is absent: a lagging RPC\n // node returns HTTP 200 with a zero struct, so no retry below this\n // layer can see it. Single-shot is only safe because the finality\n // gate (`waitForPeginRegistrationDepth`) runs first on the deposit\n // path — move this ahead of it and the read-after-write race returns.\n assertVaultRecordPresent(result, vaultIds[i]);\n return mapVaultProtocolInfo(result);\n });\n }\n\n /**\n * Read the protocol pegin fee (in wei) for a given vault provider.\n * Mirrors the `getPegInFee(address)` view on BTCVaultRegistry.\n */\n async getPegInFee(vaultProvider: Address): Promise<bigint> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n }\n\n /**\n * Read a vault provider's current commission in basis points from\n * BTCVaultRegistry. The contract enforces `commissionBps < 10000`, so the\n * legitimate range is `[0, 9999]`; anything outside indicates a wrong\n * contract address or ABI drift and is surfaced as an error rather than\n * trusted.\n */\n async getVaultProviderCommission(vaultProvider: Address): Promise<number> {\n // viem infers `number` from the `uint16` return in the `as const` ABI.\n const bps = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderCommission\",\n args: [vaultProvider],\n });\n\n if (!Number.isInteger(bps) || bps < 0 || bps > MAX_VP_COMMISSION_BPS) {\n throw new Error(\n `getVaultProviderCommission returned ${bps} bps for ${vaultProvider}, ` +\n `outside the protocol range [0, ${MAX_VP_COMMISSION_BPS}]`,\n );\n }\n\n return bps;\n }\n\n async getVaultData(vaultId: Hex): Promise<VaultData> {\n // One round-trip for both structs (hard-fail): they feed signing/refund/\n // broadcast rebinds, so reading them in a single multicall also pins both\n // to the same block — no basic/protocol skew across two `eth_call`s.\n const [basicRaw, protocolRaw] = await this.publicClient.multicall({\n contracts: [\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n },\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n },\n ],\n allowFailure: false,\n });\n\n const basic = mapVaultBasicInfo(basicRaw);\n const protocol = mapVaultProtocolInfo(protocolRaw);\n\n assertVaultRecordPresent(protocol, vaultId);\n\n return { basic, protocol };\n }\n\n /** @inheritdoc */\n async getRegistrationRecordsAtBlock(\n createdAt: bigint,\n ): Promise<PeginRegistrationRecord[]> {\n // Deliberately no `vaultId` topic filter: the block holds the target's\n // registration, so only an unfiltered answer can tell a node that served\n // nothing (empty) from one that lacks the target (findRegistrationRecord),\n // and one query serves every vault a caller reads from the block. strict:\n // a log whose data does not decode against the ABI is dropped (viem\n // parseEventLogs) instead of surfacing as `args: {}`.\n const logs = await this.publicClient.getLogs({\n address: this.contractAddress,\n event: PEGIN_SUBMITTED_EVENT,\n fromBlock: createdAt,\n toBlock: createdAt,\n strict: true,\n });\n if (logs.length === 0) {\n throw new RegistrationLogsUnavailableError(createdAt);\n }\n\n const records = new Map<string, PeginRegistrationRecord>();\n for (const log of logs) {\n const record = mapRegistrationRecord(log.args, log.blockNumber);\n // Lenient decoding covers a malformed log, not a duplicate: a vault\n // registers once, so two logs for any id mean the node is inconsistent\n // and every record from this block is suspect — fail closed by design.\n if (records.has(record.vaultId)) {\n throw new Error(\n `Expected one PegInSubmitted log for vault ${record.vaultId} at block ${createdAt}, ` +\n `found more than one`,\n );\n }\n records.set(record.vaultId, record);\n }\n return [...records.values()];\n }\n\n /**\n * Read the depositor's commission ceiling (`maxAcceptableCommissionBps`)\n * for vaults registered in the same block, from their `PegInSubmitted`\n * logs. Returned in `vaultIds` order.\n *\n * The contract bound-checks the ceiling and discards it (PeginLogic.sol,\n * `VaultProviderCommissionExceeded`), so the registration log is its only\n * on-chain source. Vault ids are matched case-insensitively.\n *\n * @throws As {@link getRegistrationRecordsAtBlock}, plus the same typed\n * transient error when a vault has no registration log in its own\n * `createdAt` block.\n */\n async getMaxAcceptableCommissionBpsBatch(\n vaultIds: readonly Hex[],\n createdAt: bigint,\n ): Promise<number[]> {\n if (vaultIds.length === 0) return [];\n\n const records = await this.getRegistrationRecordsAtBlock(createdAt);\n return vaultIds.map(\n (vaultId) =>\n findRegistrationRecord(records, vaultId, createdAt)\n .maxAcceptableCommissionBps,\n );\n }\n\n /** @inheritdoc */\n async getVaultClaimableBy(\n vaultId: Hex,\n claimerPk: Hex,\n createdAt: bigint,\n ): Promise<VaultClaimableByEvent> {\n const claimer = assertOnChainBtcPubkey(\n claimerPk,\n `getVaultClaimableBy claimer (vault=${vaultId})`,\n );\n const claimerTopic = `0x${claimer}` as Hex;\n // viem re-filters the decoded logs client-side against `args`, comparing a\n // bytes32 with `===` against lower-case hex (parseEventLogs.ts:140,172-188).\n const vaultIdTopic = vaultId.toLowerCase() as Hex;\n // Finalized, not latest: the block found here is what the prover proves\n // against, and an unfinalized redeem can reorg away (btc-vault binds the\n // same scan to its finality level, eth-client client.rs:5989-6040).\n const { number: finalized } = await this.publicClient.getBlock({\n blockTag: \"finalized\",\n });\n if (finalized < createdAt) {\n throw new Error(\n `Finalized block ${finalized} is below vault ${vaultId}'s registration block ${createdAt}; ` +\n `the registration is not finalized yet, or the node is behind it`,\n );\n }\n\n // Newest first: the redeem usually trails the tip by far less than it\n // trails the registration. The contract emits every VaultClaimableBy of a\n // vault in one transaction, so the first non-empty chunk is the answer.\n let toBlock = finalized;\n for (;;) {\n const fromBlock = maxBigint(\n createdAt,\n toBlock - VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS + 1n,\n );\n const logs = await this.publicClient.getLogs({\n address: this.contractAddress,\n event: VAULT_CLAIMABLE_BY_EVENT,\n args: { vaultId: vaultIdTopic, claimerPK: claimerTopic },\n fromBlock,\n toBlock,\n strict: true,\n });\n // A redeem emits every VaultClaimableBy of a vault in ONE transaction\n // (RedeemLogic.sol), and `redeemForDepositor` emits the VP's key and\n // then the depositor's — so when those two keys are equal this filter\n // legitimately matches twice. Identical authorizations from one\n // transaction are the same fact; logs spanning transactions are not.\n if (logs.length > 1) {\n const transactions = new Set(logs.map((log) => log.transactionHash));\n if (transactions.size > 1) {\n throw new Error(\n `Found ${logs.length} VaultClaimableBy logs for vault ${vaultId} and claimer ` +\n `${claimerTopic} across ${transactions.size} transactions in blocks ` +\n `${fromBlock}..${toBlock}; a vault is redeemed once, so the node's answer ` +\n `is inconsistent`,\n );\n }\n }\n if (logs.length >= 1) {\n const log = logs[0];\n return {\n blockNumber: log.blockNumber,\n claimerPk: assertOnChainBtcPubkey(\n log.args.claimerPK,\n `VaultClaimableBy.claimerPK (vault=${vaultId})`,\n ),\n peginTxHash: log.args.peginTxHash,\n vaultCoreVersion: log.args.vaultCoreVersion,\n proverCircuitVersion: log.args.proverCircuitVersion,\n offchainParamsVersion: log.args.offchainParamsVersion,\n universalChallengersVersion: log.args.universalChallengersVersion,\n appVaultKeepersVersion: log.args.appVaultKeepersVersion,\n };\n }\n if (fromBlock === createdAt) {\n throw new VaultClaimableByNotFoundError(\n vaultId,\n claimerTopic,\n createdAt,\n finalized,\n );\n }\n toBlock = fromBlock - 1n;\n }\n }\n}\n","import {\n encodeFunctionData,\n isAddressEqual,\n zeroAddress,\n type Address,\n type Chain,\n type Hex,\n type PublicClient,\n type WalletClient,\n} from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\nimport { handleContractError } from \"../../contracts/errors\";\nimport {\n capMaxAcceptableCommissionBps,\n COMMISSION_BPS_HEADROOM,\n} from \"../../deposit-terms/commissionCeiling\";\nimport { waitForTransactionReceiptSmartAware } from \"../../utils/eth\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\nimport { assertPayoutScriptMatchesPopKey } from \"./payout-script\";\nimport { calculateBtcTxHash, derivePeginVaultId } from \"./pegin-transaction\";\nimport { ViemVaultRegistryReader } from \"./vault-registry-reader\";\n\n/** Referral code sent with peg-in registration. Zero means no referral. */\nexport const NO_REFERRAL_CODE = 0;\nconst UINT8_MAX = 255;\n// Match the prior vault-service timeout. A dropped transaction must not wait forever.\nconst RECEIPT_TIMEOUT_MS = 120_000;\n\nfunction ensureHex(value: string, label: string): Hex {\n const prefixed = value.startsWith(\"0x\")\n ? value\n : value.startsWith(\"0X\")\n ? `0x${value.slice(2)}`\n : `0x${value}`;\n if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(prefixed)) {\n throw new Error(`${label} must be non-empty, even-length hex`);\n }\n return prefixed as Hex;\n}\n\nfunction assertBytes32(value: Hex, label: string): void {\n if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {\n throw new Error(`${label} must be a 32-byte hex value`);\n }\n}\n\n/** All-zero `bytes32` — the shape an unresolved fingerprint takes. */\nconst ZERO_BYTES32 =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\";\n\n/**\n * The single validation point for `expectedFingerprint`, on both the singular\n * and batch paths.\n *\n * Zero is rejected separately from the shape check because it is a *well-formed*\n * `bytes32` that the registry can never accept — the live fingerprint is a\n * keccak256 over a domain-separated preimage — so it can only ever mean the\n * caller had no value and filled the slot. Catching it here turns a defaulted\n * field into a named error instead of an opaque on-chain revert with two\n * hashes and no hint.\n */\nfunction assertFingerprint(value: Hex): void {\n assertBytes32(value, \"expectedFingerprint\");\n if (value.toLowerCase() === ZERO_BYTES32) {\n throw new Error(\n \"expectedFingerprint must not be zero: the registry cannot resolve a \" +\n \"zero fingerprint, so this submission would always revert\",\n );\n }\n}\n\nfunction assertHtlcVout(value: number): void {\n if (!Number.isInteger(value) || value < 0 || value > UINT8_MAX) {\n throw new Error(`htlcVout must be a uint8, got ${value}`);\n }\n}\n\n/** A PoP prepared by a Bitcoin wallet, reusable by the ETH submit client. */\nexport interface PopSignature {\n btcPopSignature: Hex;\n depositorEthAddress: Address;\n /** x-only secp256k1 public key, 64 hex chars without `0x`. */\n depositorBtcPubkey: string;\n}\n\nexport interface ViemPeginRegistrationClientConfig {\n ethWallet: WalletClient;\n ethChain: Chain;\n publicClient: PublicClient;\n btcVaultRegistry: Address;\n receiptTimeoutMs?: number;\n /**\n * Refuse to register without a `quotedCommissionBps`. Set it to `true` when\n * the depositor approved deposit terms on a device: approval froze the\n * commission ceiling from the quote, so the chain-current fallback could\n * admit a commission the device would later refuse to pay out.\n *\n * Required, with no default: an omitted flag would silently pick the unsafe\n * direction for the integrator least able to probe the wallet capability.\n */\n requireQuotedCommissionBps: boolean;\n}\n\nexport interface RegisterPeginOnChainParams {\n unsignedPrePeginTx: string;\n depositorSignedPeginTx: string;\n vaultProvider: Address;\n hashlock: Hex;\n depositorWotsPkHash: Hex;\n popSignature: PopSignature;\n /** Raw x-only, compressed, or uncompressed BTC pubkey from the PoP wallet. */\n depositorBtcPubkeyRaw: string;\n htlcVout: number;\n /**\n * Bitcoin output script bytes, not an address. The client verifies that the\n * script pays the proof-of-possession key before it submits the transaction.\n */\n depositorPayoutScriptPubKey: string;\n quotedCommissionBps?: number;\n /**\n * `keccak256(abi.encode(...))` over the protocol state the Pre-PegIn was\n * built against — see the SDK's `pegin-fingerprint` module.\n *\n * The registry recomputes it live at inclusion and reverts with\n * `PeginFingerprintChanged` on any difference, so it must be computed from\n * the same block-pinned snapshot that shaped the Bitcoin scripts. Required,\n * with no default: a fingerprint the caller did not resolve is not a\n * fingerprint, and the registry has no way to tell the two apart.\n */\n expectedFingerprint: Hex;\n}\n\nexport interface PeginRegistrationResult {\n ethTxHash: Hex;\n vaultId: Hex;\n peginTxHash: Hex;\n}\n\nexport interface BatchPeginRegistrationItem {\n depositorSignedPeginTx: string;\n hashlock: Hex;\n htlcVout: number;\n /**\n * Bitcoin output script bytes, not an address. The client verifies that the\n * script pays the proof-of-possession key before it submits the transaction.\n */\n depositorPayoutScriptPubKey: string;\n depositorWotsPkHash: Hex;\n}\n\nexport interface RegisterPeginBatchOnChainParams {\n vaultProvider: Address;\n unsignedPrePeginTx: string;\n requests: BatchPeginRegistrationItem[];\n popSignature: PopSignature;\n /** Raw x-only, compressed, or uncompressed BTC pubkey from the PoP wallet. */\n depositorBtcPubkeyRaw: string;\n quotedCommissionBps?: number;\n /**\n * See {@link RegisterPeginOnChainParams.expectedFingerprint}. One value for\n * the whole batch: the fingerprint takes no per-request input and a batch\n * fixes one vault provider, so every entry would resolve the same value.\n */\n expectedFingerprint: Hex;\n}\n\nexport interface BatchPeginRegistrationResultItem {\n vaultId: Hex;\n peginTxHash: Hex;\n}\n\nexport interface PeginBatchRegistrationResult {\n ethTxHash: Hex;\n vaults: BatchPeginRegistrationResultItem[];\n}\n\n/**\n * Ethereum-only client for the on-chain half of peg-in registration.\n *\n * It consumes Bitcoin artifacts that were prepared earlier, but owns no BTC\n * wallet and imports neither Bitcoin libraries nor the Rust/WASM package.\n */\nexport class ViemPeginRegistrationClient {\n constructor(private readonly config: ViemPeginRegistrationClientConfig) {}\n\n async registerPeginOnChain(\n params: RegisterPeginOnChainParams,\n ): Promise<PeginRegistrationResult> {\n const request = {\n ...params,\n popSignature: { ...params.popSignature },\n };\n this.assertQuotedCommissionPresentWhenRequired(request.quotedCommissionBps);\n // Second, matching the batch path, so the two public entry points validate\n // in the same order and neither can drift behind a chain call.\n assertFingerprint(request.expectedFingerprint);\n const depositor = this.assertPopMatchesEthAccount(request.popSignature);\n const depositorBtcPubkey = this.normalizeBtcPubkey(request.popSignature);\n const btcPopSignature = ensureHex(\n request.popSignature.btcPopSignature,\n \"btcPopSignature\",\n );\n const normalized = this.normalizeRequest(\n request,\n depositor,\n depositorBtcPubkey,\n );\n\n await this.assertVaultDoesNotExist(\n normalized.vaultId,\n normalized.peginTxHash,\n );\n const peginFee = await this.readPeginFee(request.vaultProvider);\n const maxCommission = await this.resolveMaxAcceptableCommissionBps(\n request.vaultProvider,\n request.quotedCommissionBps,\n );\n const callData = encodeFunctionData({\n abi: BTCVaultRegistryABI,\n functionName: \"submitPeginRequest\",\n args: [\n depositor,\n depositorBtcPubkey,\n btcPopSignature,\n normalized.unsignedPrePeginTx,\n normalized.depositorSignedPeginTx,\n request.vaultProvider,\n maxCommission,\n request.hashlock,\n request.htlcVout,\n normalized.payoutScript,\n request.depositorWotsPkHash,\n // Appended last on the singular overload; the batch takes it at\n // position 4 instead. Order is the selector, so do not \"tidy\" either.\n request.expectedFingerprint,\n ],\n });\n\n const ethTxHash = await this.sendAndWait(\n callData,\n peginFee,\n false,\n depositor,\n );\n return {\n ethTxHash,\n vaultId: normalized.vaultId,\n peginTxHash: normalized.peginTxHash,\n };\n }\n\n async registerPeginBatchOnChain(\n params: RegisterPeginBatchOnChainParams,\n ): Promise<PeginBatchRegistrationResult> {\n const batch = {\n ...params,\n popSignature: { ...params.popSignature },\n requests: params.requests.map((request) => ({ ...request })),\n };\n if (batch.requests.length === 0) {\n throw new Error(\"Batch pegin requires at least one request\");\n }\n this.assertQuotedCommissionPresentWhenRequired(batch.quotedCommissionBps);\n assertFingerprint(batch.expectedFingerprint);\n const depositor = this.assertPopMatchesEthAccount(batch.popSignature);\n const unsignedPrePeginTx = ensureHex(\n batch.unsignedPrePeginTx,\n \"unsignedPrePeginTx\",\n );\n const depositorBtcPubkey = this.normalizeBtcPubkey(batch.popSignature);\n const btcPopSignature = ensureHex(\n batch.popSignature.btcPopSignature,\n \"btcPopSignature\",\n );\n\n const vaults: BatchPeginRegistrationResultItem[] = [];\n const requests = [];\n const seenVaultIds = new Set<string>();\n for (const request of batch.requests) {\n const normalized = this.normalizeRequest(\n {\n ...request,\n unsignedPrePeginTx: batch.unsignedPrePeginTx,\n vaultProvider: batch.vaultProvider,\n depositorBtcPubkeyRaw: batch.depositorBtcPubkeyRaw,\n },\n depositor,\n depositorBtcPubkey,\n );\n if (seenVaultIds.has(normalized.vaultId)) {\n throw new Error(`Duplicate vault in batch: ${normalized.vaultId}`);\n }\n seenVaultIds.add(normalized.vaultId);\n vaults.push({\n vaultId: normalized.vaultId,\n peginTxHash: normalized.peginTxHash,\n });\n requests.push({\n depositorBtcPubKey: depositorBtcPubkey,\n btcPopSignature,\n unsignedPrePeginTx,\n depositorSignedPeginTx: normalized.depositorSignedPeginTx,\n hashlock: request.hashlock,\n htlcVout: request.htlcVout,\n referralCode: NO_REFERRAL_CODE,\n depositorPayoutBtcAddress: normalized.payoutScript,\n depositorWotsPkHash: request.depositorWotsPkHash,\n });\n }\n for (const vault of vaults) {\n await this.assertVaultDoesNotExist(vault.vaultId, vault.peginTxHash);\n }\n\n const peginFee = await this.readPeginFee(batch.vaultProvider);\n const maxCommission = await this.resolveMaxAcceptableCommissionBps(\n batch.vaultProvider,\n batch.quotedCommissionBps,\n );\n const callData = encodeFunctionData({\n abi: BTCVaultRegistryABI,\n functionName: \"submitPeginRequestBatch\",\n // `expectedFingerprint` sits BEFORE `requests`, not appended. Reordering\n // these five changes the selector and the call stops existing.\n args: [\n depositor,\n batch.vaultProvider,\n maxCommission,\n batch.expectedFingerprint,\n requests,\n ],\n });\n const ethTxHash = await this.sendAndWait(\n callData,\n peginFee * BigInt(batch.requests.length),\n true,\n depositor,\n );\n return { ethTxHash, vaults };\n }\n\n private assertQuotedCommissionPresentWhenRequired(\n quotedCommissionBps?: number,\n ): void {\n if (\n quotedCommissionBps === undefined &&\n this.config.requireQuotedCommissionBps\n ) {\n throw new Error(\n \"quotedCommissionBps is required when the wallet approved deposit \" +\n \"terms: the registration ceiling must anchor to the approved quote.\",\n );\n }\n }\n\n private assertPopMatchesEthAccount(pop: PopSignature): Address {\n return this.assertEthAccount(pop.depositorEthAddress);\n }\n\n private assertEthAccount(expectedDepositor: Address): Address {\n const account = this.config.ethWallet.account;\n if (!account) throw new Error(\"Ethereum wallet account not found\");\n if (!isAddressEqual(expectedDepositor, account.address)) {\n throw new Error(\n `Proof of possession was signed for ${expectedDepositor} ` +\n `but the Ethereum wallet is currently connected to ${account.address}. ` +\n `Reconnect the original account or sign a new proof of possession.`,\n );\n }\n return account.address;\n }\n\n private normalizeBtcPubkey(pop: PopSignature): Hex {\n return `0x${assertOnChainBtcPubkey(\n ensureHex(pop.depositorBtcPubkey, \"Proof of possession BTC pubkey\"),\n \"Proof of possession BTC pubkey\",\n )}`;\n }\n\n // `expectedFingerprint` is omitted rather than accepted and ignored: nothing\n // here normalizes it, and requiring it would force the batch loop to thread a\n // value through a per-request helper that has no use for it. It is validated\n // once per call, at the top of each public method.\n private normalizeRequest(\n params: Omit<\n RegisterPeginOnChainParams,\n \"popSignature\" | \"expectedFingerprint\"\n >,\n depositor: Address,\n depositorBtcPubkey: Hex,\n ) {\n assertBytes32(params.hashlock, \"hashlock\");\n assertBytes32(params.depositorWotsPkHash, \"depositorWotsPkHash\");\n assertHtlcVout(params.htlcVout);\n const unsignedPrePeginTx = ensureHex(\n params.unsignedPrePeginTx,\n \"unsignedPrePeginTx\",\n );\n const depositorSignedPeginTx = ensureHex(\n params.depositorSignedPeginTx,\n \"depositorSignedPeginTx\",\n );\n const peginTxHash = calculateBtcTxHash(depositorSignedPeginTx);\n return {\n unsignedPrePeginTx,\n depositorSignedPeginTx,\n payoutScript: assertPayoutScriptMatchesPopKey(\n params.depositorPayoutScriptPubKey,\n depositorBtcPubkey,\n params.depositorBtcPubkeyRaw,\n ),\n peginTxHash,\n vaultId: ensureHex(derivePeginVaultId(peginTxHash, depositor), \"vaultId\"),\n };\n }\n\n private async assertVaultDoesNotExist(\n vaultId: Hex,\n peginTxHash: Hex,\n ): Promise<void> {\n const result = (await this.config.publicClient.readContract({\n address: this.config.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as { depositor: Address };\n if (result.depositor !== zeroAddress) {\n throw new Error(\n `Vault already exists (ID: ${vaultId}, peginTxHash: ${peginTxHash}). ` +\n `Vault IDs are derived from the pegin transaction hash and depositor address. ` +\n `To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`,\n );\n }\n }\n\n private async readPeginFee(vaultProvider: Address): Promise<bigint> {\n try {\n return (await this.config.publicClient.readContract({\n address: this.config.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n } catch (error) {\n throw new Error(\n \"Failed to query pegin fee from the contract. \" +\n \"Please check your network connection and contract address.\",\n { cause: error },\n );\n }\n }\n\n private async resolveMaxAcceptableCommissionBps(\n vaultProvider: Address,\n quotedCommissionBps?: number,\n ): Promise<number> {\n let currentBps: number;\n try {\n currentBps = await new ViemVaultRegistryReader(\n this.config.publicClient,\n this.config.btcVaultRegistry,\n ).getVaultProviderCommission(vaultProvider);\n } catch (error) {\n throw new Error(\n \"Failed to query vault provider commission from the contract. \" +\n \"Please check your network connection and contract address.\",\n { cause: error },\n );\n }\n if (quotedCommissionBps !== undefined) {\n if (currentBps > quotedCommissionBps + COMMISSION_BPS_HEADROOM) {\n throw new Error(\n `Vault provider commission changed since quote: quoted ${quotedCommissionBps} bps, ` +\n `chain currently reports ${currentBps} bps (allowed drift ${COMMISSION_BPS_HEADROOM} bps). ` +\n `Please refresh and try again.`,\n );\n }\n return capMaxAcceptableCommissionBps(quotedCommissionBps);\n }\n return capMaxAcceptableCommissionBps(currentBps);\n }\n\n private async sendAndWait(\n data: Hex,\n value: bigint,\n batch: boolean,\n depositor: Address,\n ): Promise<Hex> {\n let account = this.assertEthAccount(depositor);\n let gas: bigint;\n try {\n gas = await this.config.publicClient.estimateGas({\n to: this.config.btcVaultRegistry,\n data,\n value,\n account,\n });\n } catch (error) {\n handleContractError(error);\n }\n\n account = this.assertEthAccount(depositor);\n let submittedHash: Hex;\n try {\n submittedHash = await this.config.ethWallet.sendTransaction({\n to: this.config.btcVaultRegistry,\n data,\n value,\n gas,\n account,\n chain: this.config.ethChain,\n });\n } catch (error) {\n handleContractError(error);\n }\n const receipt = await waitForTransactionReceiptSmartAware({\n publicClient: this.config.publicClient,\n walletAddress: depositor,\n hash: submittedHash,\n timeout: this.config.receiptTimeoutMs ?? RECEIPT_TIMEOUT_MS,\n });\n if (receipt.status === \"reverted\") {\n handleContractError(\n new Error(\n `${batch ? \"Batch transaction\" : \"Transaction\"} reverted. ` +\n `Hash: ${receipt.transactionHash}. Check a block explorer for details.`,\n ),\n );\n }\n return receipt.transactionHash;\n }\n}\n"],"names":["COMMISSION_BPS_HEADROOM","MAX_ACCEPTABLE_COMMISSION_BPS_CAP","capMaxAcceptableCommissionBps","bps","MAX_VP_COMMISSION_BPS_EXCLUSIVE","MAX_VP_COMMISSION_BPS","mapVaultBasicInfo","result","mapVaultProtocolInfo","offchainParamsVersion","assertValidOffchainParamsVersion","UINT64_EXCLUSIVE_UPPER_BOUND","VP_GENESIS_KEY_EPOCH","PEGIN_SUBMITTED_EVENT","getAbiItem","BTCVaultRegistryABI","VAULT_CLAIMABLE_BY_EVENT","VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS","maxBigint","a","b","mapRegistrationRecord","args","blockNumber","assertEpochInRange","value","field","vaultId","VAULT_RECORD_NOT_FOUND_MESSAGE","assertVaultRecordPresent","record","mapKeyEpochs","ViemVaultRegistryReader","publicClient","contractAddress","vpAddress","epoch","assertOnChainBtcPubkey","BTCVaultRegistryKeyEpochsABI","vaultIds","info","i","vaultProvider","basicRaw","protocolRaw","basic","protocol","createdAt","logs","RegistrationLogsUnavailableError","records","log","findRegistrationRecord","claimerPk","claimerTopic","vaultIdTopic","finalized","toBlock","fromBlock","transactions","VaultClaimableByNotFoundError","NO_REFERRAL_CODE","UINT8_MAX","RECEIPT_TIMEOUT_MS","ensureHex","label","prefixed","assertBytes32","ZERO_BYTES32","assertFingerprint","assertHtlcVout","ViemPeginRegistrationClient","config","params","request","depositor","depositorBtcPubkey","btcPopSignature","normalized","peginFee","maxCommission","callData","encodeFunctionData","batch","unsignedPrePeginTx","vaults","requests","seenVaultIds","vault","quotedCommissionBps","pop","expectedDepositor","account","isAddressEqual","depositorSignedPeginTx","peginTxHash","calculateBtcTxHash","assertPayoutScriptMatchesPopKey","derivePeginVaultId","zeroAddress","error","currentBps","data","gas","handleContractError","submittedHash","receipt","waitForTransactionReceiptSmartAware"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const f=require("viem"),a=require("./BTCVaultRegistry.abi-DzbfZ9_s.cjs"),C=require("./BTCVaultRegistryKeyEpochs.abi-CReWFJdu.cjs"),T=require("./constants-BCg6O0PX.cjs"),k=require("./tbv/core/utils/eth/index.cjs"),h=require("./registration-records-CKc0OVuK.cjs"),B=25,R=9999;function w(r){if(!Number.isInteger(r)||r<0||r>=T.MAX_VP_COMMISSION_BPS_EXCLUSIVE)throw new Error(`Quoted commissionBps must be an integer in [0, ${T.MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${r}`);return Math.min(r+B,R)}const v=9999;function x(r){return{depositor:r.depositor,depositorBtcPubKey:r.depositorBtcPubKey,amount:r.amount,vaultProvider:r.vaultProvider,status:r.status,applicationEntryPoint:r.applicationEntryPoint,createdAt:r.createdAt}}function y(r){const t=Number(r.offchainParamsVersion);return h.assertValidOffchainParamsVersion(t),{depositorSignedPeginTx:r.depositorSignedPeginTx,universalChallengersVersion:r.universalChallengersVersion,appVaultKeepersVersion:r.appVaultKeepersVersion,offchainParamsVersion:t,verifiedAt:r.verifiedAt,depositorWotsPkHash:r.depositorWotsPkHash,hashlock:r.hashlock,htlcVout:r.htlcVout,depositorPopSignature:r.depositorPopSignature,prePeginTxHash:r.prePeginTxHash,vaultProviderCommissionBps:r.vaultProviderCommissionBps,claimExpiredUntil:r.claimExpiredUntil,vaultCoreVersion:r.vaultCoreVersion}}const N=1n<<64n,$=0n,K=f.getAbiItem({abi:a.BTCVaultRegistryABI,name:"PegInSubmitted"}),O=f.getAbiItem({abi:a.BTCVaultRegistryABI,name:"VaultClaimableBy"}),M=7200n;function H(r,t){return r>t?r:t}function q(r,t){return{vaultId:r.vaultId.toLowerCase(),depositor:r.depositor,vaultProvider:r.vaultProvider,amount:r.amount,vaultCoreVersion:r.vaultCoreVersion,universalChallengersVersion:r.universalChallengersVersion,appVaultKeepersVersion:r.appVaultKeepersVersion,proverCircuitVersion:r.proverCircuitVersion,offchainParamsVersion:r.offchainParamsVersion,peginTxHash:r.peginTxHash.toLowerCase(),depositorPayoutScriptPubKey:r.depositorPayoutBtcAddress.toLowerCase(),unsignedPrePeginTx:r.unsignedPrePeginTx,maxAcceptableCommissionBps:r.maxAcceptableCommissionBps,blockNumber:t}}function V(r,t,e){if(r<0n||r>=N)throw new Error(`getBtcVaultProtocolInfo returned ${t}=${r} for vault ${e}, outside the uint64 range — the registry may predate RFC-006`);return r}const F="not found on-chain or has no pegin transaction";function E(r,t){if(!r.depositorSignedPeginTx||r.depositorSignedPeginTx==="0x")throw new Error(`Vault ${t} ${F}`)}function I(r,t){return E(r,t),{vpKeyEpoch:V(r.vpKeyEpoch,"vpKeyEpoch",t),appKeeperKeyEpoch:V(r.appKeeperKeyEpoch,"appKeeperKeyEpoch",t),ucKeyEpoch:V(r.ucKeyEpoch,"ucKeyEpoch",t)}}class _{constructor(t,e){this.publicClient=t,this.contractAddress=e}async getVaultProviderGenesisBtcPubKey(t,e){return this.getVaultProviderOperationBtcKeyAtEpoch(t,$,e)}async getVaultProviderOperationBtcKeyAtEpoch(t,e,o){const i=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getOperationBtcKeyAtEpoch",args:[t,e],blockNumber:o});return h.assertOnChainBtcPubkey(i,`getOperationBtcKeyAtEpoch (vp=${t}, epoch=${e})`)}async getVaultProviderApplication(t,e){return await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getVaultProviderApplication",args:[t],blockNumber:e})}async getCurrentVaultProviderOperationBtcKey(t){const e=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getCurrentOperationBtcKey",args:[t]});return h.assertOnChainBtcPubkey(e,`getCurrentOperationBtcKey (vp=${t})`)}async getVaultKeyEpochs(t){const e=await this.publicClient.readContract({address:this.contractAddress,abi:C.BTCVaultRegistryKeyEpochsABI,functionName:"getBtcVaultProtocolInfo",args:[t]});return I(e,t)}async getVaultKeyEpochsBatch(t){return t.length===0?[]:(await this.publicClient.multicall({contracts:t.map(o=>({address:this.contractAddress,abi:C.BTCVaultRegistryKeyEpochsABI,functionName:"getBtcVaultProtocolInfo",args:[o]})),allowFailure:!1})).map((o,i)=>I(o,t[i]))}async getVaultBasicInfo(t){const e=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[t]});return x(e)}async getVaultProtocolInfo(t){const e=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[t]});return y(e)}async getProtocolInfoBatch(t){return t.length===0?[]:(await this.publicClient.multicall({contracts:t.map(o=>({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[o]})),allowFailure:!1})).map((o,i)=>{const s=o;return E(s,t[i]),y(s)})}async getPegInFee(t){return await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getPegInFee",args:[t]})}async getVaultProviderCommission(t){const e=await this.publicClient.readContract({address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getVaultProviderCommission",args:[t]});if(!Number.isInteger(e)||e<0||e>v)throw new Error(`getVaultProviderCommission returned ${e} bps for ${t}, outside the protocol range [0, ${v}]`);return e}async getVaultData(t){const[e,o]=await this.publicClient.multicall({contracts:[{address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[t]},{address:this.contractAddress,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultProtocolInfo",args:[t]}],allowFailure:!1}),i=x(e),s=y(o);return E(s,t),{basic:i,protocol:s}}async getRegistrationRecordsAtBlock(t){const e=await this.publicClient.getLogs({address:this.contractAddress,event:K,fromBlock:t,toBlock:t,strict:!0});if(e.length===0)throw new h.RegistrationLogsUnavailableError(t);const o=new Map;for(const i of e){const s=q(i.args,i.blockNumber);if(o.has(s.vaultId))throw new Error(`Expected one PegInSubmitted log for vault ${s.vaultId} at block ${t}, found more than one`);o.set(s.vaultId,s)}return[...o.values()]}async getMaxAcceptableCommissionBpsBatch(t,e){if(t.length===0)return[];const o=await this.getRegistrationRecordsAtBlock(e);return t.map(i=>h.findRegistrationRecord(o,i,e).maxAcceptableCommissionBps)}async getVaultClaimableBy(t,e,o){const s=`0x${h.assertOnChainBtcPubkey(e,`getVaultClaimableBy claimer (vault=${t})`)}`,n=t.toLowerCase(),{number:c}=await this.publicClient.getBlock({blockTag:"finalized"});if(c<o)throw new Error(`Finalized block ${c} is below vault ${t}'s registration block ${o}; the registration is not finalized yet, or the node is behind it`);let u=c;for(;;){const l=H(o,u-M+1n),g=await this.publicClient.getLogs({address:this.contractAddress,event:O,args:{vaultId:n,claimerPK:s},fromBlock:l,toBlock:u,strict:!0});if(g.length>1){const d=new Set(g.map(b=>b.transactionHash));if(d.size>1)throw new Error(`Found ${g.length} VaultClaimableBy logs for vault ${t} and claimer ${s} across ${d.size} transactions in blocks ${l}..${u}; a vault is redeemed once, so the node's answer is inconsistent`)}if(g.length>=1){const d=g[0];return{blockNumber:d.blockNumber,claimerPk:h.assertOnChainBtcPubkey(d.args.claimerPK,`VaultClaimableBy.claimerPK (vault=${t})`),peginTxHash:d.args.peginTxHash,vaultCoreVersion:d.args.vaultCoreVersion,proverCircuitVersion:d.args.proverCircuitVersion,offchainParamsVersion:d.args.offchainParamsVersion,universalChallengersVersion:d.args.universalChallengersVersion,appVaultKeepersVersion:d.args.appVaultKeepersVersion}}if(l===o)throw new h.VaultClaimableByNotFoundError(t,s,o,c);u=l-1n}}}const L=0,U=255,z=12e4;function m(r,t){const e=r.startsWith("0x")?r:r.startsWith("0X")?`0x${r.slice(2)}`:`0x${r}`;if(!/^0x(?:[0-9a-fA-F]{2})+$/.test(e))throw new Error(`${t} must be non-empty, even-length hex`);return e}function A(r,t){if(!/^0x[0-9a-fA-F]{64}$/.test(r))throw new Error(`${t} must be a 32-byte hex value`)}const D="0x0000000000000000000000000000000000000000000000000000000000000000";function S(r){if(A(r,"expectedFingerprint"),r.toLowerCase()===D)throw new Error("expectedFingerprint must not be zero: the registry cannot resolve a zero fingerprint, so this submission would always revert")}function W(r){if(!Number.isInteger(r)||r<0||r>U)throw new Error(`htlcVout must be a uint8, got ${r}`)}class X{constructor(t){this.config=t}async registerPeginOnChain(t){const e={...t,popSignature:{...t.popSignature}};this.assertQuotedCommissionPresentWhenRequired(e.quotedCommissionBps),S(e.expectedFingerprint);const o=this.assertPopMatchesEthAccount(e.popSignature),i=this.normalizeBtcPubkey(e.popSignature),s=m(e.popSignature.btcPopSignature,"btcPopSignature"),n=this.normalizeRequest(e,o,i);await this.assertVaultDoesNotExist(n.vaultId,n.peginTxHash);const c=await this.readPeginFee(e.vaultProvider),u=await this.resolveMaxAcceptableCommissionBps(e.vaultProvider,e.quotedCommissionBps),l=f.encodeFunctionData({abi:a.BTCVaultRegistryABI,functionName:"submitPeginRequest",args:[o,i,s,n.unsignedPrePeginTx,n.depositorSignedPeginTx,e.vaultProvider,u,e.hashlock,e.htlcVout,n.payoutScript,e.depositorWotsPkHash,e.expectedFingerprint]});return{ethTxHash:await this.sendAndWait(l,c,!1,o),vaultId:n.vaultId,peginTxHash:n.peginTxHash}}async registerPeginBatchOnChain(t){const e={...t,popSignature:{...t.popSignature},requests:t.requests.map(p=>({...p}))};if(e.requests.length===0)throw new Error("Batch pegin requires at least one request");this.assertQuotedCommissionPresentWhenRequired(e.quotedCommissionBps),S(e.expectedFingerprint);const o=this.assertPopMatchesEthAccount(e.popSignature),i=m(e.unsignedPrePeginTx,"unsignedPrePeginTx"),s=this.normalizeBtcPubkey(e.popSignature),n=m(e.popSignature.btcPopSignature,"btcPopSignature"),c=[],u=[],l=new Set;for(const p of e.requests){const P=this.normalizeRequest({...p,unsignedPrePeginTx:e.unsignedPrePeginTx,vaultProvider:e.vaultProvider,depositorBtcPubkeyRaw:e.depositorBtcPubkeyRaw},o,s);if(l.has(P.vaultId))throw new Error(`Duplicate vault in batch: ${P.vaultId}`);l.add(P.vaultId),c.push({vaultId:P.vaultId,peginTxHash:P.peginTxHash}),u.push({depositorBtcPubKey:s,btcPopSignature:n,unsignedPrePeginTx:i,depositorSignedPeginTx:P.depositorSignedPeginTx,hashlock:p.hashlock,htlcVout:p.htlcVout,referralCode:L,depositorPayoutBtcAddress:P.payoutScript,depositorWotsPkHash:p.depositorWotsPkHash})}for(const p of c)await this.assertVaultDoesNotExist(p.vaultId,p.peginTxHash);const g=await this.readPeginFee(e.vaultProvider),d=await this.resolveMaxAcceptableCommissionBps(e.vaultProvider,e.quotedCommissionBps),b=f.encodeFunctionData({abi:a.BTCVaultRegistryABI,functionName:"submitPeginRequestBatch",args:[o,e.vaultProvider,d,e.expectedFingerprint,u]});return{ethTxHash:await this.sendAndWait(b,g*BigInt(e.requests.length),!0,o),vaults:c}}assertQuotedCommissionPresentWhenRequired(t){if(t===void 0&&this.config.requireQuotedCommissionBps)throw new Error("quotedCommissionBps is required when the wallet approved deposit terms: the registration ceiling must anchor to the approved quote.")}assertPopMatchesEthAccount(t){return this.assertEthAccount(t.depositorEthAddress)}assertEthAccount(t){const e=this.config.ethWallet.account;if(!e)throw new Error("Ethereum wallet account not found");if(!f.isAddressEqual(t,e.address))throw new Error(`Proof of possession was signed for ${t} but the Ethereum wallet is currently connected to ${e.address}. Reconnect the original account or sign a new proof of possession.`);return e.address}normalizeBtcPubkey(t){return`0x${h.assertOnChainBtcPubkey(m(t.depositorBtcPubkey,"Proof of possession BTC pubkey"),"Proof of possession BTC pubkey")}`}normalizeRequest(t,e,o){A(t.hashlock,"hashlock"),A(t.depositorWotsPkHash,"depositorWotsPkHash"),W(t.htlcVout);const i=m(t.unsignedPrePeginTx,"unsignedPrePeginTx"),s=m(t.depositorSignedPeginTx,"depositorSignedPeginTx"),n=h.calculateBtcTxHash(s);return{unsignedPrePeginTx:i,depositorSignedPeginTx:s,payoutScript:h.assertPayoutScriptMatchesPopKey(t.depositorPayoutScriptPubKey,o,t.depositorBtcPubkeyRaw),peginTxHash:n,vaultId:m(h.derivePeginVaultId(n,e),"vaultId")}}async assertVaultDoesNotExist(t,e){if((await this.config.publicClient.readContract({address:this.config.btcVaultRegistry,abi:a.BTCVaultRegistryABI,functionName:"getBtcVaultBasicInfo",args:[t]})).depositor!==f.zeroAddress)throw new Error(`Vault already exists (ID: ${t}, peginTxHash: ${e}). Vault IDs are derived from the pegin transaction hash and depositor address. To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`)}async readPeginFee(t){try{return await this.config.publicClient.readContract({address:this.config.btcVaultRegistry,abi:a.BTCVaultRegistryABI,functionName:"getPegInFee",args:[t]})}catch(e){throw new Error("Failed to query pegin fee from the contract. Please check your network connection and contract address.",{cause:e})}}async resolveMaxAcceptableCommissionBps(t,e){let o;try{o=await new _(this.config.publicClient,this.config.btcVaultRegistry).getVaultProviderCommission(t)}catch(i){throw new Error("Failed to query vault provider commission from the contract. Please check your network connection and contract address.",{cause:i})}if(e!==void 0){if(o>e+B)throw new Error(`Vault provider commission changed since quote: quoted ${e} bps, chain currently reports ${o} bps (allowed drift ${B} bps). Please refresh and try again.`);return w(e)}return w(o)}async sendAndWait(t,e,o,i){let s=this.assertEthAccount(i),n;try{n=await this.config.publicClient.estimateGas({to:this.config.btcVaultRegistry,data:t,value:e,account:s})}catch(l){C.handleContractError(l)}s=this.assertEthAccount(i);let c;try{c=await this.config.ethWallet.sendTransaction({to:this.config.btcVaultRegistry,data:t,value:e,gas:n,account:s,chain:this.config.ethChain})}catch(l){C.handleContractError(l)}const u=await k.waitForTransactionReceiptSmartAware({publicClient:this.config.publicClient,walletAddress:i,hash:c,timeout:this.config.receiptTimeoutMs??z});return u.status==="reverted"&&C.handleContractError(new Error(`${o?"Batch transaction":"Transaction"} reverted. Hash: ${u.transactionHash}. Check a block explorer for details.`)),u.transactionHash}}exports.COMMISSION_BPS_HEADROOM=B;exports.MAX_ACCEPTABLE_COMMISSION_BPS_CAP=R;exports.ViemPeginRegistrationClient=X;exports.ViemVaultRegistryReader=_;exports.capMaxAcceptableCommissionBps=w;
2
- //# sourceMappingURL=pegin-registration-client-DOb-Iznp.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pegin-registration-client-DOb-Iznp.cjs","sources":["../src/tbv/core/deposit-terms/commissionCeiling.ts","../src/tbv/core/clients/eth/vault-registry-reader.ts","../src/tbv/core/clients/eth/pegin-registration-client.ts"],"sourcesContent":["/**\n * The depositor's commission ceiling (`maxAcceptableCommissionBps`) policy:\n * quoted VP commission + drift headroom, capped below the contract's\n * exclusive bound. Shared by `PeginManager` (the approved terms) and the\n * registration calldata so both carry the same ceiling; a resume rebuild reads\n * that submitted value back from the `PegInSubmitted` log instead.\n *\n * @module deposit-terms/commissionCeiling\n */\n\n/*\n * Commission-check map (each guards a DIFFERENT boundary — do not consolidate):\n * 1. assertVpCommissionInProtocolRange (vault app, vaultPayoutSignatureService)\n * — chain-read trust boundary; mirrors VPKeyRegistryLogic.sol bounds.\n * 2. capMaxAcceptableCommissionBps (here) — depositor quote → ceiling policy;\n * mirrors PeginLogic.sol's strict > check via the +25bps headroom.\n * 3. buildDepositTerms range check — public-API precondition on the projection\n * that mints the device-enforced commissionFee.\n * 4. payout.ts commission cap — the VP-built tx's output value vs bps at the\n * signing site (CLAUDE.md Critical Path #3).\n * 5. envelope.ts dust/cross-field gates (ledger-vault-signer) — firmware-only\n * constants, pre-device-I/O (Critical Path #7).\n */\n\nimport { MAX_VP_COMMISSION_BPS_EXCLUSIVE } from \"../primitives/psbt/constants\";\n\n/**\n * Headroom (in basis points) added to the current VP commission to compute\n * `maxAcceptableCommissionBps` at submit time. Lets the VP raise its\n * commission by up to this amount between read and submit without forcing\n * a re-quote. Capped by {@link MAX_ACCEPTABLE_COMMISSION_BPS_CAP}.\n *\n * Contract check is strict `>` (PeginLogic.sol `VaultProviderCommissionExceeded`\n * revert), so +25 allows up\n * to +25 bps of drift.\n */\nexport const COMMISSION_BPS_HEADROOM = 25;\n\n/**\n * Hard ceiling for `maxAcceptableCommissionBps`. The contract enforces\n * `commissionBps < 10000`, so any value at/above that is unreachable;\n * `9999` is the maximum useful cap.\n */\nexport const MAX_ACCEPTABLE_COMMISSION_BPS_CAP = 9999;\n\n/**\n * The commission ceiling submitted as registration calldata and mirrored\n * into `DepositTerms.commissionFee`: quoted + drift headroom, capped.\n * Single source for both consumers — feed it the SAME quoted bps at prepare\n * and register time so device-accept stays coextensive with contract-accept.\n */\nexport function capMaxAcceptableCommissionBps(bps: number): number {\n // Validate the raw quote before headroom shifts its domain — a negative\n // quote must throw here, not become a small \"legal\" ceiling.\n // Reject an out-of-range quote outright — clamping it to 9999 would turn a\n // bad read into a 99.99% ceiling, the exact failure the cap exists to stop.\n if (\n !Number.isInteger(bps) ||\n bps < 0 ||\n bps >= MAX_VP_COMMISSION_BPS_EXCLUSIVE\n ) {\n throw new Error(\n `Quoted commissionBps must be an integer in ` +\n `[0, ${MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${bps}`,\n );\n }\n return Math.min(\n bps + COMMISSION_BPS_HEADROOM,\n MAX_ACCEPTABLE_COMMISSION_BPS_CAP,\n );\n}\n","/**\n * Concrete BTCVaultRegistry reader using viem's readContract.\n *\n * This is an optional utility — callers can use their own implementation\n * of the VaultRegistryReader interface.\n */\n\nimport type { Abi, Address, Hex, PublicClient } from \"viem\";\nimport { getAbiItem } from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\nimport { BTCVaultRegistryKeyEpochsABI } from \"../../contracts/abis/BTCVaultRegistryKeyEpochs.abi\";\nimport { VaultClaimableByNotFoundError } from \"./claimable-event-error\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\nimport { assertValidOffchainParamsVersion } from \"./protocol-params-validation\";\nimport { RegistrationLogsUnavailableError } from \"./registration-logs-error\";\nimport { findRegistrationRecord } from \"./registration-records\";\nimport type {\n KeyEpochs,\n OnChainBtcPubkey,\n PeginRegistrationRecord,\n VaultBasicInfo,\n VaultClaimableByEvent,\n VaultData,\n VaultProtocolInfo,\n VaultRegistryReader,\n} from \"./types\";\n\n/**\n * Inclusive upper bound the BTCVaultRegistry contract enforces on a vault\n * provider's commission (the contract check is `< 10000`).\n */\nconst MAX_VP_COMMISSION_BPS = 9999;\n\n/** Raw `getBtcVaultBasicInfo` tuple as decoded by viem. */\ntype RawVaultBasicInfo = {\n depositor: Address;\n depositorBtcPubKey: Hex;\n amount: bigint;\n vaultProvider: Address;\n status: number;\n applicationEntryPoint: Address;\n createdAt: bigint;\n};\n\n/**\n * Raw `getBtcVaultProtocolInfo` tuple as decoded by viem.\n *\n * Mirrors the ABI's components. The trailing key epochs are read through the\n * separate key-epochs ABI, so this prefix stops at `vaultCoreVersion`.\n */\ntype RawVaultProtocolInfo = {\n depositorSignedPeginTx: Hex;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n offchainParamsVersion: number;\n verifiedAt: bigint;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n depositorPopSignature: Hex;\n prePeginTxHash: Hex;\n vaultProviderCommissionBps: number;\n claimExpiredUntil: bigint;\n vaultCoreVersion: number;\n};\n\n/** Raw `getBtcVaultProtocolInfo` tuple as decoded by the key-epochs ABI. */\ntype RawVaultKeyEpochsInfo = RawVaultProtocolInfo & KeyEpochs;\n\nfunction mapVaultBasicInfo(result: RawVaultBasicInfo): VaultBasicInfo {\n return {\n depositor: result.depositor,\n depositorBtcPubKey: result.depositorBtcPubKey,\n amount: result.amount,\n vaultProvider: result.vaultProvider,\n status: result.status,\n applicationEntryPoint: result.applicationEntryPoint,\n createdAt: result.createdAt,\n };\n}\n\nfunction mapVaultProtocolInfo(result: RawVaultProtocolInfo): VaultProtocolInfo {\n const offchainParamsVersion = Number(result.offchainParamsVersion);\n assertValidOffchainParamsVersion(offchainParamsVersion);\n return {\n depositorSignedPeginTx: result.depositorSignedPeginTx,\n universalChallengersVersion: result.universalChallengersVersion,\n appVaultKeepersVersion: result.appVaultKeepersVersion,\n offchainParamsVersion,\n verifiedAt: result.verifiedAt,\n depositorWotsPkHash: result.depositorWotsPkHash,\n hashlock: result.hashlock,\n htlcVout: result.htlcVout,\n depositorPopSignature: result.depositorPopSignature,\n prePeginTxHash: result.prePeginTxHash,\n vaultProviderCommissionBps: result.vaultProviderCommissionBps,\n claimExpiredUntil: result.claimExpiredUntil,\n vaultCoreVersion: result.vaultCoreVersion,\n };\n}\n\n/**\n * Exclusive upper bound for a `uint64` epoch.\n *\n * viem does not range-check a decoded `uint64`, so a misaligned decode can\n * hand back a value far larger than the field can hold. Rejecting those is\n * cheap defence in depth against a mis-decode of the extended ABI.\n *\n * The state this is load-bearing for is narrower than \"a registry that predates\n * RFC-006\". Against a *fully* pre-RFC-006 registry the path fails closed on its\n * own: `resolveParticipantKeysAtEpochs` goes on to call\n * `getOperationBtcKeyAtEpochOrGenesis` on ApplicationRegistry and\n * ProtocolParams, which do not exist there, so the multicall reverts and these\n * epochs are never used. The reachable gap is a registry that *has* the\n * operation-key getters but whose `BTCVaultProtocolInfo` struct is not\n * extended — there the tail-data epochs resolve with no error at all, and this\n * range check is the only thing looking at them.\n *\n * Even for that case it is only a backstop, and a weak one: a misaligned decode\n * can land on a small, plausible-looking integer this range accepts. Correctness\n * rests on only ever pointing at an RFC-006 registry, which is a deployment\n * precondition rather than something this call can establish — see\n * https://github.com/babylonlabs-io/babylon-toolkit/issues/2192 for where that\n * check is owned, and `BTCVaultRegistryKeyEpochs.abi.ts` for the decode hazard.\n */\nconst UINT64_EXCLUSIVE_UPPER_BOUND = 1n << 64n;\n\n/**\n * The epoch a vault provider's registration key is bonded at.\n *\n * A provider's operation-key history is append-only and every appended version\n * is stamped at epoch 1 or later, so epoch 0 always resolves to the key set at\n * registration. This is what lets `getOperationBtcKeyAtEpoch` stand in for the\n * removed `getVaultProviderBTCKey` getter.\n */\nconst VP_GENESIS_KEY_EPOCH = 0n;\n\nconst PEGIN_SUBMITTED_EVENT = getAbiItem({\n abi: BTCVaultRegistryABI,\n name: \"PegInSubmitted\",\n});\n\nconst VAULT_CLAIMABLE_BY_EVENT = getAbiItem({\n abi: BTCVaultRegistryABI,\n name: \"VaultClaimableBy\",\n});\n\n/**\n * Block span of one `VaultClaimableBy` query: btc-vault's own scan chunk\n * (`EVENT_QUERY_CHUNK_BLOCKS = 7200`, `crates/eth-client/src/client.rs:793`\n * @ ac4954e7), about a day of Ethereum blocks, so a recent redeem costs one\n * request. Not every provider serves a range this wide — an Alchemy free key\n * caps `eth_getLogs` at 10 blocks\n * (https://www.alchemy.com/docs/reference/eth-getlogs) — and a provider that\n * answered a wide range short instead of erroring would make this scan report\n * not-found, so confirming the RPC honours 7,200-block ranges is a\n * prerequisite of a claim run.\n */\nconst VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS = 7_200n;\n\nfunction maxBigint(a: bigint, b: bigint): bigint {\n return a > b ? a : b;\n}\n\n/** A `PegInSubmitted` log's decoded args, as viem's strict `getLogs` hands them back. */\ninterface PegInSubmittedArgs {\n vaultId: Hex;\n peginTxHash: Hex;\n depositor: Address;\n vaultProvider: Address;\n amount: bigint;\n vaultCoreVersion: number;\n universalChallengersVersion: number;\n appVaultKeepersVersion: number;\n proverCircuitVersion: number;\n offchainParamsVersion: number;\n depositorPayoutBtcAddress: Hex;\n depositorWotsPkHash: Hex;\n hashlock: Hex;\n htlcVout: number;\n unsignedPrePeginTx: Hex;\n maxAcceptableCommissionBps: number;\n}\n\nfunction mapRegistrationRecord(\n args: PegInSubmittedArgs,\n blockNumber: bigint,\n): PeginRegistrationRecord {\n // A plain decode of every registration log in the block, strangers'\n // included: nothing here parses a transaction or bound-checks a script, so\n // one malformed registration elsewhere in the block cannot fail the\n // caller's read. The strict per-record checks live in\n // registration-records.ts. A duplicate vault id is not covered: a vault\n // registers once, so two logs for one id are an inconsistent node and fail\n // the read closed (see the caller).\n return {\n vaultId: args.vaultId.toLowerCase() as Hex,\n depositor: args.depositor,\n vaultProvider: args.vaultProvider,\n amount: args.amount,\n vaultCoreVersion: args.vaultCoreVersion,\n universalChallengersVersion: args.universalChallengersVersion,\n appVaultKeepersVersion: args.appVaultKeepersVersion,\n proverCircuitVersion: args.proverCircuitVersion,\n offchainParamsVersion: args.offchainParamsVersion,\n peginTxHash: args.peginTxHash.toLowerCase() as Hex,\n depositorPayoutScriptPubKey:\n args.depositorPayoutBtcAddress.toLowerCase() as Hex,\n unsignedPrePeginTx: args.unsignedPrePeginTx,\n maxAcceptableCommissionBps: args.maxAcceptableCommissionBps,\n blockNumber,\n };\n}\n\nfunction assertEpochInRange(\n value: bigint,\n field: string,\n vaultId: Hex,\n): bigint {\n if (value < 0n || value >= UINT64_EXCLUSIVE_UPPER_BOUND) {\n throw new Error(\n `getBtcVaultProtocolInfo returned ${field}=${value} for vault ${vaultId}, ` +\n `outside the uint64 range — the registry may predate RFC-006`,\n );\n }\n return value;\n}\n\n/** Matched by substring (\"not found on-chain\") in the vault app's `isVaultRecordEmptyError`. */\nconst VAULT_RECORD_NOT_FOUND_MESSAGE =\n \"not found on-chain or has no pegin transaction\";\n\nfunction assertVaultRecordPresent(\n record: { depositorSignedPeginTx: Hex },\n vaultId: Hex,\n): void {\n if (\n !record.depositorSignedPeginTx ||\n record.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(`Vault ${vaultId} ${VAULT_RECORD_NOT_FOUND_MESSAGE}`);\n }\n}\n\nfunction mapKeyEpochs(result: RawVaultKeyEpochsInfo, vaultId: Hex): KeyEpochs {\n // An upgraded registry decodes an unknown or not-yet-indexed vault to a zero\n // struct whose epochs read as {0,0,0} (genesis keys), so check the record\n // exists first.\n assertVaultRecordPresent(result, vaultId);\n return {\n vpKeyEpoch: assertEpochInRange(result.vpKeyEpoch, \"vpKeyEpoch\", vaultId),\n appKeeperKeyEpoch: assertEpochInRange(\n result.appKeeperKeyEpoch,\n \"appKeeperKeyEpoch\",\n vaultId,\n ),\n ucKeyEpoch: assertEpochInRange(result.ucKeyEpoch, \"ucKeyEpoch\", vaultId),\n };\n}\n\n/**\n * Concrete vault registry reader using viem.\n *\n * Usage:\n * ```ts\n * const reader = new ViemVaultRegistryReader(publicClient, registryAddress);\n * const data = await reader.getVaultData(vaultId);\n * ```\n */\nexport class ViemVaultRegistryReader implements VaultRegistryReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n /**\n * Read the VP's **genesis** (registration) x-only BTC pubkey — the key bonded\n * at version 0, which never moves when the operator rotates.\n *\n * Resolved as \"the operation key at epoch 0\" rather than through the\n * dedicated `getVaultProviderBTCKey` getter, which\n * https://github.com/babylonlabs-io/vault-contracts-aave-v4/pull/539 removes.\n * Epoch 0 predates any rotation — appended versions are stamped at epoch 1 or\n * later — so it resolves to the registration key, and the contracts team has\n * confirmed that is a property we can rely on rather than an implementation\n * detail. The devnet comparison behind that claim — both getters returning the\n * identical key for a provider that *has* rotated, while\n * `getCurrentOperationBtcKey` differed — is recorded in\n * https://github.com/babylonlabs-io/babylon-toolkit/issues/2188.\n *\n * This makes the read RFC-006-only, where the removed getter also existed on a\n * legacy registry. That costs nothing: every caller of this method already\n * resolves participant keys through `OperationKeyReader`, so all of them\n * require an RFC-006 registry regardless.\n *\n * Validates length, hex form, and secp256k1 curve membership before minting\n * the brand. Returns 64-char lowercase hex without the `0x` prefix.\n */\n async getVaultProviderGenesisBtcPubKey(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey> {\n return this.getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress,\n VP_GENESIS_KEY_EPOCH,\n blockNumber,\n );\n }\n\n /**\n * Read the VP operation key selected by `epoch`.\n *\n * This is public rather than hidden inside `OperationKeyReader` because\n * subject-specific VP authentication needs exactly one participant: the\n * gRPC bootstrap is signed by the key frozen into the vault, while the\n * JSON-RPC bootstrap is signed by the provider's live key.\n */\n async getVaultProviderOperationBtcKeyAtEpoch(\n vpAddress: Address,\n epoch: bigint,\n blockNumber?: bigint,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getOperationBtcKeyAtEpoch\",\n args: [vpAddress, epoch],\n blockNumber,\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getOperationBtcKeyAtEpoch (vp=${vpAddress}, epoch=${epoch})`,\n );\n }\n\n /**\n * Read the application entry point a vault provider is registered for.\n *\n * This is the registry's own `vaultProviders[vp].applicationEntryPoint`, and\n * it is the value the peg-in submit path resolves internally — it selects\n * which application's vault-keeper roster, roster version and keeper key\n * epoch a deposit is bonded to. The dApp separately carries an entry point\n * from its own configuration; the two agree today, but they are different\n * sources of truth, so the build path reads this one and asserts the\n * configured value matches it rather than trusting either alone.\n */\n async getVaultProviderApplication(\n vpAddress: Address,\n blockNumber?: bigint,\n ): Promise<Address> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderApplication\",\n args: [vpAddress],\n blockNumber,\n })) as Address;\n }\n\n /**\n * Read a vault provider's *current* RFC-006 operation BTC key.\n *\n * Falls back on-chain to the registration key when the provider has never\n * rotated, so this returns the same value as\n * `getVaultProviderGenesisBtcPubKey` until the first rotation.\n *\n * This is the key the VP's server uses for JSON-RPC-subject authentication.\n * The gRPC-subject bootstrap is instead bound to the existing vault's frozen\n * epoch and resolves through `getVaultProviderOperationBtcKeyAtEpoch`.\n */\n async getCurrentVaultProviderOperationBtcKey(\n vpAddress: Address,\n ): Promise<OnChainBtcPubkey> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getCurrentOperationBtcKey\",\n args: [vpAddress],\n })) as Hex;\n return assertOnChainBtcPubkey(\n result,\n `getCurrentOperationBtcKey (vp=${vpAddress})`,\n );\n }\n\n /**\n * Read a vault's frozen RFC-006 operation-key epochs.\n *\n * Reads `getBtcVaultProtocolInfo` through the **extended** ABI, which is only\n * valid against an RFC-006 registry: against one whose `BTCVaultProtocolInfo`\n * struct is not extended this call does not fail for a populated vault, it\n * silently returns three words of tail data as epochs. Nothing here can detect\n * that, so the guarantee is a deployment one — every network this ships to has\n * the RFC-006 getters, and mainnet is a fresh RFC-006 deploy.\n *\n * A registry missing the operation-key getters entirely is the *safer* of the\n * two cases: `resolveParticipantKeysAtEpochs` reverts downstream and these\n * epochs never reach key resolution. See {@link UINT64_EXCLUSIVE_UPPER_BOUND}\n * for which state the range check actually guards, and\n * `BTCVaultRegistryKeyEpochs.abi.ts` for the decode hazard.\n */\n async getVaultKeyEpochs(vaultId: Hex): Promise<KeyEpochs> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultKeyEpochsInfo;\n\n return mapKeyEpochs(result, vaultId);\n }\n\n async getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) =>\n mapKeyEpochs(info as RawVaultKeyEpochsInfo, vaultIds[i]),\n );\n }\n\n async getVaultBasicInfo(vaultId: Hex): Promise<VaultBasicInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as RawVaultBasicInfo;\n\n return mapVaultBasicInfo(result);\n }\n\n async getVaultProtocolInfo(vaultId: Hex): Promise<VaultProtocolInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultProtocolInfo;\n\n return mapVaultProtocolInfo(result);\n }\n\n async getProtocolInfoBatch(\n vaultIds: readonly Hex[],\n ): Promise<VaultProtocolInfo[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) => {\n const result = info as unknown as RawVaultProtocolInfo;\n // An empty record is not proof the vault is absent: a lagging RPC\n // node returns HTTP 200 with a zero struct, so no retry below this\n // layer can see it. Single-shot is only safe because the finality\n // gate (`waitForPeginRegistrationDepth`) runs first on the deposit\n // path — move this ahead of it and the read-after-write race returns.\n assertVaultRecordPresent(result, vaultIds[i]);\n return mapVaultProtocolInfo(result);\n });\n }\n\n /**\n * Read the protocol pegin fee (in wei) for a given vault provider.\n * Mirrors the `getPegInFee(address)` view on BTCVaultRegistry.\n */\n async getPegInFee(vaultProvider: Address): Promise<bigint> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n }\n\n /**\n * Read a vault provider's current commission in basis points from\n * BTCVaultRegistry. The contract enforces `commissionBps < 10000`, so the\n * legitimate range is `[0, 9999]`; anything outside indicates a wrong\n * contract address or ABI drift and is surfaced as an error rather than\n * trusted.\n */\n async getVaultProviderCommission(vaultProvider: Address): Promise<number> {\n // viem infers `number` from the `uint16` return in the `as const` ABI.\n const bps = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderCommission\",\n args: [vaultProvider],\n });\n\n if (!Number.isInteger(bps) || bps < 0 || bps > MAX_VP_COMMISSION_BPS) {\n throw new Error(\n `getVaultProviderCommission returned ${bps} bps for ${vaultProvider}, ` +\n `outside the protocol range [0, ${MAX_VP_COMMISSION_BPS}]`,\n );\n }\n\n return bps;\n }\n\n async getVaultData(vaultId: Hex): Promise<VaultData> {\n // One round-trip for both structs (hard-fail): they feed signing/refund/\n // broadcast rebinds, so reading them in a single multicall also pins both\n // to the same block — no basic/protocol skew across two `eth_call`s.\n const [basicRaw, protocolRaw] = await this.publicClient.multicall({\n contracts: [\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n },\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n },\n ],\n allowFailure: false,\n });\n\n const basic = mapVaultBasicInfo(basicRaw);\n const protocol = mapVaultProtocolInfo(protocolRaw);\n\n assertVaultRecordPresent(protocol, vaultId);\n\n return { basic, protocol };\n }\n\n /** @inheritdoc */\n async getRegistrationRecordsAtBlock(\n createdAt: bigint,\n ): Promise<PeginRegistrationRecord[]> {\n // Deliberately no `vaultId` topic filter: the block holds the target's\n // registration, so only an unfiltered answer can tell a node that served\n // nothing (empty) from one that lacks the target (findRegistrationRecord),\n // and one query serves every vault a caller reads from the block. strict:\n // a log whose data does not decode against the ABI is dropped (viem\n // parseEventLogs) instead of surfacing as `args: {}`.\n const logs = await this.publicClient.getLogs({\n address: this.contractAddress,\n event: PEGIN_SUBMITTED_EVENT,\n fromBlock: createdAt,\n toBlock: createdAt,\n strict: true,\n });\n if (logs.length === 0) {\n throw new RegistrationLogsUnavailableError(createdAt);\n }\n\n const records = new Map<string, PeginRegistrationRecord>();\n for (const log of logs) {\n const record = mapRegistrationRecord(log.args, log.blockNumber);\n // Lenient decoding covers a malformed log, not a duplicate: a vault\n // registers once, so two logs for any id mean the node is inconsistent\n // and every record from this block is suspect — fail closed by design.\n if (records.has(record.vaultId)) {\n throw new Error(\n `Expected one PegInSubmitted log for vault ${record.vaultId} at block ${createdAt}, ` +\n `found more than one`,\n );\n }\n records.set(record.vaultId, record);\n }\n return [...records.values()];\n }\n\n /**\n * Read the depositor's commission ceiling (`maxAcceptableCommissionBps`)\n * for vaults registered in the same block, from their `PegInSubmitted`\n * logs. Returned in `vaultIds` order.\n *\n * The contract bound-checks the ceiling and discards it (PeginLogic.sol,\n * `VaultProviderCommissionExceeded`), so the registration log is its only\n * on-chain source. Vault ids are matched case-insensitively.\n *\n * @throws As {@link getRegistrationRecordsAtBlock}, plus the same typed\n * transient error when a vault has no registration log in its own\n * `createdAt` block.\n */\n async getMaxAcceptableCommissionBpsBatch(\n vaultIds: readonly Hex[],\n createdAt: bigint,\n ): Promise<number[]> {\n if (vaultIds.length === 0) return [];\n\n const records = await this.getRegistrationRecordsAtBlock(createdAt);\n return vaultIds.map(\n (vaultId) =>\n findRegistrationRecord(records, vaultId, createdAt)\n .maxAcceptableCommissionBps,\n );\n }\n\n /** @inheritdoc */\n async getVaultClaimableBy(\n vaultId: Hex,\n claimerPk: Hex,\n createdAt: bigint,\n ): Promise<VaultClaimableByEvent> {\n const claimer = assertOnChainBtcPubkey(\n claimerPk,\n `getVaultClaimableBy claimer (vault=${vaultId})`,\n );\n const claimerTopic = `0x${claimer}` as Hex;\n // viem re-filters the decoded logs client-side against `args`, comparing a\n // bytes32 with `===` against lower-case hex (parseEventLogs.ts:140,172-188).\n const vaultIdTopic = vaultId.toLowerCase() as Hex;\n // Finalized, not latest: the block found here is what the prover proves\n // against, and an unfinalized redeem can reorg away (btc-vault binds the\n // same scan to its finality level, eth-client client.rs:5989-6040).\n const { number: finalized } = await this.publicClient.getBlock({\n blockTag: \"finalized\",\n });\n if (finalized < createdAt) {\n throw new Error(\n `Finalized block ${finalized} is below vault ${vaultId}'s registration block ${createdAt}; ` +\n `the registration is not finalized yet, or the node is behind it`,\n );\n }\n\n // Newest first: the redeem usually trails the tip by far less than it\n // trails the registration. The contract emits every VaultClaimableBy of a\n // vault in one transaction, so the first non-empty chunk is the answer.\n let toBlock = finalized;\n for (;;) {\n const fromBlock = maxBigint(\n createdAt,\n toBlock - VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS + 1n,\n );\n const logs = await this.publicClient.getLogs({\n address: this.contractAddress,\n event: VAULT_CLAIMABLE_BY_EVENT,\n args: { vaultId: vaultIdTopic, claimerPK: claimerTopic },\n fromBlock,\n toBlock,\n strict: true,\n });\n // A redeem emits every VaultClaimableBy of a vault in ONE transaction\n // (RedeemLogic.sol), and `redeemForDepositor` emits the VP's key and\n // then the depositor's — so when those two keys are equal this filter\n // legitimately matches twice. Identical authorizations from one\n // transaction are the same fact; logs spanning transactions are not.\n if (logs.length > 1) {\n const transactions = new Set(logs.map((log) => log.transactionHash));\n if (transactions.size > 1) {\n throw new Error(\n `Found ${logs.length} VaultClaimableBy logs for vault ${vaultId} and claimer ` +\n `${claimerTopic} across ${transactions.size} transactions in blocks ` +\n `${fromBlock}..${toBlock}; a vault is redeemed once, so the node's answer ` +\n `is inconsistent`,\n );\n }\n }\n if (logs.length >= 1) {\n const log = logs[0];\n return {\n blockNumber: log.blockNumber,\n claimerPk: assertOnChainBtcPubkey(\n log.args.claimerPK,\n `VaultClaimableBy.claimerPK (vault=${vaultId})`,\n ),\n peginTxHash: log.args.peginTxHash,\n vaultCoreVersion: log.args.vaultCoreVersion,\n proverCircuitVersion: log.args.proverCircuitVersion,\n offchainParamsVersion: log.args.offchainParamsVersion,\n universalChallengersVersion: log.args.universalChallengersVersion,\n appVaultKeepersVersion: log.args.appVaultKeepersVersion,\n };\n }\n if (fromBlock === createdAt) {\n throw new VaultClaimableByNotFoundError(\n vaultId,\n claimerTopic,\n createdAt,\n finalized,\n );\n }\n toBlock = fromBlock - 1n;\n }\n }\n}\n","import {\n encodeFunctionData,\n isAddressEqual,\n zeroAddress,\n type Address,\n type Chain,\n type Hex,\n type PublicClient,\n type WalletClient,\n} from \"viem\";\n\nimport { BTCVaultRegistryABI } from \"../../contracts/abis/BTCVaultRegistry.abi\";\nimport { handleContractError } from \"../../contracts/errors\";\nimport {\n capMaxAcceptableCommissionBps,\n COMMISSION_BPS_HEADROOM,\n} from \"../../deposit-terms/commissionCeiling\";\nimport { waitForTransactionReceiptSmartAware } from \"../../utils/eth\";\nimport { assertOnChainBtcPubkey } from \"./onChainBtcPubkey\";\nimport { assertPayoutScriptMatchesPopKey } from \"./payout-script\";\nimport { calculateBtcTxHash, derivePeginVaultId } from \"./pegin-transaction\";\nimport { ViemVaultRegistryReader } from \"./vault-registry-reader\";\n\n/** Referral code sent with peg-in registration. Zero means no referral. */\nexport const NO_REFERRAL_CODE = 0;\nconst UINT8_MAX = 255;\n// Match the prior vault-service timeout. A dropped transaction must not wait forever.\nconst RECEIPT_TIMEOUT_MS = 120_000;\n\nfunction ensureHex(value: string, label: string): Hex {\n const prefixed = value.startsWith(\"0x\")\n ? value\n : value.startsWith(\"0X\")\n ? `0x${value.slice(2)}`\n : `0x${value}`;\n if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(prefixed)) {\n throw new Error(`${label} must be non-empty, even-length hex`);\n }\n return prefixed as Hex;\n}\n\nfunction assertBytes32(value: Hex, label: string): void {\n if (!/^0x[0-9a-fA-F]{64}$/.test(value)) {\n throw new Error(`${label} must be a 32-byte hex value`);\n }\n}\n\n/** All-zero `bytes32` — the shape an unresolved fingerprint takes. */\nconst ZERO_BYTES32 =\n \"0x0000000000000000000000000000000000000000000000000000000000000000\";\n\n/**\n * The single validation point for `expectedFingerprint`, on both the singular\n * and batch paths.\n *\n * Zero is rejected separately from the shape check because it is a *well-formed*\n * `bytes32` that the registry can never accept — the live fingerprint is a\n * keccak256 over a domain-separated preimage — so it can only ever mean the\n * caller had no value and filled the slot. Catching it here turns a defaulted\n * field into a named error instead of an opaque on-chain revert with two\n * hashes and no hint.\n */\nfunction assertFingerprint(value: Hex): void {\n assertBytes32(value, \"expectedFingerprint\");\n if (value.toLowerCase() === ZERO_BYTES32) {\n throw new Error(\n \"expectedFingerprint must not be zero: the registry cannot resolve a \" +\n \"zero fingerprint, so this submission would always revert\",\n );\n }\n}\n\nfunction assertHtlcVout(value: number): void {\n if (!Number.isInteger(value) || value < 0 || value > UINT8_MAX) {\n throw new Error(`htlcVout must be a uint8, got ${value}`);\n }\n}\n\n/** A PoP prepared by a Bitcoin wallet, reusable by the ETH submit client. */\nexport interface PopSignature {\n btcPopSignature: Hex;\n depositorEthAddress: Address;\n /** x-only secp256k1 public key, 64 hex chars without `0x`. */\n depositorBtcPubkey: string;\n}\n\nexport interface ViemPeginRegistrationClientConfig {\n ethWallet: WalletClient;\n ethChain: Chain;\n publicClient: PublicClient;\n btcVaultRegistry: Address;\n receiptTimeoutMs?: number;\n /**\n * Refuse to register without a `quotedCommissionBps`. Set it to `true` when\n * the depositor approved deposit terms on a device: approval froze the\n * commission ceiling from the quote, so the chain-current fallback could\n * admit a commission the device would later refuse to pay out.\n *\n * Required, with no default: an omitted flag would silently pick the unsafe\n * direction for the integrator least able to probe the wallet capability.\n */\n requireQuotedCommissionBps: boolean;\n}\n\nexport interface RegisterPeginOnChainParams {\n unsignedPrePeginTx: string;\n depositorSignedPeginTx: string;\n vaultProvider: Address;\n hashlock: Hex;\n depositorWotsPkHash: Hex;\n popSignature: PopSignature;\n /** Raw x-only, compressed, or uncompressed BTC pubkey from the PoP wallet. */\n depositorBtcPubkeyRaw: string;\n htlcVout: number;\n /**\n * Bitcoin output script bytes, not an address. The client verifies that the\n * script pays the proof-of-possession key before it submits the transaction.\n */\n depositorPayoutScriptPubKey: string;\n quotedCommissionBps?: number;\n /**\n * `keccak256(abi.encode(...))` over the protocol state the Pre-PegIn was\n * built against — see the SDK's `pegin-fingerprint` module.\n *\n * The registry recomputes it live at inclusion and reverts with\n * `PeginFingerprintChanged` on any difference, so it must be computed from\n * the same block-pinned snapshot that shaped the Bitcoin scripts. Required,\n * with no default: a fingerprint the caller did not resolve is not a\n * fingerprint, and the registry has no way to tell the two apart.\n */\n expectedFingerprint: Hex;\n}\n\nexport interface PeginRegistrationResult {\n ethTxHash: Hex;\n vaultId: Hex;\n peginTxHash: Hex;\n}\n\nexport interface BatchPeginRegistrationItem {\n depositorSignedPeginTx: string;\n hashlock: Hex;\n htlcVout: number;\n /**\n * Bitcoin output script bytes, not an address. The client verifies that the\n * script pays the proof-of-possession key before it submits the transaction.\n */\n depositorPayoutScriptPubKey: string;\n depositorWotsPkHash: Hex;\n}\n\nexport interface RegisterPeginBatchOnChainParams {\n vaultProvider: Address;\n unsignedPrePeginTx: string;\n requests: BatchPeginRegistrationItem[];\n popSignature: PopSignature;\n /** Raw x-only, compressed, or uncompressed BTC pubkey from the PoP wallet. */\n depositorBtcPubkeyRaw: string;\n quotedCommissionBps?: number;\n /**\n * See {@link RegisterPeginOnChainParams.expectedFingerprint}. One value for\n * the whole batch: the fingerprint takes no per-request input and a batch\n * fixes one vault provider, so every entry would resolve the same value.\n */\n expectedFingerprint: Hex;\n}\n\nexport interface BatchPeginRegistrationResultItem {\n vaultId: Hex;\n peginTxHash: Hex;\n}\n\nexport interface PeginBatchRegistrationResult {\n ethTxHash: Hex;\n vaults: BatchPeginRegistrationResultItem[];\n}\n\n/**\n * Ethereum-only client for the on-chain half of peg-in registration.\n *\n * It consumes Bitcoin artifacts that were prepared earlier, but owns no BTC\n * wallet and imports neither Bitcoin libraries nor the Rust/WASM package.\n */\nexport class ViemPeginRegistrationClient {\n constructor(private readonly config: ViemPeginRegistrationClientConfig) {}\n\n async registerPeginOnChain(\n params: RegisterPeginOnChainParams,\n ): Promise<PeginRegistrationResult> {\n const request = {\n ...params,\n popSignature: { ...params.popSignature },\n };\n this.assertQuotedCommissionPresentWhenRequired(request.quotedCommissionBps);\n // Second, matching the batch path, so the two public entry points validate\n // in the same order and neither can drift behind a chain call.\n assertFingerprint(request.expectedFingerprint);\n const depositor = this.assertPopMatchesEthAccount(request.popSignature);\n const depositorBtcPubkey = this.normalizeBtcPubkey(request.popSignature);\n const btcPopSignature = ensureHex(\n request.popSignature.btcPopSignature,\n \"btcPopSignature\",\n );\n const normalized = this.normalizeRequest(\n request,\n depositor,\n depositorBtcPubkey,\n );\n\n await this.assertVaultDoesNotExist(\n normalized.vaultId,\n normalized.peginTxHash,\n );\n const peginFee = await this.readPeginFee(request.vaultProvider);\n const maxCommission = await this.resolveMaxAcceptableCommissionBps(\n request.vaultProvider,\n request.quotedCommissionBps,\n );\n const callData = encodeFunctionData({\n abi: BTCVaultRegistryABI,\n functionName: \"submitPeginRequest\",\n args: [\n depositor,\n depositorBtcPubkey,\n btcPopSignature,\n normalized.unsignedPrePeginTx,\n normalized.depositorSignedPeginTx,\n request.vaultProvider,\n maxCommission,\n request.hashlock,\n request.htlcVout,\n normalized.payoutScript,\n request.depositorWotsPkHash,\n // Appended last on the singular overload; the batch takes it at\n // position 4 instead. Order is the selector, so do not \"tidy\" either.\n request.expectedFingerprint,\n ],\n });\n\n const ethTxHash = await this.sendAndWait(\n callData,\n peginFee,\n false,\n depositor,\n );\n return {\n ethTxHash,\n vaultId: normalized.vaultId,\n peginTxHash: normalized.peginTxHash,\n };\n }\n\n async registerPeginBatchOnChain(\n params: RegisterPeginBatchOnChainParams,\n ): Promise<PeginBatchRegistrationResult> {\n const batch = {\n ...params,\n popSignature: { ...params.popSignature },\n requests: params.requests.map((request) => ({ ...request })),\n };\n if (batch.requests.length === 0) {\n throw new Error(\"Batch pegin requires at least one request\");\n }\n this.assertQuotedCommissionPresentWhenRequired(batch.quotedCommissionBps);\n assertFingerprint(batch.expectedFingerprint);\n const depositor = this.assertPopMatchesEthAccount(batch.popSignature);\n const unsignedPrePeginTx = ensureHex(\n batch.unsignedPrePeginTx,\n \"unsignedPrePeginTx\",\n );\n const depositorBtcPubkey = this.normalizeBtcPubkey(batch.popSignature);\n const btcPopSignature = ensureHex(\n batch.popSignature.btcPopSignature,\n \"btcPopSignature\",\n );\n\n const vaults: BatchPeginRegistrationResultItem[] = [];\n const requests = [];\n const seenVaultIds = new Set<string>();\n for (const request of batch.requests) {\n const normalized = this.normalizeRequest(\n {\n ...request,\n unsignedPrePeginTx: batch.unsignedPrePeginTx,\n vaultProvider: batch.vaultProvider,\n depositorBtcPubkeyRaw: batch.depositorBtcPubkeyRaw,\n },\n depositor,\n depositorBtcPubkey,\n );\n if (seenVaultIds.has(normalized.vaultId)) {\n throw new Error(`Duplicate vault in batch: ${normalized.vaultId}`);\n }\n seenVaultIds.add(normalized.vaultId);\n vaults.push({\n vaultId: normalized.vaultId,\n peginTxHash: normalized.peginTxHash,\n });\n requests.push({\n depositorBtcPubKey: depositorBtcPubkey,\n btcPopSignature,\n unsignedPrePeginTx,\n depositorSignedPeginTx: normalized.depositorSignedPeginTx,\n hashlock: request.hashlock,\n htlcVout: request.htlcVout,\n referralCode: NO_REFERRAL_CODE,\n depositorPayoutBtcAddress: normalized.payoutScript,\n depositorWotsPkHash: request.depositorWotsPkHash,\n });\n }\n for (const vault of vaults) {\n await this.assertVaultDoesNotExist(vault.vaultId, vault.peginTxHash);\n }\n\n const peginFee = await this.readPeginFee(batch.vaultProvider);\n const maxCommission = await this.resolveMaxAcceptableCommissionBps(\n batch.vaultProvider,\n batch.quotedCommissionBps,\n );\n const callData = encodeFunctionData({\n abi: BTCVaultRegistryABI,\n functionName: \"submitPeginRequestBatch\",\n // `expectedFingerprint` sits BEFORE `requests`, not appended. Reordering\n // these five changes the selector and the call stops existing.\n args: [\n depositor,\n batch.vaultProvider,\n maxCommission,\n batch.expectedFingerprint,\n requests,\n ],\n });\n const ethTxHash = await this.sendAndWait(\n callData,\n peginFee * BigInt(batch.requests.length),\n true,\n depositor,\n );\n return { ethTxHash, vaults };\n }\n\n private assertQuotedCommissionPresentWhenRequired(\n quotedCommissionBps?: number,\n ): void {\n if (\n quotedCommissionBps === undefined &&\n this.config.requireQuotedCommissionBps\n ) {\n throw new Error(\n \"quotedCommissionBps is required when the wallet approved deposit \" +\n \"terms: the registration ceiling must anchor to the approved quote.\",\n );\n }\n }\n\n private assertPopMatchesEthAccount(pop: PopSignature): Address {\n return this.assertEthAccount(pop.depositorEthAddress);\n }\n\n private assertEthAccount(expectedDepositor: Address): Address {\n const account = this.config.ethWallet.account;\n if (!account) throw new Error(\"Ethereum wallet account not found\");\n if (!isAddressEqual(expectedDepositor, account.address)) {\n throw new Error(\n `Proof of possession was signed for ${expectedDepositor} ` +\n `but the Ethereum wallet is currently connected to ${account.address}. ` +\n `Reconnect the original account or sign a new proof of possession.`,\n );\n }\n return account.address;\n }\n\n private normalizeBtcPubkey(pop: PopSignature): Hex {\n return `0x${assertOnChainBtcPubkey(\n ensureHex(pop.depositorBtcPubkey, \"Proof of possession BTC pubkey\"),\n \"Proof of possession BTC pubkey\",\n )}`;\n }\n\n // `expectedFingerprint` is omitted rather than accepted and ignored: nothing\n // here normalizes it, and requiring it would force the batch loop to thread a\n // value through a per-request helper that has no use for it. It is validated\n // once per call, at the top of each public method.\n private normalizeRequest(\n params: Omit<\n RegisterPeginOnChainParams,\n \"popSignature\" | \"expectedFingerprint\"\n >,\n depositor: Address,\n depositorBtcPubkey: Hex,\n ) {\n assertBytes32(params.hashlock, \"hashlock\");\n assertBytes32(params.depositorWotsPkHash, \"depositorWotsPkHash\");\n assertHtlcVout(params.htlcVout);\n const unsignedPrePeginTx = ensureHex(\n params.unsignedPrePeginTx,\n \"unsignedPrePeginTx\",\n );\n const depositorSignedPeginTx = ensureHex(\n params.depositorSignedPeginTx,\n \"depositorSignedPeginTx\",\n );\n const peginTxHash = calculateBtcTxHash(depositorSignedPeginTx);\n return {\n unsignedPrePeginTx,\n depositorSignedPeginTx,\n payoutScript: assertPayoutScriptMatchesPopKey(\n params.depositorPayoutScriptPubKey,\n depositorBtcPubkey,\n params.depositorBtcPubkeyRaw,\n ),\n peginTxHash,\n vaultId: ensureHex(derivePeginVaultId(peginTxHash, depositor), \"vaultId\"),\n };\n }\n\n private async assertVaultDoesNotExist(\n vaultId: Hex,\n peginTxHash: Hex,\n ): Promise<void> {\n const result = (await this.config.publicClient.readContract({\n address: this.config.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as { depositor: Address };\n if (result.depositor !== zeroAddress) {\n throw new Error(\n `Vault already exists (ID: ${vaultId}, peginTxHash: ${peginTxHash}). ` +\n `Vault IDs are derived from the pegin transaction hash and depositor address. ` +\n `To create a new vault, use different UTXOs or a different amount to generate a unique transaction.`,\n );\n }\n }\n\n private async readPeginFee(vaultProvider: Address): Promise<bigint> {\n try {\n return (await this.config.publicClient.readContract({\n address: this.config.btcVaultRegistry,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n } catch (error) {\n throw new Error(\n \"Failed to query pegin fee from the contract. \" +\n \"Please check your network connection and contract address.\",\n { cause: error },\n );\n }\n }\n\n private async resolveMaxAcceptableCommissionBps(\n vaultProvider: Address,\n quotedCommissionBps?: number,\n ): Promise<number> {\n let currentBps: number;\n try {\n currentBps = await new ViemVaultRegistryReader(\n this.config.publicClient,\n this.config.btcVaultRegistry,\n ).getVaultProviderCommission(vaultProvider);\n } catch (error) {\n throw new Error(\n \"Failed to query vault provider commission from the contract. \" +\n \"Please check your network connection and contract address.\",\n { cause: error },\n );\n }\n if (quotedCommissionBps !== undefined) {\n if (currentBps > quotedCommissionBps + COMMISSION_BPS_HEADROOM) {\n throw new Error(\n `Vault provider commission changed since quote: quoted ${quotedCommissionBps} bps, ` +\n `chain currently reports ${currentBps} bps (allowed drift ${COMMISSION_BPS_HEADROOM} bps). ` +\n `Please refresh and try again.`,\n );\n }\n return capMaxAcceptableCommissionBps(quotedCommissionBps);\n }\n return capMaxAcceptableCommissionBps(currentBps);\n }\n\n private async sendAndWait(\n data: Hex,\n value: bigint,\n batch: boolean,\n depositor: Address,\n ): Promise<Hex> {\n let account = this.assertEthAccount(depositor);\n let gas: bigint;\n try {\n gas = await this.config.publicClient.estimateGas({\n to: this.config.btcVaultRegistry,\n data,\n value,\n account,\n });\n } catch (error) {\n handleContractError(error);\n }\n\n account = this.assertEthAccount(depositor);\n let submittedHash: Hex;\n try {\n submittedHash = await this.config.ethWallet.sendTransaction({\n to: this.config.btcVaultRegistry,\n data,\n value,\n gas,\n account,\n chain: this.config.ethChain,\n });\n } catch (error) {\n handleContractError(error);\n }\n const receipt = await waitForTransactionReceiptSmartAware({\n publicClient: this.config.publicClient,\n walletAddress: depositor,\n hash: submittedHash,\n timeout: this.config.receiptTimeoutMs ?? RECEIPT_TIMEOUT_MS,\n });\n if (receipt.status === \"reverted\") {\n handleContractError(\n new Error(\n `${batch ? \"Batch transaction\" : \"Transaction\"} reverted. ` +\n `Hash: ${receipt.transactionHash}. Check a block explorer for details.`,\n ),\n );\n }\n return receipt.transactionHash;\n }\n}\n"],"names":["COMMISSION_BPS_HEADROOM","MAX_ACCEPTABLE_COMMISSION_BPS_CAP","capMaxAcceptableCommissionBps","bps","MAX_VP_COMMISSION_BPS_EXCLUSIVE","MAX_VP_COMMISSION_BPS","mapVaultBasicInfo","result","mapVaultProtocolInfo","offchainParamsVersion","assertValidOffchainParamsVersion","UINT64_EXCLUSIVE_UPPER_BOUND","VP_GENESIS_KEY_EPOCH","PEGIN_SUBMITTED_EVENT","getAbiItem","BTCVaultRegistryABI","VAULT_CLAIMABLE_BY_EVENT","VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS","maxBigint","a","b","mapRegistrationRecord","args","blockNumber","assertEpochInRange","value","field","vaultId","VAULT_RECORD_NOT_FOUND_MESSAGE","assertVaultRecordPresent","record","mapKeyEpochs","ViemVaultRegistryReader","publicClient","contractAddress","vpAddress","epoch","assertOnChainBtcPubkey","BTCVaultRegistryKeyEpochsABI","vaultIds","info","vaultProvider","basicRaw","protocolRaw","basic","protocol","createdAt","logs","RegistrationLogsUnavailableError","records","log","findRegistrationRecord","claimerPk","claimerTopic","vaultIdTopic","finalized","toBlock","fromBlock","transactions","VaultClaimableByNotFoundError","NO_REFERRAL_CODE","UINT8_MAX","RECEIPT_TIMEOUT_MS","ensureHex","label","prefixed","assertBytes32","ZERO_BYTES32","assertFingerprint","assertHtlcVout","ViemPeginRegistrationClient","config","params","request","depositor","depositorBtcPubkey","btcPopSignature","normalized","peginFee","maxCommission","callData","encodeFunctionData","batch","unsignedPrePeginTx","vaults","requests","seenVaultIds","vault","quotedCommissionBps","pop","expectedDepositor","account","isAddressEqual","depositorSignedPeginTx","peginTxHash","calculateBtcTxHash","assertPayoutScriptMatchesPopKey","derivePeginVaultId","zeroAddress","error","currentBps","data","gas","handleContractError","submittedHash","receipt","waitForTransactionReceiptSmartAware"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const r=require("./ProtocolParams.abi-DWfIh6VH.cjs"),s=require("./registration-records-CKc0OVuK.cjs"),p=65535,h=[{type:"function",name:"getTBVProtocolParams",inputs:[],outputs:[{name:"",type:"tuple",internalType:"struct IProtocolParams.TBVProtocolParams",components:[{name:"minimumPegInAmount",type:"uint64",internalType:"uint64"},{name:"maxPegInAmount",type:"uint64",internalType:"uint64"},{name:"pegInAckTimeout",type:"uint64",internalType:"uint64"},{name:"pegInActivationTimeout",type:"uint64",internalType:"uint64"},{name:"maxHtlcOutputCount",type:"uint8",internalType:"uint8"},{name:"expiredPegInGraceBlocks",type:"uint64",internalType:"uint64"}]}],stateMutability:"view"}];function f(t){if(t.status==="failure")throw t.error;return t.result}function u(t){return{timelockAssert:t.timelockAssert,timelockChallengeAssert:t.timelockChallengeAssert,securityCouncilKeys:[...t.securityCouncilKeys],councilQuorum:t.councilQuorum,feeRate:t.feeRate,babeTotalInstances:t.babeTotalInstances,babeInstancesToFinalize:t.babeInstancesToFinalize,maxVpCommissionBps:t.maxVpCommissionBps,tRefund:t.tRefund,tStale:t.tStale,minPeginFeeRate:t.minPeginFeeRate,proverCircuitVersion:t.proverCircuitVersion,minPrepeginDepth:t.minPrepeginDepth}}function d(t,e){return{minimumPegInAmount:t.minimumPegInAmount,maxPegInAmount:t.maxPegInAmount,pegInAckTimeout:t.pegInAckTimeout,pegInActivationTimeout:t.pegInActivationTimeout,maxHtlcOutputCount:t.maxHtlcOutputCount,expiredPegInGraceBlocks:t.expiredPegInGraceBlocks,maxFundingInputCount:e}}function I(t,e){if(t.status==="success"){const a=t.result;return d(a,a.maxFundingInputCount)}if(e.status==="success")return d(e.result,null);throw t.error}function g(t){if(t>BigInt(p))throw new Error(`timelockAssert value ${t} exceeds uint16 max (${p})`);return Number(t)}class b{constructor(e,a){this.publicClient=e,this.contractAddress=a}async getTBVProtocolParams(){const[e,a]=await this.publicClient.multicall({contracts:this.tbvParamsCalls(),allowFailure:!0}),n=I(e,a);return s.validateTBVProtocolParams(n),n}tbvParamsCalls(){return[{address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"getTBVProtocolParams"},{address:this.contractAddress,abi:h,functionName:"getTBVProtocolParams"}]}async getLatestOffchainParams(){const e=await this.publicClient.readContract({address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"getLatestOffchainParams"}),a=u(e);return s.validateOffchainParams(a),a}async getOffchainParamsByVersion(e){const a=await this.publicClient.readContract({address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"getOffchainParamsByVersion",args:[e]}),n=u(a);return s.validateOffchainParams(n),n}async getLatestOffchainParamsVersion(){const e=await this.publicClient.readContract({address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"latestOffchainParamsVersion"}),a=Number(e);return s.assertValidOffchainParamsVersion(a),a}async getTimelockPeginByVersion(e){const a=await this.getOffchainParamsByVersion(e);return g(a.timelockAssert)}async getPeginActivationDelay(){const e=await this.publicClient.readContract({address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"peginActivationDelay"});if(typeof e!="bigint")throw new Error(`Invalid peginActivationDelay from contract: must be a bigint, got ${typeof e}`);return e}async getPegInConfiguration(e){const a=await this.publicClient.multicall({blockNumber:e,contracts:[...this.tbvParamsCalls(),{address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"getLatestOffchainParams"},{address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"latestOffchainParamsVersion"},{address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"activeVaultCoreVersion"}],allowFailure:!0}),n=I(a[0],a[1]),o=u(f(a[2])),l=Number(f(a[3])),c=Number(f(a[4])),i={minimumPegInAmount:n.minimumPegInAmount,maxPegInAmount:n.maxPegInAmount,pegInAckTimeout:n.pegInAckTimeout,pegInActivationTimeout:n.pegInActivationTimeout,maxHtlcOutputCount:n.maxHtlcOutputCount,expiredPegInGraceBlocks:n.expiredPegInGraceBlocks,maxFundingInputCount:n.maxFundingInputCount,timelockPegin:g(o.timelockAssert),timelockRefund:o.tRefund,maxVpCommissionBps:o.maxVpCommissionBps,offchainParams:o,offchainParamsVersion:l,activeVaultCoreVersion:c};return s.validatePegInConfiguration(i),i}async fetchAllOffchainParams(e){const a=await this.getLatestOffchainParamsVersion();if(a===0)return{byVersion:new Map,latestVersion:0};const n=Array.from({length:a},(i,m)=>m+1),o=n.map(i=>({address:this.contractAddress,abi:r.ProtocolParamsABI,functionName:"getOffchainParamsByVersion",args:[i]})),l=await this.publicClient.multicall({contracts:o,allowFailure:!1}),c=new Map;for(let i=0;i<n.length;i++){const m=u(l[i]);try{s.validateOffchainParams(m),c.set(n[i],m)}catch(P){e==null||e(n[i],P instanceof Error?P:new Error(String(P)))}}return{byVersion:c,latestVersion:a}}}var A=(t=>(t[t.PENDING=0]="PENDING",t[t.VERIFIED=1]="VERIFIED",t[t.ACTIVE=2]="ACTIVE",t[t.REDEEMED=3]="REDEEMED",t[t.EXPIRED=4]="EXPIRED",t))(A||{});exports.OnChainBtcVaultStatus=A;exports.ViemProtocolParamsReader=b;exports.deriveTimelockPegin=g;
2
- //# sourceMappingURL=types-BnZIbDHb.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-BnZIbDHb.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 maxVpCommissionBps: 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 maxVpCommissionBps: result.maxVpCommissionBps,\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 maxVpCommissionBps: offchainParams.maxVpCommissionBps,\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-8, 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 `PegInSubmitted` 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 * `PegInSubmitted` 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, or with none\n * for a vault asked for — the registry emits one on every submission, so\n * either can be a partial answer.\n * @throws when a vault has more than one registration log.\n */\n getMaxAcceptableCommissionBpsBatch(\n vaultIds: readonly Hex[],\n createdAt: bigint,\n ): Promise<number[]>;\n /**\n * Decode every `PegInSubmitted` 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, which a\n * block holding a registration cannot have.\n * @throws when a vault has more than one registration 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 maxVpCommissionBps: 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 maxVpCommissionBps: 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 /**\n * The member's *registration* (genesis) key as the roster lists it. Under\n * RFC-006 a member can rotate its operation key without changing the\n * roster, so this is not necessarily the key a Bitcoin script commits to:\n * resolve operation keys with {@link OperationKeyReader}.\n */\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 /**\n * Read the keeper roster at a membership version. Each entry's `btcPubKey`\n * is the keeper's registration key, not necessarily the key its scripts\n * use: for an existing vault resolve the roster at the vault's frozen\n * epochs (`readStampedParticipantKeys`); for a fresh deposit use\n * `validateOnChainParticipantKeys`.\n */\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 /**\n * Read the universal challenger roster at a membership version. Each\n * entry's `btcPubKey` is the challenger's registration key, not necessarily\n * the key its scripts use: for an existing vault resolve the roster at the\n * vault's frozen epochs (`readStampedParticipantKeys`); for a fresh deposit\n * use `validateOnChainParticipantKeys`.\n */\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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"}