@babylonlabs-io/ts-sdk 3.2.1 → 3.3.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 (63) hide show
  1. package/dist/{PeginManager-sizm3dlw.js → PeginManager-BJnUgW8C.js} +3 -3
  2. package/dist/{PeginManager-sizm3dlw.js.map → PeginManager-BJnUgW8C.js.map} +1 -1
  3. package/dist/{PeginManager-BCRtUqyX.cjs → PeginManager-Co43rW_x.cjs} +2 -2
  4. package/dist/{PeginManager-BCRtUqyX.cjs.map → PeginManager-Co43rW_x.cjs.map} +1 -1
  5. package/dist/ProtocolParams.abi-BgEZaQ2I.cjs +2 -0
  6. package/dist/ProtocolParams.abi-BgEZaQ2I.cjs.map +1 -0
  7. package/dist/{ProtocolParams.abi-CKOVqFJP.js → ProtocolParams.abi-Cv77fsUe.js} +15 -9
  8. package/dist/ProtocolParams.abi-Cv77fsUe.js.map +1 -0
  9. package/dist/{buildAndBroadcastReclaim-rQyAiAUS.js → buildAndBroadcastReclaim-CQANDXVJ.js} +3 -3
  10. package/dist/{buildAndBroadcastReclaim-rQyAiAUS.js.map → buildAndBroadcastReclaim-CQANDXVJ.js.map} +1 -1
  11. package/dist/{buildAndBroadcastReclaim-CE77jzTp.cjs → buildAndBroadcastReclaim-DPk36Uhp.cjs} +2 -2
  12. package/dist/{buildAndBroadcastReclaim-CE77jzTp.cjs.map → buildAndBroadcastReclaim-DPk36Uhp.cjs.map} +1 -1
  13. package/dist/index.cjs +1 -1
  14. package/dist/index.js +8 -8
  15. package/dist/{pegin-registration-client-Bmkh1OZ9.cjs → pegin-registration-client-CdRyXP3j.cjs} +2 -2
  16. package/dist/{pegin-registration-client-Bmkh1OZ9.cjs.map → pegin-registration-client-CdRyXP3j.cjs.map} +1 -1
  17. package/dist/{pegin-registration-client-8tzSRDaq.js → pegin-registration-client-Cvjk4ILq.js} +2 -2
  18. package/dist/{pegin-registration-client-8tzSRDaq.js.map → pegin-registration-client-Cvjk4ILq.js.map} +1 -1
  19. package/dist/{registration-records-BBOz21Dm.js → registration-records-DJJC2NiO.js} +81 -79
  20. package/dist/{registration-records-BBOz21Dm.js.map → registration-records-DJJC2NiO.js.map} +1 -1
  21. package/dist/{registration-records-DaBufozs.cjs → registration-records-XQMIKjGV.cjs} +2 -2
  22. package/dist/{registration-records-DaBufozs.cjs.map → registration-records-XQMIKjGV.cjs.map} +1 -1
  23. package/dist/{signer-set-reader-DFF9MgQN.js → signer-set-reader-CSUe92zE.js} +2 -2
  24. package/dist/{signer-set-reader-DFF9MgQN.js.map → signer-set-reader-CSUe92zE.js.map} +1 -1
  25. package/dist/{signer-set-reader-D-CyIYR5.cjs → signer-set-reader-GrFe_rsW.cjs} +2 -2
  26. package/dist/{signer-set-reader-D-CyIYR5.cjs.map → signer-set-reader-GrFe_rsW.cjs.map} +1 -1
  27. package/dist/tbv/core/clients/eth/index.cjs +1 -1
  28. package/dist/tbv/core/clients/eth/index.js +4 -4
  29. package/dist/tbv/core/clients/eth/protocol-params-reader.d.ts +1 -0
  30. package/dist/tbv/core/clients/eth/protocol-params-reader.d.ts.map +1 -1
  31. package/dist/tbv/core/clients/eth/protocol-params-validation.d.ts.map +1 -1
  32. package/dist/tbv/core/clients/eth/types.d.ts +12 -6
  33. package/dist/tbv/core/clients/eth/types.d.ts.map +1 -1
  34. package/dist/tbv/core/clients/index.cjs +1 -1
  35. package/dist/tbv/core/clients/index.js +4 -4
  36. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts +8 -0
  37. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts.map +1 -1
  38. package/dist/tbv/core/contracts/index.cjs +1 -1
  39. package/dist/tbv/core/contracts/index.js +1 -1
  40. package/dist/tbv/core/index.cjs +1 -1
  41. package/dist/tbv/core/index.js +8 -8
  42. package/dist/tbv/core/managers/index.cjs +1 -1
  43. package/dist/tbv/core/managers/index.js +1 -1
  44. package/dist/tbv/core/services/index.cjs +1 -1
  45. package/dist/tbv/core/services/index.js +1 -1
  46. package/dist/tbv/index.cjs +1 -1
  47. package/dist/tbv/index.js +8 -8
  48. package/dist/{toRefundInputs-DOCLxqC1.cjs → toRefundInputs-DTuWi--u.cjs} +2 -2
  49. package/dist/{toRefundInputs-DOCLxqC1.cjs.map → toRefundInputs-DTuWi--u.cjs.map} +1 -1
  50. package/dist/{toRefundInputs-Dso_QEr-.js → toRefundInputs-Dzw1cteD.js} +3 -3
  51. package/dist/{toRefundInputs-Dso_QEr-.js.map → toRefundInputs-Dzw1cteD.js.map} +1 -1
  52. package/dist/types-24A9Qoxb.js +274 -0
  53. package/dist/types-24A9Qoxb.js.map +1 -0
  54. package/dist/types-BC2TGzcp.cjs +2 -0
  55. package/dist/types-BC2TGzcp.cjs.map +1 -0
  56. package/package.json +2 -2
  57. package/dist/ProtocolParams.abi-CKOVqFJP.js.map +0 -1
  58. package/dist/ProtocolParams.abi-CjrT0545.cjs +0 -2
  59. package/dist/ProtocolParams.abi-CjrT0545.cjs.map +0 -1
  60. package/dist/types-DGr5HWwD.cjs +0 -2
  61. package/dist/types-DGr5HWwD.cjs.map +0 -1
  62. package/dist/types-Dbs--c2M.js +0 -198
  63. package/dist/types-Dbs--c2M.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"pegin-registration-client-8tzSRDaq.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 `PegInSubmittedV2` 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\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\n/**\n * Both registration events, queried together so one answer settles whether a\n * vault's V2 log is missing (pre-upgrade registration) or the node served no\n * logs for the block at all.\n */\nconst PEGIN_SUBMITTED_EVENTS = [\n getAbiItem({ abi: BTCVaultRegistryABI, name: \"PegInSubmitted\" }),\n getAbiItem({ abi: BTCVaultRegistryABI, name: \"PegInSubmittedV2\" }),\n] as const;\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/**\n * A `PegInSubmittedV2` log's decoded args, as viem's strict `getLogs` hands\n * them back after the `eventName` narrowing.\n */\ninterface PegInSubmittedV2Args {\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: PegInSubmittedV2Args,\n blockNumber: bigint,\n): PeginRegistrationRecord {\n // A plain decode of every V2 log in the block, strangers' included: nothing\n // here parses a transaction or bound-checks a script, so one malformed\n // registration elsewhere in the block cannot fail the caller's read. The\n // strict per-record checks live in registration-records.ts. A duplicate\n // vault id is not covered: a vault registers once, so two logs for one id\n // are an inconsistent node and fail 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\nfunction mapKeyEpochs(result: KeyEpochs, vaultId: Hex): KeyEpochs {\n return {\n vpKeyEpoch: assertEpochInRange(result.vpKeyEpoch, \"vpKeyEpoch\", vaultId),\n appKeeperKeyEpoch: assertEpochInRange(\n result.appKeeperKeyEpoch,\n \"appKeeperKeyEpoch\",\n vaultId,\n ),\n ucKeyEpoch: assertEpochInRange(result.ucKeyEpoch, \"ucKeyEpoch\", vaultId),\n };\n}\n\n/**\n * Concrete vault registry reader using viem.\n *\n * Usage:\n * ```ts\n * const reader = new ViemVaultRegistryReader(publicClient, registryAddress);\n * const data = await reader.getVaultData(vaultId);\n * ```\n */\nexport class ViemVaultRegistryReader implements VaultRegistryReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n /**\n * Read the VP's **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 unknown as KeyEpochs;\n\n return mapKeyEpochs(result, vaultId);\n }\n\n async getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) =>\n mapKeyEpochs(info as unknown as KeyEpochs, vaultIds[i]),\n );\n }\n\n async getVaultBasicInfo(vaultId: Hex): Promise<VaultBasicInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as RawVaultBasicInfo;\n\n return mapVaultBasicInfo(result);\n }\n\n async getVaultProtocolInfo(vaultId: Hex): Promise<VaultProtocolInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultProtocolInfo;\n\n return mapVaultProtocolInfo(result);\n }\n\n async getProtocolInfoBatch(\n vaultIds: readonly Hex[],\n ): Promise<VaultProtocolInfo[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) => {\n const result = info as unknown as RawVaultProtocolInfo;\n if (\n !result.depositorSignedPeginTx ||\n result.depositorSignedPeginTx === \"0x\"\n ) {\n // 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 // The vault app matches this message to render \"still confirming\".\n throw new Error(\n `Vault ${vaultIds[i]} not found on-chain or has no pegin transaction`,\n );\n }\n return mapVaultProtocolInfo(result);\n });\n }\n\n /**\n * Read the protocol pegin fee (in wei) for a given vault provider.\n * Mirrors the `getPegInFee(address)` view on BTCVaultRegistry.\n */\n async getPegInFee(vaultProvider: Address): Promise<bigint> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n }\n\n /**\n * Read a vault provider's current commission in basis points from\n * BTCVaultRegistry. The contract enforces `commissionBps < 10000`, so the\n * legitimate range is `[0, 9999]`; anything outside indicates a wrong\n * contract address or ABI drift and is surfaced as an error rather than\n * trusted.\n */\n async getVaultProviderCommission(vaultProvider: Address): Promise<number> {\n // viem infers `number` from the `uint16` return in the `as const` ABI.\n const bps = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderCommission\",\n args: [vaultProvider],\n });\n\n if (!Number.isInteger(bps) || bps < 0 || bps > MAX_VP_COMMISSION_BPS) {\n throw new Error(\n `getVaultProviderCommission returned ${bps} bps for ${vaultProvider}, ` +\n `outside the protocol range [0, ${MAX_VP_COMMISSION_BPS}]`,\n );\n }\n\n return bps;\n }\n\n async getVaultData(vaultId: Hex): Promise<VaultData> {\n // One round-trip for both structs (hard-fail): they feed signing/refund/\n // broadcast rebinds, so reading them in a single multicall also pins both\n // to the same block — no basic/protocol skew across two `eth_call`s.\n const [basicRaw, protocolRaw] = await this.publicClient.multicall({\n contracts: [\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n },\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n },\n ],\n allowFailure: false,\n });\n\n const basic = mapVaultBasicInfo(basicRaw);\n const protocol = mapVaultProtocolInfo(protocolRaw);\n\n if (\n !protocol.depositorSignedPeginTx ||\n protocol.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(\n `Vault ${vaultId} not found on-chain or has no pegin transaction`,\n );\n }\n\n return { basic, protocol };\n }\n\n /** @inheritdoc */\n async getRegistrationRecordsAtBlock(\n createdAt: bigint,\n ): Promise<PeginRegistrationRecord[]> {\n // Deliberately no `vaultId` topic filter: both events must come back in\n // ONE answer for the empty-vs-missing discriminator below to hold, and\n // viem's multi-event form takes no `args` — so the block's registration\n // logs are fetched whole and ids are matched client-side. strict: a log\n // 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 events: PEGIN_SUBMITTED_EVENTS,\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 if (log.eventName !== \"PegInSubmittedV2\") continue;\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 PegInSubmittedV2 log for vault ${record.vaultId} at block ${createdAt}, ` +\n `found more than one`,\n );\n }\n records.set(record.vaultId, record);\n }\n // The registry emits V1 and V2 together on every submission\n // (vault-contracts-aave-v4 `PeginLogic.sol:144-147` @ c559f5c2), so this\n // is as readily a node that served only part of the block as a pre-#548\n // registry — retryable either way.\n if (records.size === 0) {\n throw new RegistrationLogsUnavailableError(\n createdAt,\n `Block ${createdAt} holds ${logs.length} PegInSubmitted registration log(s) but no ` +\n `PegInSubmittedV2 log: either the node served a partial answer for block ${createdAt} ` +\n `(retry, preferably another node) or the registry predates the depositor's commission ` +\n `ceiling (vault-contracts-aave-v4 #548) and the ceiling cannot be recovered on-chain`,\n );\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 `PegInSubmittedV2`\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_EVENTS","getAbiItem","BTCVaultRegistryABI","VAULT_CLAIMABLE_BY_EVENT","VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS","maxBigint","a","b","mapRegistrationRecord","args","blockNumber","assertEpochInRange","value","field","vaultId","mapKeyEpochs","ViemVaultRegistryReader","publicClient","contractAddress","vpAddress","epoch","assertOnChainBtcPubkey","BTCVaultRegistryKeyEpochsABI","vaultIds","info","i","vaultProvider","basicRaw","protocolRaw","basic","protocol","createdAt","logs","RegistrationLogsUnavailableError","records","log","record","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
+ {"version":3,"file":"pegin-registration-client-Cvjk4ILq.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 `PegInSubmittedV2` 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\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\n/**\n * Both registration events, queried together so one answer settles whether a\n * vault's V2 log is missing (pre-upgrade registration) or the node served no\n * logs for the block at all.\n */\nconst PEGIN_SUBMITTED_EVENTS = [\n getAbiItem({ abi: BTCVaultRegistryABI, name: \"PegInSubmitted\" }),\n getAbiItem({ abi: BTCVaultRegistryABI, name: \"PegInSubmittedV2\" }),\n] as const;\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/**\n * A `PegInSubmittedV2` log's decoded args, as viem's strict `getLogs` hands\n * them back after the `eventName` narrowing.\n */\ninterface PegInSubmittedV2Args {\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: PegInSubmittedV2Args,\n blockNumber: bigint,\n): PeginRegistrationRecord {\n // A plain decode of every V2 log in the block, strangers' included: nothing\n // here parses a transaction or bound-checks a script, so one malformed\n // registration elsewhere in the block cannot fail the caller's read. The\n // strict per-record checks live in registration-records.ts. A duplicate\n // vault id is not covered: a vault registers once, so two logs for one id\n // are an inconsistent node and fail 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\nfunction mapKeyEpochs(result: KeyEpochs, vaultId: Hex): KeyEpochs {\n return {\n vpKeyEpoch: assertEpochInRange(result.vpKeyEpoch, \"vpKeyEpoch\", vaultId),\n appKeeperKeyEpoch: assertEpochInRange(\n result.appKeeperKeyEpoch,\n \"appKeeperKeyEpoch\",\n vaultId,\n ),\n ucKeyEpoch: assertEpochInRange(result.ucKeyEpoch, \"ucKeyEpoch\", vaultId),\n };\n}\n\n/**\n * Concrete vault registry reader using viem.\n *\n * Usage:\n * ```ts\n * const reader = new ViemVaultRegistryReader(publicClient, registryAddress);\n * const data = await reader.getVaultData(vaultId);\n * ```\n */\nexport class ViemVaultRegistryReader implements VaultRegistryReader {\n constructor(\n private publicClient: PublicClient,\n private contractAddress: Address,\n ) {}\n\n /**\n * Read the VP's **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 unknown as KeyEpochs;\n\n return mapKeyEpochs(result, vaultId);\n }\n\n async getVaultKeyEpochsBatch(vaultIds: readonly Hex[]): Promise<KeyEpochs[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryKeyEpochsABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) =>\n mapKeyEpochs(info as unknown as KeyEpochs, vaultIds[i]),\n );\n }\n\n async getVaultBasicInfo(vaultId: Hex): Promise<VaultBasicInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n })) as RawVaultBasicInfo;\n\n return mapVaultBasicInfo(result);\n }\n\n async getVaultProtocolInfo(vaultId: Hex): Promise<VaultProtocolInfo> {\n const result = (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n })) as RawVaultProtocolInfo;\n\n return mapVaultProtocolInfo(result);\n }\n\n async getProtocolInfoBatch(\n vaultIds: readonly Hex[],\n ): Promise<VaultProtocolInfo[]> {\n if (vaultIds.length === 0) return [];\n\n const results = await this.publicClient.multicall({\n contracts: vaultIds.map((vaultId) => ({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI as Abi,\n functionName: \"getBtcVaultProtocolInfo\" as const,\n args: [vaultId] as const,\n })),\n allowFailure: false,\n });\n\n return results.map((info, i) => {\n const result = info as unknown as RawVaultProtocolInfo;\n if (\n !result.depositorSignedPeginTx ||\n result.depositorSignedPeginTx === \"0x\"\n ) {\n // 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 // The vault app matches this message to render \"still confirming\".\n throw new Error(\n `Vault ${vaultIds[i]} not found on-chain or has no pegin transaction`,\n );\n }\n return mapVaultProtocolInfo(result);\n });\n }\n\n /**\n * Read the protocol pegin fee (in wei) for a given vault provider.\n * Mirrors the `getPegInFee(address)` view on BTCVaultRegistry.\n */\n async getPegInFee(vaultProvider: Address): Promise<bigint> {\n return (await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getPegInFee\",\n args: [vaultProvider],\n })) as bigint;\n }\n\n /**\n * Read a vault provider's current commission in basis points from\n * BTCVaultRegistry. The contract enforces `commissionBps < 10000`, so the\n * legitimate range is `[0, 9999]`; anything outside indicates a wrong\n * contract address or ABI drift and is surfaced as an error rather than\n * trusted.\n */\n async getVaultProviderCommission(vaultProvider: Address): Promise<number> {\n // viem infers `number` from the `uint16` return in the `as const` ABI.\n const bps = await this.publicClient.readContract({\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getVaultProviderCommission\",\n args: [vaultProvider],\n });\n\n if (!Number.isInteger(bps) || bps < 0 || bps > MAX_VP_COMMISSION_BPS) {\n throw new Error(\n `getVaultProviderCommission returned ${bps} bps for ${vaultProvider}, ` +\n `outside the protocol range [0, ${MAX_VP_COMMISSION_BPS}]`,\n );\n }\n\n return bps;\n }\n\n async getVaultData(vaultId: Hex): Promise<VaultData> {\n // One round-trip for both structs (hard-fail): they feed signing/refund/\n // broadcast rebinds, so reading them in a single multicall also pins both\n // to the same block — no basic/protocol skew across two `eth_call`s.\n const [basicRaw, protocolRaw] = await this.publicClient.multicall({\n contracts: [\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultBasicInfo\",\n args: [vaultId],\n },\n {\n address: this.contractAddress,\n abi: BTCVaultRegistryABI,\n functionName: \"getBtcVaultProtocolInfo\",\n args: [vaultId],\n },\n ],\n allowFailure: false,\n });\n\n const basic = mapVaultBasicInfo(basicRaw);\n const protocol = mapVaultProtocolInfo(protocolRaw);\n\n if (\n !protocol.depositorSignedPeginTx ||\n protocol.depositorSignedPeginTx === \"0x\"\n ) {\n throw new Error(\n `Vault ${vaultId} not found on-chain or has no pegin transaction`,\n );\n }\n\n return { basic, protocol };\n }\n\n /** @inheritdoc */\n async getRegistrationRecordsAtBlock(\n createdAt: bigint,\n ): Promise<PeginRegistrationRecord[]> {\n // Deliberately no `vaultId` topic filter: both events must come back in\n // ONE answer for the empty-vs-missing discriminator below to hold, and\n // viem's multi-event form takes no `args` — so the block's registration\n // logs are fetched whole and ids are matched client-side. strict: a log\n // 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 events: PEGIN_SUBMITTED_EVENTS,\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 if (log.eventName !== \"PegInSubmittedV2\") continue;\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 PegInSubmittedV2 log for vault ${record.vaultId} at block ${createdAt}, ` +\n `found more than one`,\n );\n }\n records.set(record.vaultId, record);\n }\n // The registry emits V1 and V2 together on every submission\n // (vault-contracts-aave-v4 `PeginLogic.sol:144-147` @ c559f5c2), so this\n // is as readily a node that served only part of the block as a pre-#548\n // registry — retryable either way.\n if (records.size === 0) {\n throw new RegistrationLogsUnavailableError(\n createdAt,\n `Block ${createdAt} holds ${logs.length} PegInSubmitted registration log(s) but no ` +\n `PegInSubmittedV2 log: either the node served a partial answer for block ${createdAt} ` +\n `(retry, preferably another node) or the registry predates the depositor's commission ` +\n `ceiling (vault-contracts-aave-v4 #548) and the ceiling cannot be recovered on-chain`,\n );\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 `PegInSubmittedV2`\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_EVENTS","getAbiItem","BTCVaultRegistryABI","VAULT_CLAIMABLE_BY_EVENT","VAULT_CLAIMABLE_BY_QUERY_CHUNK_BLOCKS","maxBigint","a","b","mapRegistrationRecord","args","blockNumber","assertEpochInRange","value","field","vaultId","mapKeyEpochs","ViemVaultRegistryReader","publicClient","contractAddress","vpAddress","epoch","assertOnChainBtcPubkey","BTCVaultRegistryKeyEpochsABI","vaultIds","info","i","vaultProvider","basicRaw","protocolRaw","basic","protocol","createdAt","logs","RegistrationLogsUnavailableError","records","log","record","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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"}