@babylonlabs-io/ts-sdk 0.56.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +1 -1
  2. package/dist/BTCVaultRegistry.abi-AUAyCHal.cjs +2 -0
  3. package/dist/BTCVaultRegistry.abi-AUAyCHal.cjs.map +1 -0
  4. package/dist/{BTCVaultRegistry.abi-Chs4AFBj.js → BTCVaultRegistry.abi-CixOlp3B.js} +73 -14
  5. package/dist/BTCVaultRegistry.abi-CixOlp3B.js.map +1 -0
  6. package/dist/BTCVaultRegistryKeyEpochs.abi-CXjhRZbm.js +111 -0
  7. package/dist/BTCVaultRegistryKeyEpochs.abi-CXjhRZbm.js.map +1 -0
  8. package/dist/BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs +2 -0
  9. package/dist/BTCVaultRegistryKeyEpochs.abi-_NERAdc5.cjs.map +1 -0
  10. package/dist/{PeginManager-aYBkb-Qx.js → PeginManager-CnX3uFb0.js} +6 -6
  11. package/dist/{PeginManager-aYBkb-Qx.js.map → PeginManager-CnX3uFb0.js.map} +1 -1
  12. package/dist/PeginManager-iDbqXsKD.cjs +2 -0
  13. package/dist/{PeginManager-BkWdZI7P.cjs.map → PeginManager-iDbqXsKD.cjs.map} +1 -1
  14. package/dist/ProtocolParams.abi-C8U7BHCS.cjs +2 -0
  15. package/dist/ProtocolParams.abi-C8U7BHCS.cjs.map +1 -0
  16. package/dist/{ApplicationRegistry.abi-w5prf7Ig.js → ProtocolParams.abi-CV938AYZ.js} +150 -80
  17. package/dist/ProtocolParams.abi-CV938AYZ.js.map +1 -0
  18. package/dist/{buildAndBroadcastRefund-BtXUqBkb.js → buildAndBroadcastRefund-CCb1_z24.js} +627 -452
  19. package/dist/buildAndBroadcastRefund-CCb1_z24.js.map +1 -0
  20. package/dist/buildAndBroadcastRefund-CDzzTZ2U.cjs +2 -0
  21. package/dist/buildAndBroadcastRefund-CDzzTZ2U.cjs.map +1 -0
  22. package/dist/index.cjs +1 -1
  23. package/dist/index.js +186 -175
  24. package/dist/index.js.map +1 -1
  25. package/dist/{types-CQDRQvV-.js → json-rpc-client-Ehjthcd7.js} +61 -61
  26. package/dist/json-rpc-client-Ehjthcd7.js.map +1 -0
  27. package/dist/{types-WA0LrDk1.cjs → json-rpc-client-fUoK-TzT.cjs} +2 -2
  28. package/dist/json-rpc-client-fUoK-TzT.cjs.map +1 -0
  29. package/dist/mempoolApi-C0olk43O.js +536 -0
  30. package/dist/mempoolApi-C0olk43O.js.map +1 -0
  31. package/dist/mempoolApi-Dsm2VPXp.cjs +2 -0
  32. package/dist/mempoolApi-Dsm2VPXp.cjs.map +1 -0
  33. package/dist/{noPayout-CihCk1HE.js → noPayout-CI4l1qu2.js} +2 -2
  34. package/dist/{noPayout-CihCk1HE.js.map → noPayout-CI4l1qu2.js.map} +1 -1
  35. package/dist/{noPayout-Cb8vFrkY.cjs → noPayout-Djrv31V5.cjs} +2 -2
  36. package/dist/{noPayout-Cb8vFrkY.cjs.map → noPayout-Djrv31V5.cjs.map} +1 -1
  37. package/dist/onChainBtcPubkey-Cd9kpz-S.cjs +2 -0
  38. package/dist/onChainBtcPubkey-Cd9kpz-S.cjs.map +1 -0
  39. package/dist/onChainBtcPubkey-aPY5ib3Q.js +19 -0
  40. package/dist/onChainBtcPubkey-aPY5ib3Q.js.map +1 -0
  41. package/dist/primeVpAuth-BlxUcdBf.cjs +2 -0
  42. package/dist/primeVpAuth-BlxUcdBf.cjs.map +1 -0
  43. package/dist/{primeVpAuth-DZOaC_Ui.js → primeVpAuth-DkJbvywo.js} +479 -367
  44. package/dist/primeVpAuth-DkJbvywo.js.map +1 -0
  45. package/dist/signPsbtsWithFallback-C01N6Kdo.cjs +2 -0
  46. package/dist/signPsbtsWithFallback-C01N6Kdo.cjs.map +1 -0
  47. package/dist/{PayoutManager-BVgmuKuK.js → signPsbtsWithFallback-CzZFZf0I.js} +105 -101
  48. package/dist/signPsbtsWithFallback-CzZFZf0I.js.map +1 -0
  49. package/dist/tbv/core/clients/eth/index.d.ts +5 -3
  50. package/dist/tbv/core/clients/eth/index.d.ts.map +1 -1
  51. package/dist/tbv/core/clients/eth/onChainBtcPubkey.d.ts +16 -0
  52. package/dist/tbv/core/clients/eth/onChainBtcPubkey.d.ts.map +1 -0
  53. package/dist/tbv/core/clients/eth/operation-key-reader.d.ts +33 -0
  54. package/dist/tbv/core/clients/eth/operation-key-reader.d.ts.map +1 -0
  55. package/dist/tbv/core/clients/eth/types.d.ts +122 -3
  56. package/dist/tbv/core/clients/eth/types.d.ts.map +1 -1
  57. package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts +25 -1
  58. package/dist/tbv/core/clients/eth/vault-registry-reader.d.ts.map +1 -1
  59. package/dist/tbv/core/clients/index.cjs +1 -1
  60. package/dist/tbv/core/clients/index.js +35 -32
  61. package/dist/tbv/core/clients/index.js.map +1 -1
  62. package/dist/tbv/core/clients/mempool/mempoolApi.d.ts.map +1 -1
  63. package/dist/tbv/core/contracts/__tests__/BTCVaultRegistryKeyEpochs.abi.test.d.ts +2 -0
  64. package/dist/tbv/core/contracts/__tests__/BTCVaultRegistryKeyEpochs.abi.test.d.ts.map +1 -0
  65. package/dist/tbv/core/contracts/abis/ApplicationRegistry.abi.d.ts +66 -0
  66. package/dist/tbv/core/contracts/abis/ApplicationRegistry.abi.d.ts.map +1 -1
  67. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts +50 -0
  68. package/dist/tbv/core/contracts/abis/BTCVaultRegistry.abi.d.ts.map +1 -1
  69. package/dist/tbv/core/contracts/abis/BTCVaultRegistryKeyEpochs.abi.d.ts +111 -0
  70. package/dist/tbv/core/contracts/abis/BTCVaultRegistryKeyEpochs.abi.d.ts.map +1 -0
  71. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts +36 -0
  72. package/dist/tbv/core/contracts/abis/ProtocolParams.abi.d.ts.map +1 -1
  73. package/dist/tbv/core/contracts/index.cjs +1 -1
  74. package/dist/tbv/core/contracts/index.d.ts +2 -1
  75. package/dist/tbv/core/contracts/index.d.ts.map +1 -1
  76. package/dist/tbv/core/contracts/index.js +8 -6
  77. package/dist/tbv/core/contracts/index.js.map +1 -1
  78. package/dist/tbv/core/index.cjs +1 -1
  79. package/dist/tbv/core/index.js +183 -172
  80. package/dist/tbv/core/index.js.map +1 -1
  81. package/dist/tbv/core/managers/PayoutManager.d.ts +8 -0
  82. package/dist/tbv/core/managers/PayoutManager.d.ts.map +1 -1
  83. package/dist/tbv/core/managers/index.cjs +1 -1
  84. package/dist/tbv/core/managers/index.js +2 -2
  85. package/dist/tbv/core/primitives/index.cjs +1 -1
  86. package/dist/tbv/core/primitives/index.js +2 -2
  87. package/dist/tbv/core/primitives/psbt/__tests__/standardPayoutScript.test.d.ts +2 -0
  88. package/dist/tbv/core/primitives/psbt/__tests__/standardPayoutScript.test.d.ts.map +1 -0
  89. package/dist/tbv/core/primitives/psbt/assertPayoutFeeBand.d.ts +5 -5
  90. package/dist/tbv/core/primitives/psbt/assertPayoutFeeBand.d.ts.map +1 -1
  91. package/dist/tbv/core/primitives/psbt/payout.d.ts +23 -0
  92. package/dist/tbv/core/primitives/psbt/payout.d.ts.map +1 -1
  93. package/dist/tbv/core/primitives/psbt/standardPayoutScript.d.ts +41 -0
  94. package/dist/tbv/core/primitives/psbt/standardPayoutScript.d.ts.map +1 -0
  95. package/dist/tbv/core/services/deposit/__tests__/verifyRegisteredParticipantKeys.test.d.ts +2 -0
  96. package/dist/tbv/core/services/deposit/__tests__/verifyRegisteredParticipantKeys.test.d.ts.map +1 -0
  97. package/dist/tbv/core/services/deposit/index.d.ts +7 -6
  98. package/dist/tbv/core/services/deposit/index.d.ts.map +1 -1
  99. package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts +10 -0
  100. package/dist/tbv/core/services/deposit/runDepositorPresignFlow.d.ts.map +1 -1
  101. package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts +9 -0
  102. package/dist/tbv/core/services/deposit/signDepositorGraph.d.ts.map +1 -1
  103. package/dist/tbv/core/services/deposit/validateOnChainParticipantKeys.d.ts +38 -1
  104. package/dist/tbv/core/services/deposit/validateOnChainParticipantKeys.d.ts.map +1 -1
  105. package/dist/tbv/core/services/deposit/verifyRegisteredParticipantKeys.d.ts +42 -0
  106. package/dist/tbv/core/services/deposit/verifyRegisteredParticipantKeys.d.ts.map +1 -0
  107. package/dist/tbv/core/services/index.cjs +1 -1
  108. package/dist/tbv/core/services/index.d.ts +1 -0
  109. package/dist/tbv/core/services/index.d.ts.map +1 -1
  110. package/dist/tbv/core/services/index.js +36 -31
  111. package/dist/tbv/core/services/participants/__tests__/fixtures/rotation.d.ts +55 -0
  112. package/dist/tbv/core/services/participants/__tests__/fixtures/rotation.d.ts.map +1 -0
  113. package/dist/tbv/core/services/participants/__tests__/resolveParticipantKeys.test.d.ts +2 -0
  114. package/dist/tbv/core/services/participants/__tests__/resolveParticipantKeys.test.d.ts.map +1 -0
  115. package/dist/tbv/core/services/participants/index.d.ts +8 -0
  116. package/dist/tbv/core/services/participants/index.d.ts.map +1 -0
  117. package/dist/tbv/core/services/participants/resolveParticipantKeys.d.ts +26 -0
  118. package/dist/tbv/core/services/participants/resolveParticipantKeys.d.ts.map +1 -0
  119. package/dist/tbv/core/services/participants/types.d.ts +62 -0
  120. package/dist/tbv/core/services/participants/types.d.ts.map +1 -0
  121. package/dist/tbv/core/utils/__tests__/abortSignals.test.d.ts +11 -0
  122. package/dist/tbv/core/utils/__tests__/abortSignals.test.d.ts.map +1 -0
  123. package/dist/tbv/core/utils/abortSignals.d.ts +23 -0
  124. package/dist/tbv/core/utils/abortSignals.d.ts.map +1 -0
  125. package/dist/tbv/core/utils/index.cjs +1 -1
  126. package/dist/tbv/core/utils/index.d.ts +1 -0
  127. package/dist/tbv/core/utils/index.d.ts.map +1 -1
  128. package/dist/tbv/core/utils/index.js +44 -43
  129. package/dist/tbv/index.cjs +1 -1
  130. package/dist/tbv/index.js +183 -172
  131. package/dist/tbv/index.js.map +1 -1
  132. package/dist/validation-CDbOaDj7.cjs +2 -0
  133. package/dist/validation-CDbOaDj7.cjs.map +1 -0
  134. package/dist/validation-Dj3dqYtl.js +30 -0
  135. package/dist/validation-Dj3dqYtl.js.map +1 -0
  136. package/dist/verifyScriptPathSchnorrSignature-C-84KJ6U.cjs +2 -0
  137. package/dist/verifyScriptPathSchnorrSignature-C-84KJ6U.cjs.map +1 -0
  138. package/dist/{verifyScriptPathSchnorrSignature-CgrnAjMW.js → verifyScriptPathSchnorrSignature-Xoo9DOHW.js} +359 -301
  139. package/dist/verifyScriptPathSchnorrSignature-Xoo9DOHW.js.map +1 -0
  140. package/package.json +3 -3
  141. package/dist/ApplicationRegistry.abi-CLaa6E99.cjs +0 -2
  142. package/dist/ApplicationRegistry.abi-CLaa6E99.cjs.map +0 -1
  143. package/dist/ApplicationRegistry.abi-w5prf7Ig.js.map +0 -1
  144. package/dist/BTCVaultRegistry.abi-Chs4AFBj.js.map +0 -1
  145. package/dist/BTCVaultRegistry.abi-JdeqLz4x.cjs +0 -2
  146. package/dist/BTCVaultRegistry.abi-JdeqLz4x.cjs.map +0 -1
  147. package/dist/PayoutManager-BVgmuKuK.js.map +0 -1
  148. package/dist/PayoutManager-Cu4_l-_Y.cjs +0 -2
  149. package/dist/PayoutManager-Cu4_l-_Y.cjs.map +0 -1
  150. package/dist/PeginManager-BkWdZI7P.cjs +0 -2
  151. package/dist/buildAndBroadcastRefund-BtXUqBkb.js.map +0 -1
  152. package/dist/buildAndBroadcastRefund-Cq01wyZX.cjs +0 -2
  153. package/dist/buildAndBroadcastRefund-Cq01wyZX.cjs.map +0 -1
  154. package/dist/mempoolApi-P_ApODLd.js +0 -483
  155. package/dist/mempoolApi-P_ApODLd.js.map +0 -1
  156. package/dist/mempoolApi-emec8bHK.cjs +0 -2
  157. package/dist/mempoolApi-emec8bHK.cjs.map +0 -1
  158. package/dist/primeVpAuth-DZOaC_Ui.js.map +0 -1
  159. package/dist/primeVpAuth-j2getl3f.cjs +0 -2
  160. package/dist/primeVpAuth-j2getl3f.cjs.map +0 -1
  161. package/dist/types-CQDRQvV-.js.map +0 -1
  162. package/dist/types-WA0LrDk1.cjs.map +0 -1
  163. package/dist/validation-CxqROCno.js +0 -15
  164. package/dist/validation-CxqROCno.js.map +0 -1
  165. package/dist/validation-u8W7Lp2x.cjs +0 -2
  166. package/dist/validation-u8W7Lp2x.cjs.map +0 -1
  167. package/dist/verifyScriptPathSchnorrSignature-BZhX-SOd.cjs +0 -2
  168. package/dist/verifyScriptPathSchnorrSignature-BZhX-SOd.cjs.map +0 -1
  169. package/dist/verifyScriptPathSchnorrSignature-CgrnAjMW.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-CQDRQvV-.js","sources":["../src/tbv/core/clients/vault-provider/json-rpc-client.ts","../src/tbv/core/clients/vault-provider/types.ts"],"sourcesContent":["/**\n * Generic JSON-RPC 2.0 HTTP Client\n *\n * Framework-agnostic client using `fetch()` — works in browsers and Node.js 18+.\n * Includes configurable retry policy and AbortSignal passthrough.\n */\n\nexport interface JsonRpcRequest<T = unknown> {\n jsonrpc: \"2.0\";\n method: string;\n params: T;\n id: number | string;\n}\n\nexport interface JsonRpcSuccessResponse<T = unknown> {\n jsonrpc: \"2.0\";\n result: T;\n id: number | string;\n}\n\nexport interface JsonRpcErrorResponse {\n jsonrpc: \"2.0\";\n error: {\n code: number;\n message: string;\n data?: unknown;\n };\n id: number | string;\n}\n\nexport type JsonRpcResponse<T = unknown> =\n | JsonRpcSuccessResponse<T>\n | JsonRpcErrorResponse;\n\n/**\n * Injects bearer tokens into requests for auth-gated methods, and is\n * notified on auth-expired responses so it can invalidate its cache.\n *\n * The `JsonRpcClient` is agnostic to which methods are auth-gated —\n * the provider's `getToken(method)` decides. Returning `null` means\n * \"no auth required for this method\"; the client then sends the\n * request with no `Authorization` header.\n */\nexport interface BearerTokenProvider {\n /**\n * Return the bearer token to inject for `method`, or `null` if the\n * method does not require auth.\n */\n getToken(method: string): Promise<string | null>;\n /**\n * Drop the cached token. Next call to `getToken` must re-acquire.\n * Called by the client on reactive-refresh-trigger responses.\n */\n invalidate(): void;\n}\n\nexport interface JsonRpcClientConfig {\n /** Base URL of the RPC service */\n baseUrl: string;\n /** Timeout in milliseconds per request attempt */\n timeout: number;\n /** Optional custom headers */\n headers?: Record<string, string>;\n /** Number of retry attempts for transient errors (default: 3) */\n retries?: number;\n /** Initial retry delay in milliseconds (default: 1000) */\n retryDelay?: number;\n /**\n * Maximum response body size, in bytes, for typed JSON-RPC calls.\n * `callRaw` intentionally returns the unparsed Response and is not capped here.\n * Default: 2 MiB.\n */\n maxResponseBytes?: number;\n /**\n * Predicate that decides which methods retry on transient errors.\n * Default retries only `getPeginStatus`, `batchGetPeginStatus`,\n * `batchGetPegoutStatus`, and `requestDepositorPresignTransactions`.\n * Write methods are not retried by default.\n */\n retryableFor?: (method: string) => boolean;\n /**\n * Per-request bearer-token source. A non-null return attaches\n * `Authorization: Bearer <token>`; `null` skips auth. `call`\n * additionally retries once on wire `auth_expired` (invalidate +\n * refetch + retry). `callRaw` skips reactive refresh.\n */\n tokenProvider?: BearerTokenProvider;\n}\n\n// \"wire\" = parsed from a JSON-RPC error envelope; \"local\" = timeout/network/parse failure.\nexport type JsonRpcErrorSource = \"wire\" | \"local\";\n\nexport class JsonRpcError extends Error {\n constructor(\n public code: number,\n message: string,\n /** \"wire\" for server-returned envelopes; \"local\" for SDK-side failures. */\n public source: JsonRpcErrorSource = \"local\",\n /** Structured data from the server `error.data` field, if any. */\n public data?: unknown,\n ) {\n super(message);\n this.name = \"JsonRpcError\";\n }\n}\n\nexport const JSON_RPC_ERROR_CODES = {\n TIMEOUT: -32000,\n NETWORK: -32001,\n /** VP proxy: request timed out at proxy level */\n PROXY_TIMEOUT: -32002,\n /** VP proxy: VP unreachable / DNS failure / response too large */\n PROXY_UNAVAILABLE: -32003,\n /** SDK client: response missing \"result\" field (malformed JSON-RPC) */\n INVALID_RESPONSE: -32700,\n /** SDK client: response body exceeded the configured byte limit */\n RESPONSE_TOO_LARGE: -32701,\n} as const;\n\n/** JSON-RPC protocol version */\nconst JSON_RPC_VERSION = \"2.0\" as const;\n\n/** Default number of retry attempts for transient errors */\nconst DEFAULT_RETRY_ATTEMPTS = 3;\n\n/** Default initial retry delay in milliseconds */\nconst DEFAULT_RETRY_DELAY_MS = 1000;\n\n/** Default maximum JSON-RPC response size for typed calls (2 MiB) */\nconst DEFAULT_MAX_RESPONSE_BYTES = 2 * 1024 * 1024;\n\n/**\n * TODO: Temporary typed-call exceptions for methods that currently return large\n * artifact payloads as JSON-RPC results.\n */\nconst UNCAPPED_TYPED_RESPONSE_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_requestDepositorClaimerArtifacts\",\n]);\n\n/** HTTP status codes that indicate transient server errors and are safe to retry */\nconst RETRYABLE_HTTP_STATUS_CODES: ReadonlySet<number> = new Set([\n 408, // Request Timeout\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n]);\n\n/** Default retry predicate: only retry read-only / idempotent methods */\nconst DEFAULT_RETRYABLE_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_getPeginStatus\",\n \"vaultProvider_batchGetPeginStatus\",\n \"vaultProvider_batchGetPegoutStatus\",\n \"vaultProvider_requestDepositorPresignTransactions\",\n]);\n\nfunction defaultRetryableFor(method: string): boolean {\n return DEFAULT_RETRYABLE_METHODS.has(method);\n}\n\n/**\n * Token-expired marker the server emits in `error.data.kind`. When\n * present on a wire-origin error, the client invalidates its cached\n * token and retries the request once with a freshly-acquired bearer.\n *\n * Kept in sync with btc-vault's auth middleware. Absence of the marker\n * means the server does not support reactive refresh yet; we fall back\n * to proactive-only refresh via `BearerTokenProvider.getToken()` TTL\n * checks.\n */\nexport const AUTH_EXPIRED_DATA_KIND = \"auth_expired\";\n\nfunction isAuthExpiredError(error: unknown): boolean {\n if (!(error instanceof JsonRpcError)) return false;\n if (error.source !== \"wire\") return false;\n const data = error.data;\n if (data === null || typeof data !== \"object\") return false;\n const kind = (data as { kind?: unknown }).kind;\n return kind === AUTH_EXPIRED_DATA_KIND;\n}\n\n/**\n * Generic JSON-RPC 2.0 HTTP client with safe retry policy.\n */\nexport class JsonRpcClient {\n private baseUrl: string;\n private timeout: number;\n private headers: Record<string, string>;\n private requestId = 0;\n private retries: number;\n private retryDelay: number;\n private maxResponseBytes: number;\n private retryableFor: (method: string) => boolean;\n private tokenProvider?: BearerTokenProvider;\n\n constructor(config: JsonRpcClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n this.timeout = config.timeout;\n this.headers = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n this.retries = config.retries ?? DEFAULT_RETRY_ATTEMPTS;\n this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;\n this.maxResponseBytes =\n config.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;\n if (!Number.isFinite(this.maxResponseBytes) || this.maxResponseBytes <= 0) {\n throw new Error(\"maxResponseBytes must be a positive finite number\");\n }\n this.retryableFor = config.retryableFor ?? defaultRetryableFor;\n this.tokenProvider = config.tokenProvider;\n }\n\n private async buildHeaders(method: string): Promise<Record<string, string>> {\n const headers: Record<string, string> = { ...this.headers };\n if (this.tokenProvider) {\n const token = await this.tokenProvider.getToken(method);\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n }\n return headers;\n }\n\n /**\n * Make a JSON-RPC request with optional retry for safe methods.\n *\n * If the request fails with a wire-origin `auth_expired` error and a\n * `tokenProvider` is configured, the client invalidates its cached\n * token and retries the request once with a freshly-acquired bearer.\n *\n * @param method - The RPC method name\n * @param params - The method parameters\n * @param signal - Optional AbortSignal for caller-controlled cancellation\n * @returns The result from the RPC method\n * @throws JsonRpcError if the RPC call fails\n */\n async call<TParams, TResult>(\n method: string,\n params: TParams,\n signal?: AbortSignal,\n ): Promise<TResult> {\n try {\n return await this.callOnce<TParams, TResult>(method, params, signal);\n } catch (error) {\n // The auth-expired retry fires for ALL methods, including mutating\n // ones. This is intentional and safe: the server's auth middleware\n // validates the bearer token BEFORE dispatching to the method\n // handler, so an `auth_expired` error means the handler never ran\n // and no state was mutated. Confirmed against btc-vault at\n // `crates/btc-auth/src/middleware/jsonrpc.rs` — token validation\n // is pre-handler only. The `retryableFor` guard on\n // HTTP-transient-error retries doesn't apply here because that\n // guard is about retrying after a request the server may have\n // started processing; auth_expired is categorically different.\n if (this.tokenProvider && isAuthExpiredError(error)) {\n this.tokenProvider.invalidate();\n return await this.callOnce<TParams, TResult>(method, params, signal);\n }\n throw error;\n }\n }\n\n private async callOnce<TParams, TResult>(\n method: string,\n params: TParams,\n signal: AbortSignal | undefined,\n ): Promise<TResult> {\n const response = await this.fetchWithRetry(method, params, signal);\n\n let jsonResponse: unknown;\n try {\n const responseText = UNCAPPED_TYPED_RESPONSE_METHODS.has(method)\n ? await response.text()\n : await readResponseTextWithLimit(response, this.maxResponseBytes);\n jsonResponse = JSON.parse(responseText);\n } catch (error) {\n if (error instanceof JsonRpcError) {\n throw error;\n }\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n \"Invalid JSON-RPC response: body is not valid JSON\",\n \"local\",\n );\n }\n\n if (\n jsonResponse === null ||\n typeof jsonResponse !== \"object\" ||\n Array.isArray(jsonResponse)\n ) {\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n `Invalid JSON-RPC response: expected an object, got ${typeof jsonResponse}`,\n \"local\",\n );\n }\n\n const rpcResponse = jsonResponse as Record<string, unknown>;\n\n if (\"error\" in rpcResponse && rpcResponse.error != null) {\n const err = rpcResponse.error as {\n code?: number;\n message?: string;\n data?: unknown;\n };\n throw new JsonRpcError(\n err.code ?? JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n err.message ?? \"Unknown RPC error\",\n \"wire\",\n err.data,\n );\n }\n\n if (!(\"result\" in rpcResponse)) {\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n `Invalid JSON-RPC response: missing \"result\" field`,\n \"local\",\n );\n }\n\n return rpcResponse.result as TResult;\n }\n\n /**\n * Make a JSON-RPC request returning the raw Response (unparsed body).\n *\n * Bearer tokens are injected identically to `call`. **Reactive refresh\n * is NOT performed here** — the response body may be unbounded (e.g.\n * claimer-artifact downloads), so the client refuses to parse it to\n * detect auth errors. Callers relying on token-expired retries for\n * large downloads must read the body themselves and re-invoke\n * `callRaw` after `tokenProvider.invalidate()`.\n */\n async callRaw<TParams>(\n method: string,\n params: TParams,\n signal?: AbortSignal,\n ): Promise<Response> {\n return this.fetchWithRetry(method, params, signal);\n }\n\n private async fetchWithRetry<TParams>(\n method: string,\n params: TParams,\n callerSignal?: AbortSignal,\n ): Promise<Response> {\n const requestId = ++this.requestId;\n const maxRetries = this.retryableFor(method) ? this.retries : 0;\n\n // jsonrpsee (Rust backend) expects params as an array (positional parameters)\n const request: JsonRpcRequest<TParams[]> = {\n jsonrpc: JSON_RPC_VERSION,\n method,\n params: [params],\n id: requestId,\n };\n\n const body = JSON.stringify(request);\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n // Merge caller signal with per-request timeout signal\n const timeoutController = new AbortController();\n const timeoutId = setTimeout(\n () => timeoutController.abort(),\n this.timeout,\n );\n\n const merged = callerSignal\n ? mergeAbortSignals(callerSignal, timeoutController.signal)\n : null;\n const signal = merged ? merged.signal : timeoutController.signal;\n\n try {\n // Build headers per-attempt so the token provider can return a\n // freshly-acquired bearer after a prior invalidate() on this\n // request (retry loop path) without plumbing state through.\n const headers = await this.buildHeaders(method);\n\n const response = await fetch(this.baseUrl, {\n method: \"POST\",\n headers,\n body,\n signal,\n });\n\n clearTimeout(timeoutId);\n merged?.cleanup();\n\n if (!response.ok) {\n const shouldRetry =\n attempt < maxRetries &&\n RETRYABLE_HTTP_STATUS_CODES.has(response.status);\n\n if (shouldRetry) {\n const delay = this.retryDelay * Math.pow(2, attempt);\n await this.sleep(delay, callerSignal);\n continue;\n }\n\n throw new Error(\n `HTTP error: ${response.status} ${response.statusText}`,\n );\n }\n\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n merged?.cleanup();\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Check if caller aborted (not our timeout)\n if (callerSignal?.aborted) {\n throw new Error(\"Request aborted\");\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n if (attempt < maxRetries) {\n const delay = this.retryDelay * Math.pow(2, attempt);\n await this.sleep(delay, callerSignal);\n continue;\n }\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.TIMEOUT,\n `Request timeout after ${this.timeout}ms (${maxRetries + 1} attempts)`,\n \"local\",\n );\n }\n\n // Handle network errors (CORS, connection refused, etc.)\n if (error instanceof TypeError) {\n if (attempt < maxRetries) {\n const delay = this.retryDelay * Math.pow(2, attempt);\n await this.sleep(delay, callerSignal);\n continue;\n }\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.NETWORK,\n `Network error: ${error.message} (${maxRetries + 1} attempts)`,\n \"local\",\n );\n }\n\n // Don't retry JSON-RPC errors (business logic errors)\n throw error;\n }\n }\n\n throw lastError || new Error(\"Unknown error after retries\");\n }\n\n private sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error(\"Request aborted\"));\n return;\n }\n const timeoutId = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(new Error(\"Request aborted\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n }\n\n getBaseUrl(): string {\n return this.baseUrl;\n }\n}\n\ninterface MergedSignal {\n signal: AbortSignal;\n /** Remove listeners from the source signals. Call after the request completes. */\n cleanup: () => void;\n}\n\n/**\n * Merge two AbortSignals — the returned signal aborts if either input aborts.\n * Returns a cleanup function to remove listeners when the request completes\n * normally, preventing listener accumulation in long-lived polling flows.\n */\nfunction mergeAbortSignals(a: AbortSignal, b: AbortSignal): MergedSignal {\n if (a.aborted) return { signal: a, cleanup: () => {} };\n if (b.aborted) return { signal: b, cleanup: () => {} };\n\n const controller = new AbortController();\n const onAbortA = () => {\n b.removeEventListener(\"abort\", onAbortB);\n controller.abort();\n };\n const onAbortB = () => {\n a.removeEventListener(\"abort\", onAbortA);\n controller.abort();\n };\n a.addEventListener(\"abort\", onAbortA, { once: true });\n b.addEventListener(\"abort\", onAbortB, { once: true });\n\n const cleanup = () => {\n a.removeEventListener(\"abort\", onAbortA);\n b.removeEventListener(\"abort\", onAbortB);\n };\n\n return { signal: controller.signal, cleanup };\n}\n\nasync function readResponseTextWithLimit(\n response: Response,\n maxBytes: number,\n): Promise<string> {\n const contentLength = response.headers.get(\"content-length\");\n if (contentLength !== null) {\n const parsedContentLength = Number(contentLength);\n if (\n Number.isFinite(parsedContentLength) &&\n parsedContentLength > maxBytes\n ) {\n throw responseTooLargeError(maxBytes);\n }\n }\n\n if (!response.body) {\n return \"\";\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let totalBytes = 0;\n let responseText = \"\";\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n totalBytes += value.byteLength;\n if (totalBytes > maxBytes) {\n await reader.cancel();\n throw responseTooLargeError(maxBytes);\n }\n responseText += decoder.decode(value, { stream: true });\n }\n } finally {\n reader.releaseLock();\n }\n\n return responseText + decoder.decode();\n}\n\nfunction responseTooLargeError(maxBytes: number): JsonRpcError {\n return new JsonRpcError(\n JSON_RPC_ERROR_CODES.RESPONSE_TOO_LARGE,\n `JSON-RPC response exceeds maximum size of ${maxBytes} bytes`,\n \"local\",\n );\n}\n","/**\n * Type definitions for Vault Provider JSON-RPC API.\n *\n * These types match the `vaultProvider_*` RPC namespace defined by the\n * btc-vault daemon. They are the SDK's canonical copy of the VP protocol\n * contract, independent of any frontend framework.\n *\n * @see https://github.com/babylonlabs-io/btc-vault/blob/main/docs/pegin.md\n */\n\n// ============================================================================\n// Daemon Status\n// ============================================================================\n\n/**\n * Backend daemon status (vault provider database).\n * Source: btc-vault crates/vaultd/src/workers/claimer/mod.rs PegInStatus enum\n *\n * State flow (happy path):\n * PendingIngestion -> PendingDepositorWotsPK -> PendingBabeSetup -> PendingChallengerPresigning\n * -> PendingPeginSigsAvailability -> PendingPrePegInConfirmations\n * -> PendingDepositorSignatures -> PendingACKs -> PendingActivation\n * -> ActivatedPendingBroadcast -> Activated\n *\n * Branching / terminal states:\n * - IngestionRejected: terminal — ingestion permanently failed (e.g. malformed\n * Pre-PegIn, invalid HTLC outputs); reachable directly from PendingIngestion.\n * - Expired: activation timed out; non-terminal during the grace window\n * (RFC 003) — transitions to ExpiredCleanedUp or ExpiredInClaim.\n * - InvalidSigInContract: terminal — pegin input signature posted on\n * chain failed verification.\n * - AmlRejected: terminal — AML address screening rejected the pegin.\n * - ExpiredCleanedUp: terminal — grace window expired, per-pegin\n * artifacts deleted.\n * - ExpiredInClaim: terminal at the pegin-state-machine level; pegout-side\n * work continues on the pegout_tracking row.\n */\nexport enum DaemonStatus {\n PENDING_INGESTION = \"PendingIngestion\",\n PENDING_DEPOSITOR_WOTS_PK = \"PendingDepositorWotsPK\",\n PENDING_BABE_SETUP = \"PendingBabeSetup\",\n PENDING_CHALLENGER_PRESIGNING = \"PendingChallengerPresigning\",\n PENDING_PEGIN_SIGS_AVAILABILITY = \"PendingPeginSigsAvailability\",\n PENDING_PRE_PEGIN_CONFIRMATIONS = \"PendingPrePegInConfirmations\",\n PENDING_DEPOSITOR_SIGNATURES = \"PendingDepositorSignatures\",\n PENDING_ACKS = \"PendingACKs\",\n PENDING_ACTIVATION = \"PendingActivation\",\n ACTIVATED_PENDING_BROADCAST = \"ActivatedPendingBroadcast\",\n ACTIVATED = \"Activated\",\n EXPIRED = \"Expired\",\n INGESTION_REJECTED = \"IngestionRejected\",\n INVALID_SIG_IN_CONTRACT = \"InvalidSigInContract\",\n AML_REJECTED = \"AmlRejected\",\n EXPIRED_CLEANED_UP = \"ExpiredCleanedUp\",\n EXPIRED_IN_CLAIM = \"ExpiredInClaim\",\n}\n\n// ============================================================================\n// Status Groups\n// ============================================================================\n\n/**\n * States where the VP is still processing (no depositor action needed).\n * Excludes PENDING_DEPOSITOR_WOTS_PK (requires depositor action).\n */\nexport const PRE_DEPOSITOR_SIGNATURES_STATES: readonly DaemonStatus[] = [\n DaemonStatus.PENDING_INGESTION,\n DaemonStatus.PENDING_BABE_SETUP,\n DaemonStatus.PENDING_CHALLENGER_PRESIGNING,\n DaemonStatus.PENDING_PEGIN_SIGS_AVAILABILITY,\n DaemonStatus.PENDING_PRE_PEGIN_CONFIRMATIONS,\n];\n\n/** States after PendingDepositorSignatures where the depositor has no action. */\nconst POST_PAYOUT_SIGNATURE_STATUSES: readonly DaemonStatus[] = [\n DaemonStatus.PENDING_ACKS,\n DaemonStatus.PENDING_ACTIVATION,\n DaemonStatus.ACTIVATED_PENDING_BROADCAST,\n DaemonStatus.ACTIVATED,\n];\n\n/**\n * Statuses where no depositor action is needed (VP processing or already past\n * depositor interaction). Excludes PENDING_INGESTION and PENDING_DEPOSITOR_WOTS_PK.\n */\nexport const VP_TRANSIENT_STATUSES: ReadonlySet<DaemonStatus> = new Set([\n DaemonStatus.PENDING_BABE_SETUP,\n DaemonStatus.PENDING_CHALLENGER_PRESIGNING,\n DaemonStatus.PENDING_PEGIN_SIGS_AVAILABILITY,\n DaemonStatus.PENDING_PRE_PEGIN_CONFIRMATIONS,\n ...POST_PAYOUT_SIGNATURE_STATUSES,\n]);\n\n/**\n * Terminal VP statuses that represent failure outcomes — polling should\n * stop immediately with an error rather than wait for timeout.\n *\n * Mirrors the failure subset of the server-side terminals\n * (`allowed_transitions()` empty, see\n * `btc-vault/crates/vaultd/src/workers/claimer/mod.rs:230-242`).\n * `Activated` IS terminal on-chain but is the success outcome, so it is\n * intentionally excluded — a caller polling for an earlier state that\n * races straight to `Activated` should treat that as success-via-overshoot,\n * not failure. `Expired` is also excluded — under RFC 003 it is a\n * grace-window interim that transitions to `ExpiredCleanedUp` or\n * `ExpiredInClaim`. Callers that want to stop polling on any expiry\n * should check `status === DaemonStatus.EXPIRED ||\n * VP_TERMINAL_FAILURE_STATUSES.has(status)`.\n */\nexport const VP_TERMINAL_FAILURE_STATUSES: ReadonlySet<DaemonStatus> = new Set([\n DaemonStatus.INGESTION_REJECTED,\n DaemonStatus.INVALID_SIG_IN_CONTRACT,\n DaemonStatus.AML_REJECTED,\n DaemonStatus.EXPIRED_CLEANED_UP,\n DaemonStatus.EXPIRED_IN_CLAIM,\n]);\n\n/**\n * Statuses that come after WOTS key submission.\n * If the VP is already in one of these states, the WOTS key was already\n * submitted and we can skip.\n */\nexport const POST_WOTS_STATUSES: ReadonlySet<DaemonStatus> = new Set([\n ...VP_TRANSIENT_STATUSES,\n DaemonStatus.PENDING_DEPOSITOR_SIGNATURES,\n]);\n\n// ============================================================================\n// WOTS Types (needed by SubmitDepositorWotsKeyParams)\n// ============================================================================\n\n/**\n * WOTS configuration for a single block.\n * Matches Rust `babe::wots::Config` serde format.\n */\nexport interface WotsConfig {\n /** Digit bit-width (e.g. 4 → base-16 digits). */\n d: number;\n /** Number of message digits in this block. */\n n: number;\n /** Radix used for the checksum computation. */\n checksum_radix: number;\n}\n\n/**\n * A single block of WOTS public keys.\n * Chain values are arrays of byte values (matching Rust `[u8; 20]`).\n */\nexport interface WotsBlockPublicKey {\n config: WotsConfig;\n message_terminals: number[][];\n checksum_major_terminal: number[];\n checksum_minor_terminal: number[];\n}\n\n// ============================================================================\n// Request Parameter Types\n// ============================================================================\n\n/** Params for requesting the payout/claim/assert transactions to pre-sign. */\nexport interface RequestDepositorPresignTransactionsParams {\n pegin_txid: string;\n depositor_pk: string;\n}\n\n/** Params for submitting the depositor's WOTS public key to the VP. */\nexport interface SubmitDepositorWotsKeyParams {\n pegin_txid: string;\n depositor_pk: string;\n wots_public_keys: WotsBlockPublicKey[];\n}\n\n/** Per-challenger signatures for the depositor-as-claimer flow. */\nexport interface DepositorPreSigsPerChallenger {\n nopayout_signature: string;\n}\n\n/** Depositor-as-claimer pre-signatures (payout + per-challenger). */\nexport interface DepositorAsClaimerPresignatures {\n payout_signatures: ClaimerSignatures;\n per_challenger: Record<string, DepositorPreSigsPerChallenger>;\n}\n\n/** Params for submitting depositor pre-signatures including claimer presignatures. */\nexport interface SubmitDepositorPresignaturesParams {\n pegin_txid: string;\n depositor_pk: string;\n signatures: Record<string, ClaimerSignatures>;\n depositor_claimer_presignatures: DepositorAsClaimerPresignatures;\n}\n\n/** Payout signatures per claimer. */\nexport interface ClaimerSignatures {\n payout_signature: string;\n}\n\n/** Params for requesting BaBe DecryptorArtifacts from the VP. */\nexport interface RequestDepositorClaimerArtifactsParams {\n pegin_txid: string;\n depositor_pk: string;\n}\n\n/** Params for querying pegin status. Either pegin_txid or vault_id must be provided. */\nexport type GetPeginStatusParams =\n | { pegin_txid: string; vault_id?: never }\n | { vault_id: string; pegin_txid?: never };\n\n// ============================================================================\n// Response Types\n// ============================================================================\n\n/** A raw Bitcoin transaction with its hex encoding. */\nexport interface TransactionData {\n tx_hex: string;\n}\n\n/** Set of transactions the depositor must pre-sign for a single claimer. */\nexport interface ClaimerTransactions {\n claimer_pubkey: string;\n claim_tx: TransactionData;\n assert_tx: TransactionData;\n payout_tx: TransactionData;\n payout_psbt: string;\n}\n\n/** Per-segment connector data for ChallengeAssert inputs. */\nexport interface ChallengeAssertConnectorData {\n wots_pks_json: string;\n gc_wots_keys_json: string;\n}\n\n/** Challenger-specific transactions and signing data for the depositor graph. */\nexport interface PresignDataPerChallenger {\n challenger_pubkey: string;\n challenge_assert_x_tx: TransactionData;\n challenge_assert_y_tx: TransactionData;\n nopayout_tx: TransactionData;\n nopayout_psbt: string;\n challenge_assert_connectors: ChallengeAssertConnectorData[];\n output_label_hashes: string[];\n}\n\n/** Depositor-as-claimer TxGraph transactions. */\nexport interface DepositorGraphTransactions {\n claim_tx: TransactionData;\n assert_tx: TransactionData;\n payout_tx: TransactionData;\n payout_psbt: string;\n challenger_presign_data: PresignDataPerChallenger[];\n offchain_params_version: number;\n}\n\n/** Response from `requestDepositorPresignTransactions`. */\nexport interface RequestDepositorPresignTransactionsResponse {\n txs: ClaimerTransactions[];\n depositor_graph: DepositorGraphTransactions;\n}\n\n/** BaBe garbled-circuit session data for a single challenger. */\nexport interface BaBeSessionData {\n decryptor_artifacts_hex: string;\n}\n\n/** Response from `requestDepositorClaimerArtifacts`. */\nexport interface RequestDepositorClaimerArtifactsResponse {\n tx_graph_json: string;\n verifying_key_hex: string;\n babe_sessions: Record<string, BaBeSessionData>;\n}\n\n/** Progress tracker for a multi-challenger operation. */\nexport interface ChallengerProgress {\n total_challengers: number;\n completed_challengers: number;\n completed_challenger_pubkeys: string[];\n pending_challenger_pubkeys: string[];\n}\n\nexport type GcDataProgress = ChallengerProgress;\nexport type AckCollectionProgress = ChallengerProgress;\n\n/** Extended presigning progress with all 3 concurrent phases. */\nexport interface PresigningProgress extends ChallengerProgress {\n depositor_graph_created?: boolean;\n vk_challenger_presigning_completed?: number;\n vk_challenger_presigning_total?: number;\n}\n\n/** Detailed progress breakdown for an in-progress pegin. */\nexport interface PeginProgressDetails {\n gc_data?: GcDataProgress;\n presigning?: PresigningProgress;\n ack_collection?: AckCollectionProgress;\n claimer_graphs?: ClaimerGraphStatus[];\n}\n\n/** Per-claimer graph status (challenger perspective). */\nexport interface ClaimerGraphStatus {\n claimer_pubkey: string;\n presigned: boolean;\n}\n\n/** Response from `getPeginStatus`. */\nexport interface GetPeginStatusResponse {\n pegin_txid: string;\n status: string;\n progress: PeginProgressDetails;\n health_info: string;\n last_error?: string;\n}\n\n// ============================================================================\n// Pegout Types\n// ============================================================================\n\n/**\n * Claimer-side pegout progress.\n * Source: btc-vault crates/vaultd/src/rpc/server/pegout_status.rs ClaimerPegoutStatus.\n */\nexport interface ClaimerPegoutStatus {\n /** Wire string from PegoutStatus enum. */\n status: string;\n failed: boolean;\n claim_txid: string;\n claimer_pubkey: string;\n assert_txid: string;\n /** Unix epoch seconds. */\n created_at: number;\n /** Unix epoch seconds. */\n updated_at: number;\n}\n\n/**\n * Challenger-side pegout progress.\n * Source: btc-vault crates/vaultd/src/rpc/server/pegout_status.rs ChallengerStatus.\n */\nexport interface ChallengerStatus {\n status: string;\n claim_txid: string;\n claimer_pubkey: string;\n assert_txid: string | null;\n challenge_assert_x_txid: string | null;\n challenge_assert_y_txid: string | null;\n nopayout_txid: string | null;\n created_at: number;\n updated_at: number;\n}\n\n/**\n * Pegout status response. Embedded by `batchGetPegoutStatus` per-result\n * envelopes. Mirrors btc-vault `GetPegoutStatusResponse`.\n */\nexport interface GetPegoutStatusResponse {\n pegin_txid: string;\n found: boolean;\n claimer: ClaimerPegoutStatus | null;\n challengers: ChallengerStatus[];\n}\n\n// ============================================================================\n// Batch Status Types (peginStatus + pegoutStatus)\n// ============================================================================\n\n/** Params for `batchGetPeginStatus`. */\nexport interface BatchGetPeginStatusParams {\n /** Up to MAX_BATCH_SIZE (50) txids per call. */\n pegin_txids: string[];\n}\n\n/** Per-pegin entry in a `batchGetPeginStatus` response. */\nexport interface BatchPeginStatusResult {\n pegin_txid: string;\n result: GetPeginStatusResponse | null;\n error: string | null;\n}\n\n/** Response from `batchGetPeginStatus`. Results are returned in request order. */\nexport interface BatchGetPeginStatusResponse {\n results: BatchPeginStatusResult[];\n}\n\n/** Params for `batchGetPegoutStatus`. */\nexport interface BatchGetPegoutStatusParams {\n pegin_txids: string[];\n}\n\n/** Per-vault entry in a `batchGetPegoutStatus` response. */\nexport interface BatchPegoutStatusResult {\n pegin_txid: string;\n result: GetPegoutStatusResponse | null;\n error: string | null;\n}\n\n/** Response from `batchGetPegoutStatus`. Results are returned in request order. */\nexport interface BatchGetPegoutStatusResponse {\n results: BatchPegoutStatusResult[];\n}\n\n/**\n * Maximum number of items per batch call. Mirrors the server-side\n * `MAX_BATCH_SIZE` in btc-vault (`crates/vaultd/src/rpc/server/vault_provider.rs:7`).\n * Callers must chunk requests larger than this.\n */\nexport const VP_BATCH_MAX_SIZE = 50;\n\n// ============================================================================\n// Error Codes\n// ============================================================================\n\n/**\n * JSON-RPC error codes returned by the vault provider.\n * Source: btc-vault `crates/vaultd/src/rpc/error.rs::RpcError::error_code`.\n */\nexport enum RpcErrorCode {\n PEGIN_NOT_FOUND = 4001,\n}\n"],"names":["JsonRpcError","code","message","source","data","JSON_RPC_ERROR_CODES","JSON_RPC_VERSION","DEFAULT_RETRY_ATTEMPTS","DEFAULT_RETRY_DELAY_MS","DEFAULT_MAX_RESPONSE_BYTES","UNCAPPED_TYPED_RESPONSE_METHODS","RETRYABLE_HTTP_STATUS_CODES","DEFAULT_RETRYABLE_METHODS","defaultRetryableFor","method","AUTH_EXPIRED_DATA_KIND","isAuthExpiredError","error","JsonRpcClient","config","__publicField","headers","token","params","signal","response","jsonResponse","responseText","readResponseTextWithLimit","rpcResponse","err","callerSignal","requestId","maxRetries","body","lastError","attempt","timeoutController","timeoutId","merged","mergeAbortSignals","delay","ms","resolve","reject","onAbort","a","b","controller","onAbortA","onAbortB","cleanup","maxBytes","contentLength","parsedContentLength","responseTooLargeError","reader","decoder","totalBytes","done","value","DaemonStatus","PRE_DEPOSITOR_SIGNATURES_STATES","POST_PAYOUT_SIGNATURE_STATUSES","VP_TRANSIENT_STATUSES","VP_TERMINAL_FAILURE_STATUSES","POST_WOTS_STATUSES","VP_BATCH_MAX_SIZE","RpcErrorCode"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-WA0LrDk1.cjs","sources":["../src/tbv/core/clients/vault-provider/json-rpc-client.ts","../src/tbv/core/clients/vault-provider/types.ts"],"sourcesContent":["/**\n * Generic JSON-RPC 2.0 HTTP Client\n *\n * Framework-agnostic client using `fetch()` — works in browsers and Node.js 18+.\n * Includes configurable retry policy and AbortSignal passthrough.\n */\n\nexport interface JsonRpcRequest<T = unknown> {\n jsonrpc: \"2.0\";\n method: string;\n params: T;\n id: number | string;\n}\n\nexport interface JsonRpcSuccessResponse<T = unknown> {\n jsonrpc: \"2.0\";\n result: T;\n id: number | string;\n}\n\nexport interface JsonRpcErrorResponse {\n jsonrpc: \"2.0\";\n error: {\n code: number;\n message: string;\n data?: unknown;\n };\n id: number | string;\n}\n\nexport type JsonRpcResponse<T = unknown> =\n | JsonRpcSuccessResponse<T>\n | JsonRpcErrorResponse;\n\n/**\n * Injects bearer tokens into requests for auth-gated methods, and is\n * notified on auth-expired responses so it can invalidate its cache.\n *\n * The `JsonRpcClient` is agnostic to which methods are auth-gated —\n * the provider's `getToken(method)` decides. Returning `null` means\n * \"no auth required for this method\"; the client then sends the\n * request with no `Authorization` header.\n */\nexport interface BearerTokenProvider {\n /**\n * Return the bearer token to inject for `method`, or `null` if the\n * method does not require auth.\n */\n getToken(method: string): Promise<string | null>;\n /**\n * Drop the cached token. Next call to `getToken` must re-acquire.\n * Called by the client on reactive-refresh-trigger responses.\n */\n invalidate(): void;\n}\n\nexport interface JsonRpcClientConfig {\n /** Base URL of the RPC service */\n baseUrl: string;\n /** Timeout in milliseconds per request attempt */\n timeout: number;\n /** Optional custom headers */\n headers?: Record<string, string>;\n /** Number of retry attempts for transient errors (default: 3) */\n retries?: number;\n /** Initial retry delay in milliseconds (default: 1000) */\n retryDelay?: number;\n /**\n * Maximum response body size, in bytes, for typed JSON-RPC calls.\n * `callRaw` intentionally returns the unparsed Response and is not capped here.\n * Default: 2 MiB.\n */\n maxResponseBytes?: number;\n /**\n * Predicate that decides which methods retry on transient errors.\n * Default retries only `getPeginStatus`, `batchGetPeginStatus`,\n * `batchGetPegoutStatus`, and `requestDepositorPresignTransactions`.\n * Write methods are not retried by default.\n */\n retryableFor?: (method: string) => boolean;\n /**\n * Per-request bearer-token source. A non-null return attaches\n * `Authorization: Bearer <token>`; `null` skips auth. `call`\n * additionally retries once on wire `auth_expired` (invalidate +\n * refetch + retry). `callRaw` skips reactive refresh.\n */\n tokenProvider?: BearerTokenProvider;\n}\n\n// \"wire\" = parsed from a JSON-RPC error envelope; \"local\" = timeout/network/parse failure.\nexport type JsonRpcErrorSource = \"wire\" | \"local\";\n\nexport class JsonRpcError extends Error {\n constructor(\n public code: number,\n message: string,\n /** \"wire\" for server-returned envelopes; \"local\" for SDK-side failures. */\n public source: JsonRpcErrorSource = \"local\",\n /** Structured data from the server `error.data` field, if any. */\n public data?: unknown,\n ) {\n super(message);\n this.name = \"JsonRpcError\";\n }\n}\n\nexport const JSON_RPC_ERROR_CODES = {\n TIMEOUT: -32000,\n NETWORK: -32001,\n /** VP proxy: request timed out at proxy level */\n PROXY_TIMEOUT: -32002,\n /** VP proxy: VP unreachable / DNS failure / response too large */\n PROXY_UNAVAILABLE: -32003,\n /** SDK client: response missing \"result\" field (malformed JSON-RPC) */\n INVALID_RESPONSE: -32700,\n /** SDK client: response body exceeded the configured byte limit */\n RESPONSE_TOO_LARGE: -32701,\n} as const;\n\n/** JSON-RPC protocol version */\nconst JSON_RPC_VERSION = \"2.0\" as const;\n\n/** Default number of retry attempts for transient errors */\nconst DEFAULT_RETRY_ATTEMPTS = 3;\n\n/** Default initial retry delay in milliseconds */\nconst DEFAULT_RETRY_DELAY_MS = 1000;\n\n/** Default maximum JSON-RPC response size for typed calls (2 MiB) */\nconst DEFAULT_MAX_RESPONSE_BYTES = 2 * 1024 * 1024;\n\n/**\n * TODO: Temporary typed-call exceptions for methods that currently return large\n * artifact payloads as JSON-RPC results.\n */\nconst UNCAPPED_TYPED_RESPONSE_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_requestDepositorClaimerArtifacts\",\n]);\n\n/** HTTP status codes that indicate transient server errors and are safe to retry */\nconst RETRYABLE_HTTP_STATUS_CODES: ReadonlySet<number> = new Set([\n 408, // Request Timeout\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n]);\n\n/** Default retry predicate: only retry read-only / idempotent methods */\nconst DEFAULT_RETRYABLE_METHODS: ReadonlySet<string> = new Set([\n \"vaultProvider_getPeginStatus\",\n \"vaultProvider_batchGetPeginStatus\",\n \"vaultProvider_batchGetPegoutStatus\",\n \"vaultProvider_requestDepositorPresignTransactions\",\n]);\n\nfunction defaultRetryableFor(method: string): boolean {\n return DEFAULT_RETRYABLE_METHODS.has(method);\n}\n\n/**\n * Token-expired marker the server emits in `error.data.kind`. When\n * present on a wire-origin error, the client invalidates its cached\n * token and retries the request once with a freshly-acquired bearer.\n *\n * Kept in sync with btc-vault's auth middleware. Absence of the marker\n * means the server does not support reactive refresh yet; we fall back\n * to proactive-only refresh via `BearerTokenProvider.getToken()` TTL\n * checks.\n */\nexport const AUTH_EXPIRED_DATA_KIND = \"auth_expired\";\n\nfunction isAuthExpiredError(error: unknown): boolean {\n if (!(error instanceof JsonRpcError)) return false;\n if (error.source !== \"wire\") return false;\n const data = error.data;\n if (data === null || typeof data !== \"object\") return false;\n const kind = (data as { kind?: unknown }).kind;\n return kind === AUTH_EXPIRED_DATA_KIND;\n}\n\n/**\n * Generic JSON-RPC 2.0 HTTP client with safe retry policy.\n */\nexport class JsonRpcClient {\n private baseUrl: string;\n private timeout: number;\n private headers: Record<string, string>;\n private requestId = 0;\n private retries: number;\n private retryDelay: number;\n private maxResponseBytes: number;\n private retryableFor: (method: string) => boolean;\n private tokenProvider?: BearerTokenProvider;\n\n constructor(config: JsonRpcClientConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/$/, \"\");\n this.timeout = config.timeout;\n this.headers = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n this.retries = config.retries ?? DEFAULT_RETRY_ATTEMPTS;\n this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;\n this.maxResponseBytes =\n config.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;\n if (!Number.isFinite(this.maxResponseBytes) || this.maxResponseBytes <= 0) {\n throw new Error(\"maxResponseBytes must be a positive finite number\");\n }\n this.retryableFor = config.retryableFor ?? defaultRetryableFor;\n this.tokenProvider = config.tokenProvider;\n }\n\n private async buildHeaders(method: string): Promise<Record<string, string>> {\n const headers: Record<string, string> = { ...this.headers };\n if (this.tokenProvider) {\n const token = await this.tokenProvider.getToken(method);\n if (token) {\n headers.Authorization = `Bearer ${token}`;\n }\n }\n return headers;\n }\n\n /**\n * Make a JSON-RPC request with optional retry for safe methods.\n *\n * If the request fails with a wire-origin `auth_expired` error and a\n * `tokenProvider` is configured, the client invalidates its cached\n * token and retries the request once with a freshly-acquired bearer.\n *\n * @param method - The RPC method name\n * @param params - The method parameters\n * @param signal - Optional AbortSignal for caller-controlled cancellation\n * @returns The result from the RPC method\n * @throws JsonRpcError if the RPC call fails\n */\n async call<TParams, TResult>(\n method: string,\n params: TParams,\n signal?: AbortSignal,\n ): Promise<TResult> {\n try {\n return await this.callOnce<TParams, TResult>(method, params, signal);\n } catch (error) {\n // The auth-expired retry fires for ALL methods, including mutating\n // ones. This is intentional and safe: the server's auth middleware\n // validates the bearer token BEFORE dispatching to the method\n // handler, so an `auth_expired` error means the handler never ran\n // and no state was mutated. Confirmed against btc-vault at\n // `crates/btc-auth/src/middleware/jsonrpc.rs` — token validation\n // is pre-handler only. The `retryableFor` guard on\n // HTTP-transient-error retries doesn't apply here because that\n // guard is about retrying after a request the server may have\n // started processing; auth_expired is categorically different.\n if (this.tokenProvider && isAuthExpiredError(error)) {\n this.tokenProvider.invalidate();\n return await this.callOnce<TParams, TResult>(method, params, signal);\n }\n throw error;\n }\n }\n\n private async callOnce<TParams, TResult>(\n method: string,\n params: TParams,\n signal: AbortSignal | undefined,\n ): Promise<TResult> {\n const response = await this.fetchWithRetry(method, params, signal);\n\n let jsonResponse: unknown;\n try {\n const responseText = UNCAPPED_TYPED_RESPONSE_METHODS.has(method)\n ? await response.text()\n : await readResponseTextWithLimit(response, this.maxResponseBytes);\n jsonResponse = JSON.parse(responseText);\n } catch (error) {\n if (error instanceof JsonRpcError) {\n throw error;\n }\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n \"Invalid JSON-RPC response: body is not valid JSON\",\n \"local\",\n );\n }\n\n if (\n jsonResponse === null ||\n typeof jsonResponse !== \"object\" ||\n Array.isArray(jsonResponse)\n ) {\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n `Invalid JSON-RPC response: expected an object, got ${typeof jsonResponse}`,\n \"local\",\n );\n }\n\n const rpcResponse = jsonResponse as Record<string, unknown>;\n\n if (\"error\" in rpcResponse && rpcResponse.error != null) {\n const err = rpcResponse.error as {\n code?: number;\n message?: string;\n data?: unknown;\n };\n throw new JsonRpcError(\n err.code ?? JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n err.message ?? \"Unknown RPC error\",\n \"wire\",\n err.data,\n );\n }\n\n if (!(\"result\" in rpcResponse)) {\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.INVALID_RESPONSE,\n `Invalid JSON-RPC response: missing \"result\" field`,\n \"local\",\n );\n }\n\n return rpcResponse.result as TResult;\n }\n\n /**\n * Make a JSON-RPC request returning the raw Response (unparsed body).\n *\n * Bearer tokens are injected identically to `call`. **Reactive refresh\n * is NOT performed here** — the response body may be unbounded (e.g.\n * claimer-artifact downloads), so the client refuses to parse it to\n * detect auth errors. Callers relying on token-expired retries for\n * large downloads must read the body themselves and re-invoke\n * `callRaw` after `tokenProvider.invalidate()`.\n */\n async callRaw<TParams>(\n method: string,\n params: TParams,\n signal?: AbortSignal,\n ): Promise<Response> {\n return this.fetchWithRetry(method, params, signal);\n }\n\n private async fetchWithRetry<TParams>(\n method: string,\n params: TParams,\n callerSignal?: AbortSignal,\n ): Promise<Response> {\n const requestId = ++this.requestId;\n const maxRetries = this.retryableFor(method) ? this.retries : 0;\n\n // jsonrpsee (Rust backend) expects params as an array (positional parameters)\n const request: JsonRpcRequest<TParams[]> = {\n jsonrpc: JSON_RPC_VERSION,\n method,\n params: [params],\n id: requestId,\n };\n\n const body = JSON.stringify(request);\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n // Merge caller signal with per-request timeout signal\n const timeoutController = new AbortController();\n const timeoutId = setTimeout(\n () => timeoutController.abort(),\n this.timeout,\n );\n\n const merged = callerSignal\n ? mergeAbortSignals(callerSignal, timeoutController.signal)\n : null;\n const signal = merged ? merged.signal : timeoutController.signal;\n\n try {\n // Build headers per-attempt so the token provider can return a\n // freshly-acquired bearer after a prior invalidate() on this\n // request (retry loop path) without plumbing state through.\n const headers = await this.buildHeaders(method);\n\n const response = await fetch(this.baseUrl, {\n method: \"POST\",\n headers,\n body,\n signal,\n });\n\n clearTimeout(timeoutId);\n merged?.cleanup();\n\n if (!response.ok) {\n const shouldRetry =\n attempt < maxRetries &&\n RETRYABLE_HTTP_STATUS_CODES.has(response.status);\n\n if (shouldRetry) {\n const delay = this.retryDelay * Math.pow(2, attempt);\n await this.sleep(delay, callerSignal);\n continue;\n }\n\n throw new Error(\n `HTTP error: ${response.status} ${response.statusText}`,\n );\n }\n\n return response;\n } catch (error) {\n clearTimeout(timeoutId);\n merged?.cleanup();\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Check if caller aborted (not our timeout)\n if (callerSignal?.aborted) {\n throw new Error(\"Request aborted\");\n }\n\n if (error instanceof Error && error.name === \"AbortError\") {\n if (attempt < maxRetries) {\n const delay = this.retryDelay * Math.pow(2, attempt);\n await this.sleep(delay, callerSignal);\n continue;\n }\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.TIMEOUT,\n `Request timeout after ${this.timeout}ms (${maxRetries + 1} attempts)`,\n \"local\",\n );\n }\n\n // Handle network errors (CORS, connection refused, etc.)\n if (error instanceof TypeError) {\n if (attempt < maxRetries) {\n const delay = this.retryDelay * Math.pow(2, attempt);\n await this.sleep(delay, callerSignal);\n continue;\n }\n throw new JsonRpcError(\n JSON_RPC_ERROR_CODES.NETWORK,\n `Network error: ${error.message} (${maxRetries + 1} attempts)`,\n \"local\",\n );\n }\n\n // Don't retry JSON-RPC errors (business logic errors)\n throw error;\n }\n }\n\n throw lastError || new Error(\"Unknown error after retries\");\n }\n\n private sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new Error(\"Request aborted\"));\n return;\n }\n const timeoutId = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timeoutId);\n reject(new Error(\"Request aborted\"));\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n }\n\n getBaseUrl(): string {\n return this.baseUrl;\n }\n}\n\ninterface MergedSignal {\n signal: AbortSignal;\n /** Remove listeners from the source signals. Call after the request completes. */\n cleanup: () => void;\n}\n\n/**\n * Merge two AbortSignals — the returned signal aborts if either input aborts.\n * Returns a cleanup function to remove listeners when the request completes\n * normally, preventing listener accumulation in long-lived polling flows.\n */\nfunction mergeAbortSignals(a: AbortSignal, b: AbortSignal): MergedSignal {\n if (a.aborted) return { signal: a, cleanup: () => {} };\n if (b.aborted) return { signal: b, cleanup: () => {} };\n\n const controller = new AbortController();\n const onAbortA = () => {\n b.removeEventListener(\"abort\", onAbortB);\n controller.abort();\n };\n const onAbortB = () => {\n a.removeEventListener(\"abort\", onAbortA);\n controller.abort();\n };\n a.addEventListener(\"abort\", onAbortA, { once: true });\n b.addEventListener(\"abort\", onAbortB, { once: true });\n\n const cleanup = () => {\n a.removeEventListener(\"abort\", onAbortA);\n b.removeEventListener(\"abort\", onAbortB);\n };\n\n return { signal: controller.signal, cleanup };\n}\n\nasync function readResponseTextWithLimit(\n response: Response,\n maxBytes: number,\n): Promise<string> {\n const contentLength = response.headers.get(\"content-length\");\n if (contentLength !== null) {\n const parsedContentLength = Number(contentLength);\n if (\n Number.isFinite(parsedContentLength) &&\n parsedContentLength > maxBytes\n ) {\n throw responseTooLargeError(maxBytes);\n }\n }\n\n if (!response.body) {\n return \"\";\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let totalBytes = 0;\n let responseText = \"\";\n\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n if (!value) continue;\n\n totalBytes += value.byteLength;\n if (totalBytes > maxBytes) {\n await reader.cancel();\n throw responseTooLargeError(maxBytes);\n }\n responseText += decoder.decode(value, { stream: true });\n }\n } finally {\n reader.releaseLock();\n }\n\n return responseText + decoder.decode();\n}\n\nfunction responseTooLargeError(maxBytes: number): JsonRpcError {\n return new JsonRpcError(\n JSON_RPC_ERROR_CODES.RESPONSE_TOO_LARGE,\n `JSON-RPC response exceeds maximum size of ${maxBytes} bytes`,\n \"local\",\n );\n}\n","/**\n * Type definitions for Vault Provider JSON-RPC API.\n *\n * These types match the `vaultProvider_*` RPC namespace defined by the\n * btc-vault daemon. They are the SDK's canonical copy of the VP protocol\n * contract, independent of any frontend framework.\n *\n * @see https://github.com/babylonlabs-io/btc-vault/blob/main/docs/pegin.md\n */\n\n// ============================================================================\n// Daemon Status\n// ============================================================================\n\n/**\n * Backend daemon status (vault provider database).\n * Source: btc-vault crates/vaultd/src/workers/claimer/mod.rs PegInStatus enum\n *\n * State flow (happy path):\n * PendingIngestion -> PendingDepositorWotsPK -> PendingBabeSetup -> PendingChallengerPresigning\n * -> PendingPeginSigsAvailability -> PendingPrePegInConfirmations\n * -> PendingDepositorSignatures -> PendingACKs -> PendingActivation\n * -> ActivatedPendingBroadcast -> Activated\n *\n * Branching / terminal states:\n * - IngestionRejected: terminal — ingestion permanently failed (e.g. malformed\n * Pre-PegIn, invalid HTLC outputs); reachable directly from PendingIngestion.\n * - Expired: activation timed out; non-terminal during the grace window\n * (RFC 003) — transitions to ExpiredCleanedUp or ExpiredInClaim.\n * - InvalidSigInContract: terminal — pegin input signature posted on\n * chain failed verification.\n * - AmlRejected: terminal — AML address screening rejected the pegin.\n * - ExpiredCleanedUp: terminal — grace window expired, per-pegin\n * artifacts deleted.\n * - ExpiredInClaim: terminal at the pegin-state-machine level; pegout-side\n * work continues on the pegout_tracking row.\n */\nexport enum DaemonStatus {\n PENDING_INGESTION = \"PendingIngestion\",\n PENDING_DEPOSITOR_WOTS_PK = \"PendingDepositorWotsPK\",\n PENDING_BABE_SETUP = \"PendingBabeSetup\",\n PENDING_CHALLENGER_PRESIGNING = \"PendingChallengerPresigning\",\n PENDING_PEGIN_SIGS_AVAILABILITY = \"PendingPeginSigsAvailability\",\n PENDING_PRE_PEGIN_CONFIRMATIONS = \"PendingPrePegInConfirmations\",\n PENDING_DEPOSITOR_SIGNATURES = \"PendingDepositorSignatures\",\n PENDING_ACKS = \"PendingACKs\",\n PENDING_ACTIVATION = \"PendingActivation\",\n ACTIVATED_PENDING_BROADCAST = \"ActivatedPendingBroadcast\",\n ACTIVATED = \"Activated\",\n EXPIRED = \"Expired\",\n INGESTION_REJECTED = \"IngestionRejected\",\n INVALID_SIG_IN_CONTRACT = \"InvalidSigInContract\",\n AML_REJECTED = \"AmlRejected\",\n EXPIRED_CLEANED_UP = \"ExpiredCleanedUp\",\n EXPIRED_IN_CLAIM = \"ExpiredInClaim\",\n}\n\n// ============================================================================\n// Status Groups\n// ============================================================================\n\n/**\n * States where the VP is still processing (no depositor action needed).\n * Excludes PENDING_DEPOSITOR_WOTS_PK (requires depositor action).\n */\nexport const PRE_DEPOSITOR_SIGNATURES_STATES: readonly DaemonStatus[] = [\n DaemonStatus.PENDING_INGESTION,\n DaemonStatus.PENDING_BABE_SETUP,\n DaemonStatus.PENDING_CHALLENGER_PRESIGNING,\n DaemonStatus.PENDING_PEGIN_SIGS_AVAILABILITY,\n DaemonStatus.PENDING_PRE_PEGIN_CONFIRMATIONS,\n];\n\n/** States after PendingDepositorSignatures where the depositor has no action. */\nconst POST_PAYOUT_SIGNATURE_STATUSES: readonly DaemonStatus[] = [\n DaemonStatus.PENDING_ACKS,\n DaemonStatus.PENDING_ACTIVATION,\n DaemonStatus.ACTIVATED_PENDING_BROADCAST,\n DaemonStatus.ACTIVATED,\n];\n\n/**\n * Statuses where no depositor action is needed (VP processing or already past\n * depositor interaction). Excludes PENDING_INGESTION and PENDING_DEPOSITOR_WOTS_PK.\n */\nexport const VP_TRANSIENT_STATUSES: ReadonlySet<DaemonStatus> = new Set([\n DaemonStatus.PENDING_BABE_SETUP,\n DaemonStatus.PENDING_CHALLENGER_PRESIGNING,\n DaemonStatus.PENDING_PEGIN_SIGS_AVAILABILITY,\n DaemonStatus.PENDING_PRE_PEGIN_CONFIRMATIONS,\n ...POST_PAYOUT_SIGNATURE_STATUSES,\n]);\n\n/**\n * Terminal VP statuses that represent failure outcomes — polling should\n * stop immediately with an error rather than wait for timeout.\n *\n * Mirrors the failure subset of the server-side terminals\n * (`allowed_transitions()` empty, see\n * `btc-vault/crates/vaultd/src/workers/claimer/mod.rs:230-242`).\n * `Activated` IS terminal on-chain but is the success outcome, so it is\n * intentionally excluded — a caller polling for an earlier state that\n * races straight to `Activated` should treat that as success-via-overshoot,\n * not failure. `Expired` is also excluded — under RFC 003 it is a\n * grace-window interim that transitions to `ExpiredCleanedUp` or\n * `ExpiredInClaim`. Callers that want to stop polling on any expiry\n * should check `status === DaemonStatus.EXPIRED ||\n * VP_TERMINAL_FAILURE_STATUSES.has(status)`.\n */\nexport const VP_TERMINAL_FAILURE_STATUSES: ReadonlySet<DaemonStatus> = new Set([\n DaemonStatus.INGESTION_REJECTED,\n DaemonStatus.INVALID_SIG_IN_CONTRACT,\n DaemonStatus.AML_REJECTED,\n DaemonStatus.EXPIRED_CLEANED_UP,\n DaemonStatus.EXPIRED_IN_CLAIM,\n]);\n\n/**\n * Statuses that come after WOTS key submission.\n * If the VP is already in one of these states, the WOTS key was already\n * submitted and we can skip.\n */\nexport const POST_WOTS_STATUSES: ReadonlySet<DaemonStatus> = new Set([\n ...VP_TRANSIENT_STATUSES,\n DaemonStatus.PENDING_DEPOSITOR_SIGNATURES,\n]);\n\n// ============================================================================\n// WOTS Types (needed by SubmitDepositorWotsKeyParams)\n// ============================================================================\n\n/**\n * WOTS configuration for a single block.\n * Matches Rust `babe::wots::Config` serde format.\n */\nexport interface WotsConfig {\n /** Digit bit-width (e.g. 4 → base-16 digits). */\n d: number;\n /** Number of message digits in this block. */\n n: number;\n /** Radix used for the checksum computation. */\n checksum_radix: number;\n}\n\n/**\n * A single block of WOTS public keys.\n * Chain values are arrays of byte values (matching Rust `[u8; 20]`).\n */\nexport interface WotsBlockPublicKey {\n config: WotsConfig;\n message_terminals: number[][];\n checksum_major_terminal: number[];\n checksum_minor_terminal: number[];\n}\n\n// ============================================================================\n// Request Parameter Types\n// ============================================================================\n\n/** Params for requesting the payout/claim/assert transactions to pre-sign. */\nexport interface RequestDepositorPresignTransactionsParams {\n pegin_txid: string;\n depositor_pk: string;\n}\n\n/** Params for submitting the depositor's WOTS public key to the VP. */\nexport interface SubmitDepositorWotsKeyParams {\n pegin_txid: string;\n depositor_pk: string;\n wots_public_keys: WotsBlockPublicKey[];\n}\n\n/** Per-challenger signatures for the depositor-as-claimer flow. */\nexport interface DepositorPreSigsPerChallenger {\n nopayout_signature: string;\n}\n\n/** Depositor-as-claimer pre-signatures (payout + per-challenger). */\nexport interface DepositorAsClaimerPresignatures {\n payout_signatures: ClaimerSignatures;\n per_challenger: Record<string, DepositorPreSigsPerChallenger>;\n}\n\n/** Params for submitting depositor pre-signatures including claimer presignatures. */\nexport interface SubmitDepositorPresignaturesParams {\n pegin_txid: string;\n depositor_pk: string;\n signatures: Record<string, ClaimerSignatures>;\n depositor_claimer_presignatures: DepositorAsClaimerPresignatures;\n}\n\n/** Payout signatures per claimer. */\nexport interface ClaimerSignatures {\n payout_signature: string;\n}\n\n/** Params for requesting BaBe DecryptorArtifacts from the VP. */\nexport interface RequestDepositorClaimerArtifactsParams {\n pegin_txid: string;\n depositor_pk: string;\n}\n\n/** Params for querying pegin status. Either pegin_txid or vault_id must be provided. */\nexport type GetPeginStatusParams =\n | { pegin_txid: string; vault_id?: never }\n | { vault_id: string; pegin_txid?: never };\n\n// ============================================================================\n// Response Types\n// ============================================================================\n\n/** A raw Bitcoin transaction with its hex encoding. */\nexport interface TransactionData {\n tx_hex: string;\n}\n\n/** Set of transactions the depositor must pre-sign for a single claimer. */\nexport interface ClaimerTransactions {\n claimer_pubkey: string;\n claim_tx: TransactionData;\n assert_tx: TransactionData;\n payout_tx: TransactionData;\n payout_psbt: string;\n}\n\n/** Per-segment connector data for ChallengeAssert inputs. */\nexport interface ChallengeAssertConnectorData {\n wots_pks_json: string;\n gc_wots_keys_json: string;\n}\n\n/** Challenger-specific transactions and signing data for the depositor graph. */\nexport interface PresignDataPerChallenger {\n challenger_pubkey: string;\n challenge_assert_x_tx: TransactionData;\n challenge_assert_y_tx: TransactionData;\n nopayout_tx: TransactionData;\n nopayout_psbt: string;\n challenge_assert_connectors: ChallengeAssertConnectorData[];\n output_label_hashes: string[];\n}\n\n/** Depositor-as-claimer TxGraph transactions. */\nexport interface DepositorGraphTransactions {\n claim_tx: TransactionData;\n assert_tx: TransactionData;\n payout_tx: TransactionData;\n payout_psbt: string;\n challenger_presign_data: PresignDataPerChallenger[];\n offchain_params_version: number;\n}\n\n/** Response from `requestDepositorPresignTransactions`. */\nexport interface RequestDepositorPresignTransactionsResponse {\n txs: ClaimerTransactions[];\n depositor_graph: DepositorGraphTransactions;\n}\n\n/** BaBe garbled-circuit session data for a single challenger. */\nexport interface BaBeSessionData {\n decryptor_artifacts_hex: string;\n}\n\n/** Response from `requestDepositorClaimerArtifacts`. */\nexport interface RequestDepositorClaimerArtifactsResponse {\n tx_graph_json: string;\n verifying_key_hex: string;\n babe_sessions: Record<string, BaBeSessionData>;\n}\n\n/** Progress tracker for a multi-challenger operation. */\nexport interface ChallengerProgress {\n total_challengers: number;\n completed_challengers: number;\n completed_challenger_pubkeys: string[];\n pending_challenger_pubkeys: string[];\n}\n\nexport type GcDataProgress = ChallengerProgress;\nexport type AckCollectionProgress = ChallengerProgress;\n\n/** Extended presigning progress with all 3 concurrent phases. */\nexport interface PresigningProgress extends ChallengerProgress {\n depositor_graph_created?: boolean;\n vk_challenger_presigning_completed?: number;\n vk_challenger_presigning_total?: number;\n}\n\n/** Detailed progress breakdown for an in-progress pegin. */\nexport interface PeginProgressDetails {\n gc_data?: GcDataProgress;\n presigning?: PresigningProgress;\n ack_collection?: AckCollectionProgress;\n claimer_graphs?: ClaimerGraphStatus[];\n}\n\n/** Per-claimer graph status (challenger perspective). */\nexport interface ClaimerGraphStatus {\n claimer_pubkey: string;\n presigned: boolean;\n}\n\n/** Response from `getPeginStatus`. */\nexport interface GetPeginStatusResponse {\n pegin_txid: string;\n status: string;\n progress: PeginProgressDetails;\n health_info: string;\n last_error?: string;\n}\n\n// ============================================================================\n// Pegout Types\n// ============================================================================\n\n/**\n * Claimer-side pegout progress.\n * Source: btc-vault crates/vaultd/src/rpc/server/pegout_status.rs ClaimerPegoutStatus.\n */\nexport interface ClaimerPegoutStatus {\n /** Wire string from PegoutStatus enum. */\n status: string;\n failed: boolean;\n claim_txid: string;\n claimer_pubkey: string;\n assert_txid: string;\n /** Unix epoch seconds. */\n created_at: number;\n /** Unix epoch seconds. */\n updated_at: number;\n}\n\n/**\n * Challenger-side pegout progress.\n * Source: btc-vault crates/vaultd/src/rpc/server/pegout_status.rs ChallengerStatus.\n */\nexport interface ChallengerStatus {\n status: string;\n claim_txid: string;\n claimer_pubkey: string;\n assert_txid: string | null;\n challenge_assert_x_txid: string | null;\n challenge_assert_y_txid: string | null;\n nopayout_txid: string | null;\n created_at: number;\n updated_at: number;\n}\n\n/**\n * Pegout status response. Embedded by `batchGetPegoutStatus` per-result\n * envelopes. Mirrors btc-vault `GetPegoutStatusResponse`.\n */\nexport interface GetPegoutStatusResponse {\n pegin_txid: string;\n found: boolean;\n claimer: ClaimerPegoutStatus | null;\n challengers: ChallengerStatus[];\n}\n\n// ============================================================================\n// Batch Status Types (peginStatus + pegoutStatus)\n// ============================================================================\n\n/** Params for `batchGetPeginStatus`. */\nexport interface BatchGetPeginStatusParams {\n /** Up to MAX_BATCH_SIZE (50) txids per call. */\n pegin_txids: string[];\n}\n\n/** Per-pegin entry in a `batchGetPeginStatus` response. */\nexport interface BatchPeginStatusResult {\n pegin_txid: string;\n result: GetPeginStatusResponse | null;\n error: string | null;\n}\n\n/** Response from `batchGetPeginStatus`. Results are returned in request order. */\nexport interface BatchGetPeginStatusResponse {\n results: BatchPeginStatusResult[];\n}\n\n/** Params for `batchGetPegoutStatus`. */\nexport interface BatchGetPegoutStatusParams {\n pegin_txids: string[];\n}\n\n/** Per-vault entry in a `batchGetPegoutStatus` response. */\nexport interface BatchPegoutStatusResult {\n pegin_txid: string;\n result: GetPegoutStatusResponse | null;\n error: string | null;\n}\n\n/** Response from `batchGetPegoutStatus`. Results are returned in request order. */\nexport interface BatchGetPegoutStatusResponse {\n results: BatchPegoutStatusResult[];\n}\n\n/**\n * Maximum number of items per batch call. Mirrors the server-side\n * `MAX_BATCH_SIZE` in btc-vault (`crates/vaultd/src/rpc/server/vault_provider.rs:7`).\n * Callers must chunk requests larger than this.\n */\nexport const VP_BATCH_MAX_SIZE = 50;\n\n// ============================================================================\n// Error Codes\n// ============================================================================\n\n/**\n * JSON-RPC error codes returned by the vault provider.\n * Source: btc-vault `crates/vaultd/src/rpc/error.rs::RpcError::error_code`.\n */\nexport enum RpcErrorCode {\n PEGIN_NOT_FOUND = 4001,\n}\n"],"names":["JsonRpcError","code","message","source","data","JSON_RPC_ERROR_CODES","JSON_RPC_VERSION","DEFAULT_RETRY_ATTEMPTS","DEFAULT_RETRY_DELAY_MS","DEFAULT_MAX_RESPONSE_BYTES","UNCAPPED_TYPED_RESPONSE_METHODS","RETRYABLE_HTTP_STATUS_CODES","DEFAULT_RETRYABLE_METHODS","defaultRetryableFor","method","AUTH_EXPIRED_DATA_KIND","isAuthExpiredError","error","JsonRpcClient","config","__publicField","headers","token","params","signal","response","jsonResponse","responseText","readResponseTextWithLimit","rpcResponse","err","callerSignal","requestId","maxRetries","body","lastError","attempt","timeoutController","timeoutId","merged","mergeAbortSignals","delay","ms","resolve","reject","onAbort","a","b","controller","onAbortA","onAbortB","cleanup","maxBytes","contentLength","parsedContentLength","responseTooLargeError","reader","decoder","totalBytes","done","value","DaemonStatus","PRE_DEPOSITOR_SIGNATURES_STATES","POST_PAYOUT_SIGNATURE_STATUSES","VP_TRANSIENT_STATUSES","VP_TERMINAL_FAILURE_STATUSES","POST_WOTS_STATUSES","VP_BATCH_MAX_SIZE","RpcErrorCode"],"mappings":"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"}
@@ -1,15 +0,0 @@
1
- const E = /^[0-9a-fA-F]+$/, a = /^[0-9a-fA-F]{64}$/, s = /^[a-zA-Z0-9]{25,90}$/, _ = [
2
- "76a914",
3
- "a914",
4
- "0014",
5
- "0020",
6
- "5120"
7
- ], A = 1000000n;
8
- export {
9
- s as B,
10
- E as H,
11
- _ as K,
12
- A as M,
13
- a as T
14
- };
15
- //# sourceMappingURL=validation-CxqROCno.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validation-CxqROCno.js","sources":["../src/tbv/core/utils/validation.ts"],"sourcesContent":["/**\n * Shared validation constants for Bitcoin-related input sanitization.\n *\n * These are used across mempool API clients, broadcast services, and\n * transaction construction to enforce consistent format checks.\n */\n\n/** Non-empty string of hexadecimal characters (case-insensitive). */\nexport const HEX_RE = /^[0-9a-fA-F]+$/;\n\n/** Bitcoin txid: exactly 64 hex characters (32 bytes). */\nexport const TXID_RE = /^[0-9a-fA-F]{64}$/;\n\n/**\n * Bitcoin address format gate: 25–90 alphanumeric characters.\n * Covers legacy (P2PKH/P2SH), bech32 (P2WPKH/P2WSH), bech32m (P2TR),\n * and regtest addresses (bcrt1... which are 62–64 chars for 32-byte witness programs).\n * Upper bound of 90 provides headroom for future address formats.\n * This is a format gate to prevent path-traversal — not full address validation.\n */\nexport const BITCOIN_ADDRESS_RE = /^[a-zA-Z0-9]{25,90}$/;\n\n/**\n * Known Bitcoin scriptPubKey prefixes:\n * - P2PKH: 76a914...88ac (25 bytes)\n * - P2SH: a914...87 (23 bytes)\n * - P2WPKH: 0014... (22 bytes)\n * - P2WSH: 0020... (34 bytes)\n * - P2TR: 5120... (34 bytes)\n */\nexport const KNOWN_SCRIPT_PREFIXES = [\n \"76a914\",\n \"a914\",\n \"0014\",\n \"0020\",\n \"5120\",\n] as const;\n\n/**\n * Upper bound on the implied miner fee (0.01 BTC = 1,000,000 sats).\n * Catches inflated input values from a compromised mempool API — if inputs are\n * grossly overstated the implied fee becomes unreasonably large. The April 2024\n * Runes spike saw ~450 sat/vB; at 500 vB that's ~225k sats, well under this cap.\n */\nexport const MAX_REASONABLE_FEE_SATS = 1_000_000n;\n"],"names":["HEX_RE","TXID_RE","BITCOIN_ADDRESS_RE","KNOWN_SCRIPT_PREFIXES","MAX_REASONABLE_FEE_SATS"],"mappings":"AAQO,MAAMA,IAAS,kBAGTC,IAAU,qBASVC,IAAqB,wBAUrBC,IAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQaC,IAA0B;"}
@@ -1,2 +0,0 @@
1
- "use strict";const E=/^[0-9a-fA-F]+$/,_=/^[0-9a-fA-F]{64}$/,R=/^[a-zA-Z0-9]{25,90}$/,S=["76a914","a914","0014","0020","5120"],A=1000000n;exports.BITCOIN_ADDRESS_RE=R;exports.HEX_RE=E;exports.KNOWN_SCRIPT_PREFIXES=S;exports.MAX_REASONABLE_FEE_SATS=A;exports.TXID_RE=_;
2
- //# sourceMappingURL=validation-u8W7Lp2x.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validation-u8W7Lp2x.cjs","sources":["../src/tbv/core/utils/validation.ts"],"sourcesContent":["/**\n * Shared validation constants for Bitcoin-related input sanitization.\n *\n * These are used across mempool API clients, broadcast services, and\n * transaction construction to enforce consistent format checks.\n */\n\n/** Non-empty string of hexadecimal characters (case-insensitive). */\nexport const HEX_RE = /^[0-9a-fA-F]+$/;\n\n/** Bitcoin txid: exactly 64 hex characters (32 bytes). */\nexport const TXID_RE = /^[0-9a-fA-F]{64}$/;\n\n/**\n * Bitcoin address format gate: 25–90 alphanumeric characters.\n * Covers legacy (P2PKH/P2SH), bech32 (P2WPKH/P2WSH), bech32m (P2TR),\n * and regtest addresses (bcrt1... which are 62–64 chars for 32-byte witness programs).\n * Upper bound of 90 provides headroom for future address formats.\n * This is a format gate to prevent path-traversal — not full address validation.\n */\nexport const BITCOIN_ADDRESS_RE = /^[a-zA-Z0-9]{25,90}$/;\n\n/**\n * Known Bitcoin scriptPubKey prefixes:\n * - P2PKH: 76a914...88ac (25 bytes)\n * - P2SH: a914...87 (23 bytes)\n * - P2WPKH: 0014... (22 bytes)\n * - P2WSH: 0020... (34 bytes)\n * - P2TR: 5120... (34 bytes)\n */\nexport const KNOWN_SCRIPT_PREFIXES = [\n \"76a914\",\n \"a914\",\n \"0014\",\n \"0020\",\n \"5120\",\n] as const;\n\n/**\n * Upper bound on the implied miner fee (0.01 BTC = 1,000,000 sats).\n * Catches inflated input values from a compromised mempool API — if inputs are\n * grossly overstated the implied fee becomes unreasonably large. The April 2024\n * Runes spike saw ~450 sat/vB; at 500 vB that's ~225k sats, well under this cap.\n */\nexport const MAX_REASONABLE_FEE_SATS = 1_000_000n;\n"],"names":["HEX_RE","TXID_RE","BITCOIN_ADDRESS_RE","KNOWN_SCRIPT_PREFIXES","MAX_REASONABLE_FEE_SATS"],"mappings":"aAQO,MAAMA,EAAS,iBAGTC,EAAU,oBASVC,EAAqB,uBAUrBC,EAAwB,CACnC,SACA,OACA,OACA,OACA,MACF,EAQaC,EAA0B"}
@@ -1,2 +0,0 @@
1
- "use strict";const S=require("@babylonlabs-io/babylon-tbv-rust-wasm"),d=require("buffer"),x=require("bitcoinjs-lib"),_=require("./fundPeginTransaction-BLD8FRL9.cjs"),c=require("./bitcoin-CHfKAhcI.cjs"),p=require("./constants-BqU1Uz15.cjs"),F=require("@bitcoin-js/tiny-secp256k1-asmjs");function M(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const o=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,o.get?o:{enumerable:!0,get:()=>e[n]})}}return t.default=e,Object.freeze(t)}const q=M(F);async function K(e,t){const n=t.pegInAmounts.length;if(e.htlcValues.length!==n)throw new Error(`WASM Pre-PegIn returned ${e.htlcValues.length} HTLC value(s), expected ${n} (one per requested deposit).`);if(e.peginAmounts.length!==n||e.htlcScriptPubKeys.length!==n||e.htlcAddresses.length!==n)throw new Error(`WASM Pre-PegIn returned mismatched array lengths (htlcValues=${e.htlcValues.length}, peginAmounts=${e.peginAmounts.length}, htlcScriptPubKeys=${e.htlcScriptPubKeys.length}, htlcAddresses=${e.htlcAddresses.length}); expected ${n} each.`);if(e.depositorClaimValue<=0n)throw new Error(`WASM Pre-PegIn returned non-positive depositorClaimValue ${e.depositorClaimValue}; expected > 0.`);const o=await S.computeMinClaimValue(t.vaultCoreVersion,t.numLocalChallengers,t.universalChallengerPubkeys.length,t.councilQuorum,t.councilSize,t.feeRate);if(e.depositorClaimValue!==o)throw new Error(`WASM Pre-PegIn depositorClaimValue ${e.depositorClaimValue} does not match the independently computed minimum claim value ${o} (vaultCoreVersion=${t.vaultCoreVersion}, numLocalChallengers=${t.numLocalChallengers}, numUniversalChallengers=${t.universalChallengerPubkeys.length}, councilQuorum=${t.councilQuorum}, councilSize=${t.councilSize}, feeRate=${t.feeRate}).`);const r=await S.peginP2aAnchorOutput(t.vaultCoreVersion),i=(r==null?void 0:r.value)??0n,s=await S.computeMinPeginFee(t.vaultCoreVersion,t.vaultKeeperPubkeys.length,t.universalChallengerPubkeys.length,t.minPeginFeeRate),u=s+i,h=t.minPeginFeeRate*_.MAX_REASONABLE_PEGIN_VBYTES;for(let a=0;a<n;a++){const P=t.pegInAmounts[a],f=e.peginAmounts[a],g=e.htlcValues[a];if(f!==P)throw new Error(`WASM Pre-PegIn peginAmount[${a}] ${f} does not match the requested amount ${P}; refusing to build a tx whose recorded amount differs from the depositor's request.`);if(f<=0n)throw new Error(`WASM Pre-PegIn peginAmount[${a}] is non-positive (${f}); expected > 0.`);if(g<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${a}] is non-positive (${g}); expected > 0.`);const l=g-f-e.depositorClaimValue;if(l<=0n)throw new Error(`WASM Pre-PegIn htlcValue[${a}] ${g} does not strictly cover peginAmount ${f} + depositorClaimValue ${e.depositorClaimValue} + a PegIn reserve (implied reserve ${l}).`);if(l>h)throw new Error(`WASM Pre-PegIn implied reserve for HTLC[${a}] (${l} sat) exceeds the plausibility cap ${h} sat (minPeginFeeRate=${t.minPeginFeeRate} × ${_.MAX_REASONABLE_PEGIN_VBYTES} vbytes); htlcValue ${g} appears grossly inflated.`);if(l!==u)throw new Error(`WASM Pre-PegIn htlcValue[${a}] ${g} implies a PegIn fee+anchor reserve of ${l} sat, expected exactly ${u} sat (minPeginFee ${s} + p2aAnchor ${i} for vaultCoreVersion ${t.vaultCoreVersion}, vaultKeepers=${t.vaultKeeperPubkeys.length}, universalChallengers=${t.universalChallengerPubkeys.length}, minPeginFeeRate=${t.minPeginFeeRate}).`)}return s}function X(e,t,n){if(e.length<t.length)throw new Error(`Encoded Pre-PegIn tx has ${e.length} output(s), fewer than the ${t.length} HTLC output(s) the cross-check validated.`);for(let o=0;o<t.length;o++){const r=BigInt(e[o].value);if(r!==t[o])throw new Error(`Encoded Pre-PegIn HTLC output[${o}] value ${r} does not match the cross-checked htlcValue ${t[o]}; the funded/signed tx would not pay the validated amount.`);const i=e[o].script.toString("hex").toLowerCase(),s=n[o].toLowerCase();if(i!==s)throw new Error(`Encoded Pre-PegIn HTLC output[${o}] scriptPubKey ${i} does not match the cross-checked htlcScriptPubKey ${s}.`)}}const I=64,W=/^[0-9a-fA-F]+$/;async function z(e){const t=T(e.authAnchorHash),n=await S.createPrePeginTransaction({txGraphVersion:e.vaultCoreVersion,depositorPubkey:e.depositorPubkey,vaultProviderPubkey:e.vaultProviderPubkey,vaultKeeperPubkeys:e.vaultKeeperPubkeys,universalChallengerPubkeys:e.universalChallengerPubkeys,hashlocks:[...e.hashlocks],timelockRefund:e.timelockRefund,pegInAmounts:[...e.pegInAmounts],feeRate:e.feeRate,minPeginFeeRate:e.minPeginFeeRate,numLocalChallengers:e.numLocalChallengers,councilQuorum:e.councilQuorum,councilSize:e.councilSize,network:e.network,authAnchorHash:t}),o=await K(n,e),r=_.parseUnfundedWasmTransaction(n.txHex);X(r.outputs,n.htlcValues,n.htlcScriptPubKeys);const i=r.outputs.reduce((u,h)=>u+BigInt(h.value),0n),s=t!==void 0?n.htlcValues.length:null;return{psbtHex:n.txHex,totalOutputValue:i,htlcValues:n.htlcValues,htlcScriptPubKeys:n.htlcScriptPubKeys,htlcAddresses:n.htlcAddresses,peginAmounts:n.peginAmounts,depositorClaimValue:n.depositorClaimValue,authAnchorVout:s,minPeginFee:o}}function T(e){if(e===void 0)return;const t=e.startsWith("0x")||e.startsWith("0X")?e.slice(2):e;if(t.length!==I||!W.test(t))throw new Error(`authAnchorHash must be 32-byte hex (${I} chars, no 0x prefix); got length ${t.length}`);return t.toLowerCase()}async function Y(e){const t=await S.buildPeginTxFromPrePegin({txGraphVersion:e.prePeginParams.vaultCoreVersion,depositorPubkey:e.prePeginParams.depositorPubkey,vaultProviderPubkey:e.prePeginParams.vaultProviderPubkey,vaultKeeperPubkeys:e.prePeginParams.vaultKeeperPubkeys,universalChallengerPubkeys:e.prePeginParams.universalChallengerPubkeys,hashlocks:[...e.prePeginParams.hashlocks],timelockRefund:e.prePeginParams.timelockRefund,pegInAmounts:[...e.prePeginParams.pegInAmounts],feeRate:e.prePeginParams.feeRate,minPeginFeeRate:e.prePeginParams.minPeginFeeRate,numLocalChallengers:e.prePeginParams.numLocalChallengers,councilQuorum:e.prePeginParams.councilQuorum,councilSize:e.prePeginParams.councilSize,network:e.prePeginParams.network,authAnchorHash:T(e.prePeginParams.authAnchorHash)},e.timelockPegin,e.fundedPrePeginTxHex,e.htlcVout);return await Q(t,e),{txHex:t.txHex,txid:t.txid,vaultScriptPubKey:t.vaultScriptPubKey,vaultValue:t.vaultValue}}const D=2,G=1;async function Q(e,t){const n=t.prePeginParams.vaultCoreVersion;await S.validatePeginP2aAnchor(n,e.txHex);const o=await S.peginP2aAnchorOutput(n),r=D+(o?1:0),i=x.Transaction.fromHex(c.stripHexPrefix(e.txHex));if(i.ins.length!==1)throw new Error(`PegIn tx has ${i.ins.length} input(s), expected exactly 1 (the Pre-PegIn HTLC outpoint).`);const s=x.Transaction.fromHex(c.stripHexPrefix(t.fundedPrePeginTxHex)).getId(),u=c.uint8ArrayToHex(new Uint8Array(i.ins[0].hash).slice().reverse());if(u!==s)throw new Error(`PegIn input spends txid ${u}, expected the funded Pre-PegIn ${s}.`);if(i.ins[0].index!==t.htlcVout)throw new Error(`PegIn input spends Pre-PegIn output ${i.ins[0].index}, expected the requested HTLC vout ${t.htlcVout}.`);if(i.outs.length!==r)throw new Error(`PegIn tx has ${i.outs.length} output(s), expected exactly ${r} for vaultCoreVersion ${n} (vault + depositor claim${o?" + P2A anchor":""}).`);const h=t.prePeginParams.pegInAmounts[t.htlcVout];if(e.vaultValue!==h)throw new Error(`PegIn vault output value ${e.vaultValue} does not match the requested peg-in amount ${h} for HTLC ${t.htlcVout}; refusing to sign a vault that locks a different amount than requested.`);const a=i.outs[0];if(BigInt(a.value)!==e.vaultValue)throw new Error(`Encoded PegIn vault output value ${a.value} does not match the WASM-reported vaultValue ${e.vaultValue}.`);const P=a.script.toString("hex"),f=c.stripHexPrefix(e.vaultScriptPubKey).toLowerCase();if(P.toLowerCase()!==f)throw new Error(`Encoded PegIn vault output scriptPubKey ${P} does not match the WASM-reported vaultScriptPubKey ${e.vaultScriptPubKey}.`);const g=i.getId();if(g!==c.stripHexPrefix(e.txid).toLowerCase())throw new Error(`Encoded PegIn txid ${g} does not match the WASM-reported txid ${e.txid}.`);const l=await S.computeMinClaimValue(n,t.prePeginParams.numLocalChallengers,t.prePeginParams.universalChallengerPubkeys.length,t.prePeginParams.councilQuorum,t.prePeginParams.councilSize,t.prePeginParams.feeRate),w=i.outs[G];if(BigInt(w.value)!==l)throw new Error(`Encoded PegIn depositor-claim output value ${w.value} does not match the independently computed claim value ${l} for vaultCoreVersion ${n}.`);const y=Z(t.prePeginParams.depositorPubkey);if(!w.script.equals(y))throw new Error(`Encoded PegIn depositor-claim output scriptPubKey ${w.script.toString("hex")} does not pay to the depositor's claim script (expected ${y.toString("hex")}).`)}function Z(e){const t=x.script.compile([d.Buffer.from(c.hexToUint8Array(e)),x.opcodes.OP_CHECKSIG]),{output:n}=x.payments.p2tr({internalPubkey:d.Buffer.from(S.tapInternalPubkey),scriptTree:{output:t}});if(!n)throw new Error("Failed to derive the depositor-claim P2TR scriptPubKey for PegIn output validation");return n}async function N(e){const t=await S.createPayoutConnector({txGraphVersion:e.vaultCoreVersion,depositor:e.depositor,vaultProvider:e.vaultProvider,vaultKeepers:e.vaultKeepers,universalChallengers:e.universalChallengers,timelockPegin:e.timelockPegin},e.network);return{payoutScript:t.payoutScript,taprootScriptHash:t.taprootScriptHash,scriptPubKey:t.scriptPubKey,address:t.address,payoutControlBlock:t.payoutControlBlock}}const j=500,J=55,V=0xffffffffn,O=32,ee=34;function te(e){if(typeof e.protocolFeeRate!="bigint"||e.protocolFeeRate<=0n||e.protocolFeeRate>V)throw new Error(`protocolFeeRate must be in [1, ${V}] sat/vB, got ${e.protocolFeeRate}`);for(const[t,n]of[["keepers",e.numVaultKeepers],["challengers",e.numUniversalChallengers]])if(!Number.isInteger(n)||n<1||n>O)throw new Error(`Participant count for ${t} (${n}) is outside the device range [1, ${O}].`);if(!Number.isInteger(e.councilSize)||e.councilSize<1)throw new Error(`councilSize must be an integer >= 1, got ${e.councilSize}`)}async function ne(e,t){const{implicitFeeSats:n,out0Len:o,out1Len:r}=t,i=e.numVaultKeepers+e.numUniversalChallengers,s=BigInt(n),u=Math.max(0,o-ee),h=j+J*i+u,a=e.protocolFeeRate*BigInt(h);if(s>a)throw new Error(`Payout implicit fee ${n} sats exceeds the safety cap of ${a} sats (${e.protocolFeeRate} sat/vB x ${h} vB for ${i} participants); refusing to sign payout.`);const P=await S.computePayoutFeeFloor(e.vaultCoreVersion,e.numVaultKeepers,e.numUniversalChallengers,e.numVaultKeepers,e.councilSize,o,r,e.protocolFeeRate);if(s<P)throw new Error(`Payout implicit fee ${n} sats is below the floor of ${P} sats (the smallest fee any known vault-provider build produces for this shape); refusing to sign payout.`)}const k=3;async function re(e){const t={vaultCoreVersion:e.vaultCoreVersion,numVaultKeepers:e.vaultKeeperBtcPubkeys.length,numUniversalChallengers:e.universalChallengerBtcPubkeys.length,councilSize:e.councilSize,protocolFeeRate:e.protocolFeeRate};te(t);const n=x.Transaction.fromHex(c.stripHexPrefix(e.payoutTxHex)),o=x.Transaction.fromHex(c.stripHexPrefix(e.peginTxHex)),r=x.Transaction.fromHex(c.stripHexPrefix(e.assertTxHex));if(n.ins.length!==p.DEPOSITOR_PAYOUT_INPUT_COUNT)throw new Error(`Payout transaction must have exactly ${p.DEPOSITOR_PAYOUT_INPUT_COUNT} inputs, got ${n.ins.length}`);const i=H(n.ins[0],0,o,"PegIn",p.PEGIN_VAULT_OUTPUT_INDEX),s=H(n.ins[1],1,r,"Assert",p.ASSERT_PAYOUT_OUTPUT_INDEX),{out0Len:u,out1Len:h}=ie(n,i.value,e),a=i.value+s.value;let P=0;for(const l of n.outs)P+=l.value;if(P>a)throw new Error(`Payout outputs (${P} sats) exceed inputs (${a} sats); invalid transaction.`);const f=a-P;await ne(t,{implicitFeeSats:f,out0Len:u,out1Len:h});const g=await N({vaultCoreVersion:e.vaultCoreVersion,depositor:e.depositorBtcPubkey,vaultProvider:e.vaultProviderBtcPubkey,vaultKeepers:e.vaultKeeperBtcPubkeys,universalChallengers:e.universalChallengerBtcPubkeys,timelockPegin:e.timelockPegin,network:e.network});return{psbtHex:oe(n,i,s,g)}}function H(e,t,n,o,r){const i=c.uint8ArrayToHex(new Uint8Array(e.hash).slice().reverse()),s=n.getId();if(i!==s||e.index!==r)throw new Error(`Input ${t} must spend ${o}:${r}. Expected ${s}:${r}, got ${i}:${e.index}`);const u=n.outs[e.index];if(!u)throw new Error(`Previous output not found for input ${t} (txid: ${i}, index: ${e.index})`);return u}function oe(e,t,n,o){const r=new x.Psbt;r.setVersion(e.version),r.setLocktime(e.locktime);const[i,s]=e.ins;r.addInput({hash:i.hash,index:i.index,sequence:i.sequence,witnessUtxo:{script:t.script,value:t.value},tapLeafScript:[{leafVersion:c.TAPSCRIPT_LEAF_VERSION,script:d.Buffer.from(c.hexToUint8Array(o.payoutScript)),controlBlock:d.Buffer.from(c.hexToUint8Array(o.payoutControlBlock))}],tapInternalKey:d.Buffer.from(S.tapInternalPubkey)}),r.addInput({hash:s.hash,index:s.index,sequence:s.sequence,witnessUtxo:{script:n.script,value:n.value}});for(const u of e.outs)r.addOutput({script:u.script,value:u.value});return r.toHex()}function ie(e,t,n){const{claimerBtcPubkey:o,vaultProviderBtcPubkey:r,depositorBtcPubkey:i,vaultKeeperBtcPubkeys:s,registeredPayoutScriptPubKey:u,commissionBps:h}=n;if(!c.isValidHex(u))throw new Error("Invalid registeredPayoutScriptPubKey: not valid hex");const a=c.stripHexPrefix(o).toLowerCase(),P=c.stripHexPrefix(r).toLowerCase(),f=c.stripHexPrefix(i).toLowerCase(),g=s.map(b=>c.stripHexPrefix(b).toLowerCase());let l,w,y;if(a===P)l="vp-claimer",w=p.VP_CLAIMER_PAYOUT_OUTPUT_COUNT,y=c.stripHexPrefix(u);else if(a===f)l="depositor-as-claimer",w=p.NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT,y=c.stripHexPrefix(u);else if(g.includes(a))l="vk-claimer",w=p.NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT,y=c.stripHexPrefix(c.deriveBip86ScriptPubKeyHex(a));else throw new Error(`Unknown claimer pubkey ${a}: not VP, depositor, or a registered vault keeper`);if(e.outs.length!==w)throw new Error(`Payout transaction has ${e.outs.length} output(s), expected exactly ${w} for role ${l}.`);const v=d.Buffer.from(y,"hex");if(!e.outs[0].script.equals(v))throw new Error(`Payout transaction output 0 does not pay the expected scriptPubKey for role ${l}`);const E=w-1;if(e.outs[E].value!==p.PAYOUT_ANCHOR_DUST_SATS)throw new Error(`Payout CPFP anchor (out ${E}) value ${e.outs[E].value} sats must equal ${p.PAYOUT_ANCHOR_DUST_SATS} sats`);if(l==="vp-claimer"){if(!Number.isInteger(h)||h<0||h>=p.MAX_VP_COMMISSION_BPS_EXCLUSIVE)throw new Error(`commissionBps must be an integer in [0, ${p.MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${h}`);const b=Math.floor(t*h/p.BPS_DENOMINATOR);if(e.outs[1].value>b)throw new Error(`Payout VP commission (out 1) value ${e.outs[1].value} sats exceeds cap ${b} sats (${h} bps of peginValue=${t})`)}const A=v.length;if(A===0||A>p.MAX_PAYOUT_SCRIPT_LEN)throw new Error(`Payout receiver scriptPubKey length ${A} is outside the contract's registration cap [1, ${p.MAX_PAYOUT_SCRIPT_LEN}]; refusing to sign payout.`);const m=l==="vp-claimer"?e.outs[1].script.length:void 0;if(m!==void 0&&(m===0||m>p.MAX_PAYOUT_SCRIPT_LEN))throw new Error(`Payout commission scriptPubKey length ${m} is outside the contract's registration cap [1, ${p.MAX_PAYOUT_SCRIPT_LEN}]; refusing to sign payout.`);return{out0Len:A,out1Len:m}}function se(e,t,n=0){const o=x.Psbt.fromHex(e);if(n>=o.data.inputs.length)throw new Error(`Input index ${n} out of range (${o.data.inputs.length} inputs)`);const r=o.data.inputs[n];if(r.tapScriptSig&&r.tapScriptSig.length>0){const i=c.hexToUint8Array(t);for(const s of r.tapScriptSig)if(s.pubkey.equals(d.Buffer.from(i)))return U(s.signature,n);throw new Error(`No signature found for depositor pubkey: ${t} at input ${n}`)}if(r.finalScriptWitness&&r.finalScriptWitness.length>0){const i=ue(r.finalScriptWitness);if(i.length!==k)throw new Error(`Unexpected finalized witness stack size at input ${n}: expected ${k} items (signature, script, controlBlock), got ${i.length}`);return U(i[0],n)}throw new Error(`No tapScriptSig or finalScriptWitness found in signed PSBT at input ${n}`)}function U(e,t){if(e.length===64)return c.uint8ArrayToHex(new Uint8Array(e));throw e.length===65?new Error(`Unexpected sighash byte 0x${e[64].toString(16).padStart(2,"0")} at input ${t}. Expected implicit SIGHASH_DEFAULT as a 64-byte signature.`):new Error(`Unexpected signature length at input ${t}: ${e.length}`)}function ue(e){const t=[];let n=0;const o=s=>{if(n+s>e.length)throw new Error(`Malformed witness data: need ${s} byte(s) at offset ${n}, only ${e.length-n} remaining`)},r=()=>{o(1);const s=e[n++];if(s<253)return s;if(s===253){o(2);const u=(e[n]|e[n+1]<<8)>>>0;return n+=2,u}if(s===254){o(4);const u=(e[n]|e[n+1]<<8|e[n+2]<<16|e[n+3]<<24)>>>0;return n+=4,u}throw new Error(`Malformed witness data: 8-byte varint (0xff) not supported at offset ${n-1}`)},i=r();for(let s=0;s<i;s++){const u=r();o(u),t.push(d.Buffer.from(e.subarray(n,n+u))),n+=u}if(n!==e.length)throw new Error(`Malformed witness data: ${e.length-n} trailing byte(s) after parsing ${i} item(s)`);return t}class $ extends Error{constructor(t){super(`Wallet returned a PSBT for a different transaction: ${t}`),this.name="PsbtSubstitutionError"}}function R(e,t){try{return x.Psbt.fromHex(t)}catch(n){const o=n instanceof Error?n.message:String(n);throw new Error(`Failed to parse ${e} PSBT: ${o}`)}}const ce=8;function C(e){return`${e.toString("hex").slice(0,ce)}…`}function L(e){const t=d.Buffer.from(e).reverse();return C(t)}function ae(e){const t=R("requested",e.requestedPsbtHex),n=R("returned",e.returnedPsbtHex);if(t.version!==n.version)throw new $(`tx version differs (requested=${t.version}, returned=${n.version})`);if(t.locktime!==n.locktime)throw new $(`tx locktime differs (requested=${t.locktime}, returned=${n.locktime})`);if(t.txInputs.length!==n.txInputs.length)throw new $(`input count differs (requested=${t.txInputs.length}, returned=${n.txInputs.length})`);if(t.txOutputs.length!==n.txOutputs.length)throw new $(`output count differs (requested=${t.txOutputs.length}, returned=${n.txOutputs.length})`);for(let o=0;o<t.txInputs.length;o++){const r=t.txInputs[o],i=n.txInputs[o];if(!r.hash.equals(i.hash))throw new $(`input ${o} prevout txid differs (requested=${L(r.hash)}, returned=${L(i.hash)})`);if(r.index!==i.index)throw new $(`input ${o} prevout vout differs (requested=${r.index}, returned=${i.index})`);if(r.sequence!==i.sequence)throw new $(`input ${o} sequence differs (requested=${r.sequence}, returned=${i.sequence})`)}for(let o=0;o<t.txOutputs.length;o++){const r=t.txOutputs[o],i=n.txOutputs[o];if(!r.script.equals(i.script))throw new $(`output ${o} scriptPubKey differs (requested=${C(r.script)}, returned=${C(i.script)})`);if(r.value!==i.value)throw new $(`output ${o} value differs (requested=${r.value}, returned=${i.value})`)}}const B=253,le=254,he=65535,Pe=4294967295;function de(e){if(e<B)return d.Buffer.from([e]);if(e<=he){const t=d.Buffer.alloc(2);return t.writeUInt16LE(e),d.Buffer.concat([d.Buffer.from([B]),t])}if(e<=Pe){const t=d.Buffer.alloc(4);return t.writeUInt32LE(e),d.Buffer.concat([d.Buffer.from([le]),t])}throw new Error(`Script too large to encode as CompactSize: ${e} bytes`)}const fe="TapLeaf";function pe(e,t){const n=d.Buffer.concat([d.Buffer.from([e]),de(t.length),d.Buffer.from(t)]);return x.crypto.taggedHash(fe,n)}function ge(e){const{requestedPsbtHex:t,signatureHex:n,signerXOnlyPubkeyHex:o,inputIndex:r}=e,i=c.stripHexPrefix(n);if(i.length!==c.SCHNORR_SIG_HEX_LEN)throw new Error(`Schnorr signature for input ${r} must be ${c.SCHNORR_SIG_HEX_LEN} hex chars (64 bytes), got ${i.length}.`);const s=c.stripHexPrefix(o);if(s.length!==c.X_ONLY_PUBKEY_HEX_LEN)throw new Error(`Signer x-only pubkey for input ${r} must be ${c.X_ONLY_PUBKEY_HEX_LEN} hex chars (32 bytes), got ${s.length}.`);const u=x.Psbt.fromHex(t);if(r<0||r>=u.data.inputs.length)throw new Error(`Input index ${r} out of range (${u.data.inputs.length} inputs).`);const h=[],a=[];for(let v=0;v<u.data.inputs.length;v++){const E=u.data.inputs[v].witnessUtxo;if(!E)throw new Error(`Cannot verify signature: input ${v} of the requested PSBT has no witnessUtxo (required to recompute the Taproot sighash).`);h.push(E.script),a.push(E.value)}const P=u.data.inputs[r].tapLeafScript;if(!P||P.length!==1)throw new Error(`Cannot verify signature: input ${r} of the requested PSBT must have exactly one tapLeafScript, got ${(P==null?void 0:P.length)??0}.`);const f=P[0];if(f.leafVersion!==c.TAPSCRIPT_LEAF_VERSION)throw new Error(`Cannot verify signature: input ${r} tapLeafScript has leaf version 0x${f.leafVersion.toString(16)}, expected 0x${c.TAPSCRIPT_LEAF_VERSION.toString(16)}.`);const g=pe(f.leafVersion,f.script),l=new x.Transaction;l.version=u.version,l.locktime=u.locktime;for(const v of u.txInputs)l.addInput(v.hash,v.index,v.sequence);for(const v of u.txOutputs)l.addOutput(v.script,v.value);const w=l.hashForWitnessV1(r,h,a,x.Transaction.SIGHASH_DEFAULT,g);if(!q.verifySchnorr(w,c.hexToUint8Array(s),c.hexToUint8Array(i)))throw new Error(`Schnorr signature for input ${r} (signer ${s}) does not verify against the expected Taproot script-path sighash. The wallet may have signed with the tweaked key, signed a different transaction, or returned an invalid signature.`)}exports.PsbtSubstitutionError=$;exports.assertPsbtUnsignedTxMatches=ae;exports.assertScriptPathSchnorrSignature=ge;exports.buildPayoutPsbt=re;exports.buildPeginTxFromFundedPrePegin=Y;exports.buildPrePeginPsbt=z;exports.createPayoutScript=N;exports.extractPayoutSignature=se;exports.normalizeAuthAnchorHash=T;
2
- //# sourceMappingURL=verifyScriptPathSchnorrSignature-BZhX-SOd.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"verifyScriptPathSchnorrSignature-BZhX-SOd.cjs","sources":["../src/tbv/core/primitives/psbt/assertWasmPeginSizing.ts","../src/tbv/core/primitives/psbt/pegin.ts","../src/tbv/core/primitives/scripts/payout.ts","../src/tbv/core/primitives/psbt/assertPayoutFeeBand.ts","../src/tbv/core/primitives/psbt/payout.ts","../src/tbv/core/primitives/psbt/assertPsbtUnsignedTxMatches.ts","../src/tbv/core/primitives/psbt/verifyScriptPathSchnorrSignature.ts"],"sourcesContent":["/**\n * Cross-check the values WASM returns from `createPrePeginTransaction`\n * against independently-known expectations before they feed a signed\n * Bitcoin transaction or the on-chain PegIn registration.\n *\n * CLAUDE.md critical path #1: the Rust/WASM layer computes\n * `htlcValue = peginAmount + depositorClaimValue + p2aAnchorValue +\n * minPeginFee` internally (the anchor term is 0 for graph versions without a\n * P2A anchor, 240 sats for v2) and JS receives the outputs with no runtime\n * validation. A doctored or buggy binary that returns a different\n * `peginAmount`, an out-of-formula `htlcValue`, or a wrong\n * `depositorClaimValue` would otherwise be committed verbatim — taxing the\n * depositor or starving the downstream tx graph of fees.\n *\n * @module primitives/psbt/assertWasmPeginSizing\n */\n\nimport {\n computeMinClaimValue,\n computeMinPeginFee,\n peginP2aAnchorOutput,\n type PrePeginResult,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\nimport { MAX_REASONABLE_PEGIN_VBYTES } from \"../../utils/fee/constants\";\nimport type { ParsedOutput } from \"../../utils/transaction/fundPeginTransaction\";\n\nimport type { PrePeginParams } from \"./pegin\";\n\n/**\n * Assert the WASM Pre-PegIn sizing result is internally consistent and\n * matches what the caller requested.\n *\n * Two layers of checks. Pure-JS, binary-INDEPENDENT: the per-HTLC\n * `peginAmount` must echo the requested amount, array lengths must match,\n * every value must be positive, and the implied per-HTLC reserve\n * (`htlcValue - peginAmount - depositorClaimValue`) must be strictly\n * positive and under the plausibility cap\n * ({@link MAX_REASONABLE_PEGIN_VBYTES}). WASM-vs-WASM consistency: the\n * reserve must also EXACTLY equal `computeMinPeginFee(version, …) +\n * p2aAnchorValue(version)` (like the `computeMinClaimValue` check) —\n * exact, but both sides come from the same binary, which is why the\n * independent bounds above are kept alongside it.\n *\n * @param result - The result returned by `createPrePeginTransaction`.\n * @param params - The parameters that were passed to build it.\n * @returns The independently computed `minPeginFee` this function already\n * asserted against `result`'s implied reserve — callers that need the\n * value should reuse this instead of recomputing it.\n * @throws If any value is missing, non-positive, mismatched against the\n * request, or outside the protocol formula.\n */\nexport async function assertWasmPeginSizing(\n result: PrePeginResult,\n params: PrePeginParams,\n): Promise<bigint> {\n const expectedCount = params.pegInAmounts.length;\n\n // Count: every parallel array must carry exactly one entry per requested\n // deposit, otherwise the per-HTLC indexing downstream is meaningless.\n if (result.htlcValues.length !== expectedCount) {\n throw new Error(\n `WASM Pre-PegIn returned ${result.htlcValues.length} HTLC value(s), ` +\n `expected ${expectedCount} (one per requested deposit).`,\n );\n }\n if (\n result.peginAmounts.length !== expectedCount ||\n result.htlcScriptPubKeys.length !== expectedCount ||\n result.htlcAddresses.length !== expectedCount\n ) {\n throw new Error(\n `WASM Pre-PegIn returned mismatched array lengths ` +\n `(htlcValues=${result.htlcValues.length}, ` +\n `peginAmounts=${result.peginAmounts.length}, ` +\n `htlcScriptPubKeys=${result.htlcScriptPubKeys.length}, ` +\n `htlcAddresses=${result.htlcAddresses.length}); ` +\n `expected ${expectedCount} each.`,\n );\n }\n\n // depositorClaimValue: positivity + WASM-vs-WASM consistency. Sized by the\n // tx-graph `feeRate` (see PrePeginParams.feeRate), so the standalone\n // `computeMinClaimValue` must reproduce the constructor's internal value.\n if (result.depositorClaimValue <= 0n) {\n throw new Error(\n `WASM Pre-PegIn returned non-positive depositorClaimValue ` +\n `${result.depositorClaimValue}; expected > 0.`,\n );\n }\n const expectedClaimValue = await computeMinClaimValue(\n // Must price the same graph version the builder constructed.\n params.vaultCoreVersion,\n params.numLocalChallengers,\n params.universalChallengerPubkeys.length,\n params.councilQuorum,\n params.councilSize,\n params.feeRate,\n );\n if (result.depositorClaimValue !== expectedClaimValue) {\n throw new Error(\n `WASM Pre-PegIn depositorClaimValue ${result.depositorClaimValue} does ` +\n `not match the independently computed minimum claim value ` +\n `${expectedClaimValue} (vaultCoreVersion=${params.vaultCoreVersion}, ` +\n `numLocalChallengers=${params.numLocalChallengers}, ` +\n `numUniversalChallengers=${params.universalChallengerPubkeys.length}, ` +\n `councilQuorum=${params.councilQuorum}, councilSize=${params.councilSize}, ` +\n `feeRate=${params.feeRate}).`,\n );\n }\n\n // The per-HTLC reserve above pegin+claim decomposes into the version's\n // P2A anchor value (0 when the version has no anchor) plus the exact\n // minimum PegIn fee. Both terms are Rust-model values fetched through\n // independent WASM entry points; the builder must reproduce their sum.\n // The Rust fee model sizes the PegIn input witness from the vault keeper\n // and universal challenger counts (btc-vault `PegInTx::estimate_vsize`).\n const anchor = await peginP2aAnchorOutput(params.vaultCoreVersion);\n const anchorValue = anchor?.value ?? 0n;\n const expectedPeginFee = await computeMinPeginFee(\n params.vaultCoreVersion,\n params.vaultKeeperPubkeys.length,\n params.universalChallengerPubkeys.length,\n params.minPeginFeeRate,\n );\n const expectedReserve = expectedPeginFee + anchorValue;\n // Binary-INDEPENDENT plausibility cap: the exact identity below compares\n // WASM against WASM, so a consistently doctored binary could satisfy it\n // with an inflated reserve. This pure-JS bound (max standard-relay tx\n // vbytes × the caller's fee rate) caps how much a compromised binary can\n // burn.\n const maxImpliedReserve =\n params.minPeginFeeRate * MAX_REASONABLE_PEGIN_VBYTES;\n\n for (let i = 0; i < expectedCount; i++) {\n const requested = params.pegInAmounts[i];\n const peginAmount = result.peginAmounts[i];\n const htlcValue = result.htlcValues[i];\n\n // Amount echo (strongest, fully independent): the recorded pegin amount\n // must equal exactly what the caller requested. A mismatch is the\n // WASM-tax attack — the contract would record a doctored amount while the\n // depositor's wallet funds the original, and the difference is a\n // WASM-controlled tax.\n if (peginAmount !== requested) {\n throw new Error(\n `WASM Pre-PegIn peginAmount[${i}] ${peginAmount} does not match the ` +\n `requested amount ${requested}; refusing to build a tx whose ` +\n `recorded amount differs from the depositor's request.`,\n );\n }\n if (peginAmount <= 0n) {\n throw new Error(\n `WASM Pre-PegIn peginAmount[${i}] is non-positive (${peginAmount}); ` +\n `expected > 0.`,\n );\n }\n if (htlcValue <= 0n) {\n throw new Error(\n `WASM Pre-PegIn htlcValue[${i}] is non-positive (${htlcValue}); ` +\n `expected > 0.`,\n );\n }\n\n // Formula: htlcValue = peginAmount + depositorClaimValue +\n // p2aAnchorValue + minPeginFee. The reserve must match exactly — a\n // shortfall starves the PegIn's fee/anchor, an excess locks sats\n // irrecoverably in the HTLC.\n const impliedReserve = htlcValue - peginAmount - result.depositorClaimValue;\n // Independent JS-side bounds first (see maxImpliedReserve above): the\n // reserve must be strictly positive (a zero reserve starves the PegIn\n // of its fee) and plausibly sized, regardless of what the binary's own\n // reference entry points claim.\n if (impliedReserve <= 0n) {\n throw new Error(\n `WASM Pre-PegIn htlcValue[${i}] ${htlcValue} does not strictly ` +\n `cover peginAmount ${peginAmount} + depositorClaimValue ` +\n `${result.depositorClaimValue} + a PegIn reserve (implied ` +\n `reserve ${impliedReserve}).`,\n );\n }\n if (impliedReserve > maxImpliedReserve) {\n throw new Error(\n `WASM Pre-PegIn implied reserve for HTLC[${i}] (${impliedReserve} ` +\n `sat) exceeds the plausibility cap ${maxImpliedReserve} sat ` +\n `(minPeginFeeRate=${params.minPeginFeeRate} × ` +\n `${MAX_REASONABLE_PEGIN_VBYTES} vbytes); htlcValue ${htlcValue} ` +\n `appears grossly inflated.`,\n );\n }\n if (impliedReserve !== expectedReserve) {\n throw new Error(\n `WASM Pre-PegIn htlcValue[${i}] ${htlcValue} implies a PegIn ` +\n `fee+anchor reserve of ${impliedReserve} sat, expected exactly ` +\n `${expectedReserve} sat (minPeginFee ${expectedPeginFee} + ` +\n `p2aAnchor ${anchorValue} for vaultCoreVersion ` +\n `${params.vaultCoreVersion}, vaultKeepers=` +\n `${params.vaultKeeperPubkeys.length}, universalChallengers=` +\n `${params.universalChallengerPubkeys.length}, minPeginFeeRate=` +\n `${params.minPeginFeeRate}).`,\n );\n }\n }\n\n return expectedPeginFee;\n}\n\n/**\n * Bind the validated metadata to the bytes that actually get funded and\n * signed.\n *\n * `assertWasmPeginSizing` proves the WASM *metadata* (`htlcValues`,\n * `htlcScriptPubKeys`) matches the request and the protocol formula — but the\n * transaction the depositor funds and signs is `result.txHex`. If the encoded\n * tx carried a different HTLC output value or script than the metadata, the\n * depositor would fund a transaction whose real outputs differ from the values\n * that were cross-checked. This closes that final link: the encoded HTLC\n * outputs must equal the validated metadata.\n *\n * The WASM lays out HTLC outputs first (vouts `0..N-1`), then the optional\n * auth-anchor OP_RETURN, then the CPFP anchor — so we only compare the first\n * `htlcValues.length` outputs.\n *\n * @param outputs - Outputs parsed from the unfunded Pre-PegIn tx hex.\n * @param htlcValues - The (already value-validated) per-HTLC values.\n * @param htlcScriptPubKeys - The per-HTLC scriptPubKeys (hex).\n * @throws If the encoded outputs are too few, or any HTLC output's value or\n * scriptPubKey disagrees with the validated metadata.\n */\nexport function assertEncodedHtlcOutputsMatch(\n outputs: readonly ParsedOutput[],\n htlcValues: readonly bigint[],\n htlcScriptPubKeys: readonly string[],\n): void {\n if (outputs.length < htlcValues.length) {\n throw new Error(\n `Encoded Pre-PegIn tx has ${outputs.length} output(s), fewer than the ` +\n `${htlcValues.length} HTLC output(s) the cross-check validated.`,\n );\n }\n\n for (let i = 0; i < htlcValues.length; i++) {\n const encodedValue = BigInt(outputs[i].value);\n if (encodedValue !== htlcValues[i]) {\n throw new Error(\n `Encoded Pre-PegIn HTLC output[${i}] value ${encodedValue} does not ` +\n `match the cross-checked htlcValue ${htlcValues[i]}; the funded/signed ` +\n `tx would not pay the validated amount.`,\n );\n }\n\n const encodedScript = outputs[i].script.toString(\"hex\").toLowerCase();\n const expectedScript = htlcScriptPubKeys[i].toLowerCase();\n if (encodedScript !== expectedScript) {\n throw new Error(\n `Encoded Pre-PegIn HTLC output[${i}] scriptPubKey ${encodedScript} does ` +\n `not match the cross-checked htlcScriptPubKey ${expectedScript}.`,\n );\n }\n }\n}\n","/**\n * Pre-PegIn PSBT Builder Primitive\n *\n * This module provides pure functions for building unfunded Pre-PegIn transactions\n * and deriving PegIn transactions from them, using the WASM implementation from\n * @babylonlabs-io/babylon-tbv-rust-wasm.\n *\n * Pre-PegIn Flow:\n * 1. buildPrePeginPsbt() — creates unfunded Pre-PegIn tx (HTLC output)\n * 2. [caller funds Pre-PegIn tx and computes txid]\n * 3. buildPeginTxFromFundedPrePegin() — derives PegIn tx spending the HTLC\n * 4. buildPeginInputPsbt() — PSBT for depositor to sign PegIn HTLC leaf 0 input\n *\n * @module primitives/psbt/pegin\n */\n\nimport {\n buildPeginTxFromPrePegin,\n computeMinClaimValue,\n createPrePeginTransaction,\n peginP2aAnchorOutput,\n tapInternalPubkey,\n validatePeginP2aAnchor,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Buffer } from \"buffer\";\nimport { payments, script as bscript, Transaction, opcodes } from \"bitcoinjs-lib\";\n\nimport { parseUnfundedWasmTransaction } from \"../../utils/transaction/fundPeginTransaction\";\nimport {\n hexToUint8Array,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\n\nimport {\n assertEncodedHtlcOutputsMatch,\n assertWasmPeginSizing,\n} from \"./assertWasmPeginSizing\";\n\n/**\n * Parameters for building an unfunded Pre-PegIn PSBT\n */\nexport interface PrePeginParams {\n /**\n * Vault core (tx-graph) version to build. Fresh deposits use the contract's\n * `ProtocolParams.activeVaultCoreVersion()`; resumed vaults use their\n * stamped on-chain `vaultCoreVersion`. The WASM facade fails closed on\n * versions it wasn't compiled with.\n */\n vaultCoreVersion: number;\n /** Depositor's BTC public key (x-only, 64-char hex without 0x prefix) */\n depositorPubkey: string;\n /** Vault provider's BTC public key (x-only, 64-char hex) */\n vaultProviderPubkey: string;\n /** Array of vault keeper BTC public keys (x-only, 64-char hex) */\n vaultKeeperPubkeys: string[];\n /** Array of universal challenger BTC public keys (x-only, 64-char hex) */\n universalChallengerPubkeys: string[];\n /** SHA256 hash commitment(s) (64 hex chars = 32 bytes each) */\n hashlocks: readonly string[];\n /** CSV timelock in blocks for the HTLC refund path */\n timelockRefund: number;\n /** Amounts to peg in (satoshis), one per deposit */\n pegInAmounts: readonly bigint[];\n /** TX-graph fee rate in sat/vB from contract offchain params; sizes the depositor claim value */\n feeRate: bigint;\n /** Minimum PegIn fee rate in sat/vB from contract offchain params; sizes the PegIn tx fee */\n minPeginFeeRate: bigint;\n /** Number of local challengers (from contract params) */\n numLocalChallengers: number;\n /** M in M-of-N council multisig (from contract params) */\n councilQuorum: number;\n /** N in M-of-N council multisig (from contract params) */\n councilSize: number;\n /** Bitcoin network */\n network: Network;\n /**\n * Optional 32-byte `SHA256(auth_anchor)` commitment (64-char hex, no\n * `0x` prefix). If provided, the Pre-PegIn tx will include an\n * `OP_RETURN <PUSH32 authAnchorHash>` output at vout =\n * `hashlocks.length`, binding the depositor's bearer-token\n * `auth_anchor` preimage to this Pre-PegIn.\n */\n authAnchorHash?: string;\n}\n\n/**\n * Byte length of an `auth_anchor_hash` commitment when encoded as a\n * lowercase hex string (32 bytes → 64 hex chars).\n */\nconst AUTH_ANCHOR_HASH_HEX_LEN = 64;\n\nconst HEX_PATTERN = /^[0-9a-fA-F]+$/;\n\n/**\n * Result of building an unfunded Pre-PegIn transaction\n */\nexport interface PrePeginPsbtResult {\n /**\n * Unfunded transaction hex (no inputs, HTLC outputs + optional\n * auth-anchor OP_RETURN + CPFP anchor).\n *\n * The caller is responsible for:\n * - Selecting UTXOs covering totalOutputValue + network fees\n * - Funding the transaction (add inputs and change output)\n * - Calling buildPeginTxFromFundedPrePegin() with the funded tx hex\n */\n psbtHex: string;\n /** Sum of all unfunded outputs — use this for UTXO selection */\n totalOutputValue: bigint;\n /**\n * HTLC output values in satoshis, one per deposit. Each includes\n * peginAmount + depositorClaimValue + p2aAnchorValue + minPeginFee (the\n * anchor term is 0 for graph versions without a P2A anchor, 240 for v2).\n */\n htlcValues: readonly bigint[];\n /** HTLC output scriptPubKeys (hex encoded), one per deposit */\n htlcScriptPubKeys: readonly string[];\n /** HTLC Taproot addresses, one per deposit */\n htlcAddresses: readonly string[];\n /** Pegin amounts in satoshis, one per deposit */\n peginAmounts: readonly bigint[];\n /** Depositor claim value computed by WASM from contract parameters */\n depositorClaimValue: bigint;\n /**\n * Vout index of the auth-anchor `OP_RETURN` output if one was\n * included (i.e. `authAnchorHash` was provided), or `null` if not.\n * Always equals `htlcValues.length` when present.\n */\n authAnchorVout: number | null;\n /**\n * Minimum PegIn fee (sats), independently computed and asserted against\n * `htlcValues`' implied reserve by {@link assertWasmPeginSizing}. Reuse\n * this instead of recomputing — it is already the cross-checked value.\n */\n minPeginFee: bigint;\n}\n\n/**\n * Parameters for building the PegIn transaction from a funded Pre-PegIn tx\n */\nexport interface BuildPeginTxParams {\n /** Same PrePeginParams used to create the Pre-PegIn transaction */\n prePeginParams: PrePeginParams;\n /** CSV timelock in blocks for the PegIn vault output */\n timelockPegin: number;\n /** Hex-encoded funded Pre-PegIn transaction */\n fundedPrePeginTxHex: string;\n /** Index of the HTLC output to spend */\n htlcVout: number;\n}\n\n/**\n * Result of building the PegIn transaction\n */\nexport interface PeginTxResult {\n /**\n * PegIn transaction hex. 1 input spending the HTLC; outputs are\n * version-shaped: v1 = vault + depositor claim, v2 = vault + depositor\n * claim + P2A anchor at vout 2 (nVersion 3 / TRUC).\n */\n txHex: string;\n /** PegIn transaction ID */\n txid: string;\n /** Vault output scriptPubKey (hex encoded) */\n vaultScriptPubKey: string;\n /** Vault output value in satoshis */\n vaultValue: bigint;\n}\n\n/**\n * Build unfunded Pre-PegIn transaction using WASM.\n *\n * Creates a Bitcoin transaction template with no inputs, an HTLC output, and a\n * CPFP anchor output. The HTLC value is computed internally from the contract\n * parameters — the caller does not need to compute depositorClaimValue separately.\n *\n * @param params - Pre-PegIn parameters\n * @returns Unfunded Pre-PegIn transaction details with HTLC output information\n * @throws If WASM initialization fails or parameters are invalid\n */\nexport async function buildPrePeginPsbt(\n params: PrePeginParams,\n): Promise<PrePeginPsbtResult> {\n const authAnchorHash = normalizeAuthAnchorHash(params.authAnchorHash);\n\n const result = await createPrePeginTransaction({\n txGraphVersion: params.vaultCoreVersion,\n depositorPubkey: params.depositorPubkey,\n vaultProviderPubkey: params.vaultProviderPubkey,\n vaultKeeperPubkeys: params.vaultKeeperPubkeys,\n universalChallengerPubkeys: params.universalChallengerPubkeys,\n hashlocks: [...params.hashlocks],\n timelockRefund: params.timelockRefund,\n pegInAmounts: [...params.pegInAmounts],\n feeRate: params.feeRate,\n minPeginFeeRate: params.minPeginFeeRate,\n numLocalChallengers: params.numLocalChallengers,\n councilQuorum: params.councilQuorum,\n councilSize: params.councilSize,\n network: params.network,\n authAnchorHash,\n });\n\n // CLAUDE.md critical path #1: the WASM outputs reach JS with no runtime\n // validation. Cross-check every value-bearing field against the request\n // and the protocol formula before it can feed a signed tx or the on-chain\n // PegIn registration. Both the sizing and commit passes route through here.\n const minPeginFee = await assertWasmPeginSizing(result, params);\n\n // Parse the unfunded tx to sum all output values\n // (HTLCs + optional OP_RETURN + CPFP anchor). This is the amount\n // UTXOs must cover before adding network fees.\n const parsed = parseUnfundedWasmTransaction(result.txHex);\n\n // Bind the validated metadata to the bytes that get funded and signed:\n // the encoded HTLC outputs must carry exactly the values/scripts the\n // cross-check above validated. Otherwise a tx whose real outputs differ\n // from the checked metadata could still be funded and signed.\n assertEncodedHtlcOutputsMatch(\n parsed.outputs,\n result.htlcValues,\n result.htlcScriptPubKeys,\n );\n\n const totalOutputValue = parsed.outputs.reduce(\n (sum, o) => sum + BigInt(o.value),\n 0n,\n );\n\n // The WASM places the OP_RETURN commitment immediately after the\n // HTLC outputs when authAnchorHash is provided.\n const authAnchorVout =\n authAnchorHash !== undefined ? result.htlcValues.length : null;\n\n return {\n psbtHex: result.txHex,\n totalOutputValue,\n htlcValues: result.htlcValues,\n htlcScriptPubKeys: result.htlcScriptPubKeys,\n htlcAddresses: result.htlcAddresses,\n peginAmounts: result.peginAmounts,\n depositorClaimValue: result.depositorClaimValue,\n authAnchorVout,\n minPeginFee,\n };\n}\n\n/**\n * Validate and normalize an `authAnchorHash` hex string before passing\n * it to the WASM boundary. WASM expects exactly 64 lowercase hex chars.\n */\nexport function normalizeAuthAnchorHash(\n value: string | undefined,\n): string | undefined {\n if (value === undefined) return undefined;\n const cleaned =\n value.startsWith(\"0x\") || value.startsWith(\"0X\") ? value.slice(2) : value;\n if (\n cleaned.length !== AUTH_ANCHOR_HASH_HEX_LEN ||\n !HEX_PATTERN.test(cleaned)\n ) {\n throw new Error(\n `authAnchorHash must be 32-byte hex (${AUTH_ANCHOR_HASH_HEX_LEN} chars, no 0x prefix); got length ${cleaned.length}`,\n );\n }\n return cleaned.toLowerCase();\n}\n\n/**\n * Build the PegIn transaction from a funded Pre-PegIn transaction.\n *\n * The PegIn transaction spends the Pre-PegIn HTLC output at htlcVout via the\n * hashlock + all-party script (leaf 0).\n *\n * @param params - Build parameters including Pre-PegIn params and funded tx hex\n * @returns PegIn transaction details\n * @throws If WASM initialization fails or parameters are invalid\n */\nexport async function buildPeginTxFromFundedPrePegin(\n params: BuildPeginTxParams,\n): Promise<PeginTxResult> {\n // WASM reconstructs the Pre-PegIn template from these params to\n // decode the funded tx. Must pass `authAnchorHash` (normalized\n // identically to buildPrePeginPsbt) so the reconstruction matches\n // the original outputs, including the OP_RETURN at vout =\n // hashlocks.length.\n const result = await buildPeginTxFromPrePegin(\n {\n txGraphVersion: params.prePeginParams.vaultCoreVersion,\n depositorPubkey: params.prePeginParams.depositorPubkey,\n vaultProviderPubkey: params.prePeginParams.vaultProviderPubkey,\n vaultKeeperPubkeys: params.prePeginParams.vaultKeeperPubkeys,\n universalChallengerPubkeys:\n params.prePeginParams.universalChallengerPubkeys,\n hashlocks: [...params.prePeginParams.hashlocks],\n timelockRefund: params.prePeginParams.timelockRefund,\n pegInAmounts: [...params.prePeginParams.pegInAmounts],\n feeRate: params.prePeginParams.feeRate,\n minPeginFeeRate: params.prePeginParams.minPeginFeeRate,\n numLocalChallengers: params.prePeginParams.numLocalChallengers,\n councilQuorum: params.prePeginParams.councilQuorum,\n councilSize: params.prePeginParams.councilSize,\n network: params.prePeginParams.network,\n authAnchorHash: normalizeAuthAnchorHash(\n params.prePeginParams.authAnchorHash,\n ),\n },\n params.timelockPegin,\n params.fundedPrePeginTxHex,\n params.htlcVout,\n );\n\n await assertPeginTxShape(result, params);\n\n return {\n txHex: result.txHex,\n txid: result.txid,\n vaultScriptPubKey: result.vaultScriptPubKey,\n vaultValue: result.vaultValue,\n };\n}\n\n/**\n * PegIn outputs common to every graph version: the vault output (vout 0)\n * and the depositor claim output (vout 1). Versions with a P2A anchor (v2)\n * append it after these.\n */\nconst PEGIN_BASE_OUTPUT_COUNT = 2;\n\n/**\n * Vout of the depositor-claim output in every PegIn version (btc-vault:\n * vault at 0, depositor claim at 1, optional P2A anchor appended after).\n */\nconst PEGIN_DEPOSITOR_CLAIM_VOUT = 1;\n\n/**\n * Cross-check the WASM-built PegIn transaction's bytes against the request\n * and the version's expected output layout before the depositor signs it.\n *\n * CLAUDE.md critical path #1: the metadata (`vaultValue`, `txid`,\n * `vaultScriptPubKey`) and the tx bytes both come from WASM — bind them to\n * each other and to the caller's requested amount so a doctored binary\n * can't commit one thing and encode another. The vault output value is the\n * exact on-chain vault amount, so it must equal the requested peg-in amount\n * (btc-vault: PegIn vout 0 carries `pegin_amount` verbatim). The P2A anchor\n * (exact value/vout/script for v2; complete absence for v1) is enforced by\n * the version-dispatched `validatePeginP2aAnchor`.\n *\n * @throws If the encoded outputs disagree with the metadata, the requested\n * amount, or the version's anchor rules.\n */\nasync function assertPeginTxShape(\n result: {\n txHex: string;\n txid: string;\n vaultScriptPubKey: string;\n vaultValue: bigint;\n },\n params: BuildPeginTxParams,\n): Promise<void> {\n const version = params.prePeginParams.vaultCoreVersion;\n\n await validatePeginP2aAnchor(version, result.txHex);\n\n const anchor = await peginP2aAnchorOutput(version);\n const expectedOutputCount = PEGIN_BASE_OUTPUT_COUNT + (anchor ? 1 : 0);\n\n const peginTx = Transaction.fromHex(stripHexPrefix(result.txHex));\n\n // Input bind: the PegIn must spend EXACTLY the requested HTLC outpoint\n // (fundedPrePeginTxid, htlcVout). Without this, a doctored tx could spend\n // a sibling HTLC while the caller registers it under `htlcVout` — in a\n // multi-HTLC batch that both double-spends the sibling and strands the\n // registered vault. The downstream PSBT builder follows the tx's own\n // input index, so this is the only place the requested vout is enforced.\n if (peginTx.ins.length !== 1) {\n throw new Error(\n `PegIn tx has ${peginTx.ins.length} input(s), expected exactly 1 ` +\n `(the Pre-PegIn HTLC outpoint).`,\n );\n }\n const fundedPrePeginTxid = Transaction.fromHex(\n stripHexPrefix(params.fundedPrePeginTxHex),\n ).getId();\n const inputTxid = uint8ArrayToHex(\n new Uint8Array(peginTx.ins[0].hash).slice().reverse(),\n );\n if (inputTxid !== fundedPrePeginTxid) {\n throw new Error(\n `PegIn input spends txid ${inputTxid}, expected the funded Pre-PegIn ` +\n `${fundedPrePeginTxid}.`,\n );\n }\n if (peginTx.ins[0].index !== params.htlcVout) {\n throw new Error(\n `PegIn input spends Pre-PegIn output ${peginTx.ins[0].index}, ` +\n `expected the requested HTLC vout ${params.htlcVout}.`,\n );\n }\n\n if (peginTx.outs.length !== expectedOutputCount) {\n throw new Error(\n `PegIn tx has ${peginTx.outs.length} output(s), expected exactly ` +\n `${expectedOutputCount} for vaultCoreVersion ${version} (vault + ` +\n `depositor claim${anchor ? \" + P2A anchor\" : \"\"}).`,\n );\n }\n\n const requestedAmount =\n params.prePeginParams.pegInAmounts[params.htlcVout];\n if (result.vaultValue !== requestedAmount) {\n throw new Error(\n `PegIn vault output value ${result.vaultValue} does not match the ` +\n `requested peg-in amount ${requestedAmount} for HTLC ` +\n `${params.htlcVout}; refusing to sign a vault that locks a ` +\n `different amount than requested.`,\n );\n }\n\n const encodedVaultOut = peginTx.outs[0];\n if (BigInt(encodedVaultOut.value) !== result.vaultValue) {\n throw new Error(\n `Encoded PegIn vault output value ${encodedVaultOut.value} does not ` +\n `match the WASM-reported vaultValue ${result.vaultValue}.`,\n );\n }\n const encodedVaultScript = encodedVaultOut.script.toString(\"hex\");\n const expectedVaultScript = stripHexPrefix(\n result.vaultScriptPubKey,\n ).toLowerCase();\n if (encodedVaultScript.toLowerCase() !== expectedVaultScript) {\n throw new Error(\n `Encoded PegIn vault output scriptPubKey ${encodedVaultScript} does ` +\n `not match the WASM-reported vaultScriptPubKey ` +\n `${result.vaultScriptPubKey}.`,\n );\n }\n\n const encodedTxid = peginTx.getId();\n if (encodedTxid !== stripHexPrefix(result.txid).toLowerCase()) {\n throw new Error(\n `Encoded PegIn txid ${encodedTxid} does not match the WASM-reported ` +\n `txid ${result.txid}.`,\n );\n }\n\n // Depositor-claim output (vout 1): a doctored binary could burn the claim\n // into miner fee or redirect it while the vault, anchor, and txid binds\n // all pass. Bind its value to the independently recomputed minimum claim\n // value (the same WASM-vs-WASM identity `assertWasmPeginSizing` uses) and\n // its script to a fully JS-derived expectation. With the vault bind, the\n // output count, and value conservation against the validated HTLC input,\n // the implied fee is bound too.\n const expectedClaimValue = await computeMinClaimValue(\n version,\n params.prePeginParams.numLocalChallengers,\n params.prePeginParams.universalChallengerPubkeys.length,\n params.prePeginParams.councilQuorum,\n params.prePeginParams.councilSize,\n params.prePeginParams.feeRate,\n );\n const encodedClaimOut = peginTx.outs[PEGIN_DEPOSITOR_CLAIM_VOUT];\n if (BigInt(encodedClaimOut.value) !== expectedClaimValue) {\n throw new Error(\n `Encoded PegIn depositor-claim output value ${encodedClaimOut.value} ` +\n `does not match the independently computed claim value ` +\n `${expectedClaimValue} for vaultCoreVersion ${version}.`,\n );\n }\n\n const expectedClaimScript = deriveDepositorClaimScriptPubKey(\n params.prePeginParams.depositorPubkey,\n );\n if (!encodedClaimOut.script.equals(expectedClaimScript)) {\n throw new Error(\n `Encoded PegIn depositor-claim output scriptPubKey ` +\n `${encodedClaimOut.script.toString(\"hex\")} does not pay to the ` +\n `depositor's claim script (expected ` +\n `${expectedClaimScript.toString(\"hex\")}).`,\n );\n }\n}\n\n/**\n * Independently derive the PegIn depositor-claim output's scriptPubKey in\n * JS: a Taproot output with the NUMS internal key and a single\n * `<depositor> OP_CHECKSIG` leaf — btc-vault's `SingleKeyConnector`\n * (`crates/vault/src/connectors/mod.rs`, identical across graph versions).\n * Uses the same `tapInternalPubkey` NUMS constant the HTLC connector pins.\n */\nfunction deriveDepositorClaimScriptPubKey(depositorPubkey: string): Buffer {\n const claimLeafScript = bscript.compile([\n Buffer.from(hexToUint8Array(depositorPubkey)),\n opcodes.OP_CHECKSIG,\n ]);\n const { output } = payments.p2tr({\n internalPubkey: Buffer.from(tapInternalPubkey),\n scriptTree: { output: claimLeafScript },\n });\n if (!output) {\n throw new Error(\n \"Failed to derive the depositor-claim P2TR scriptPubKey for PegIn output validation\",\n );\n }\n return output;\n}\n","/**\n * Payout Script Generator Primitive\n *\n * This module provides pure functions for generating payout scripts and taproot information\n * by wrapping the WASM implementation from @babylonlabs-io/babylon-tbv-rust-wasm.\n *\n * The payout script is used for signing payout transactions in the vault system.\n * It defines the spending conditions for the vault output, enabling the depositor\n * to authorize payouts during the peg-in flow (Step 3).\n *\n * @remarks\n * This is a low-level primitive. For most use cases, prefer using {@link buildPayoutPsbt}\n * which handles script creation internally. For high-level wallet orchestration, use\n * PayoutManager from the managers module.\n *\n * @see {@link buildPayoutPsbt} - Higher-level function that uses this internally\n *\n * @module primitives/scripts/payout\n */\n\nimport {\n createPayoutConnector,\n type Network,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\n/**\n * Parameters for creating a payout script.\n *\n * These parameters define the participants in a vault and are used to generate\n * the taproot script that controls how funds can be spent from the vault.\n */\nexport interface PayoutScriptParams {\n /**\n * Vault core (tx-graph) version the vault was registered under — the\n * vault's stamped on-chain `vaultCoreVersion`. Selects which graph's\n * payout connector the WASM derives.\n */\n vaultCoreVersion: number;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex without 0x prefix).\n *\n * This is the user depositing BTC into the vault. The depositor must sign\n * payout transactions to authorize fund distribution.\n */\n depositor: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex without 0x prefix).\n *\n * The service provider managing vault operations. Also referred to as\n * \"claimer\" in the WASM layer.\n */\n vaultProvider: string;\n\n /**\n * Array of vault keeper BTC public keys (x-only, 64-char hex without 0x prefix).\n *\n * Vault keepers participate in vault operations and script spending conditions.\n */\n vaultKeepers: string[];\n\n /**\n * Array of universal challenger BTC public keys (x-only, 64-char hex without 0x prefix).\n *\n * These parties can challenge the vault under certain conditions.\n */\n universalChallengers: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Bitcoin network for script generation.\n *\n * Must match the network used for all other vault operations to ensure\n * address encoding compatibility.\n */\n network: Network;\n}\n\n/**\n * Result of creating a payout script.\n *\n * Contains all the taproot-related data needed for constructing and signing\n * payout transactions from the vault.\n */\nexport interface PayoutScriptResult {\n /**\n * The payout script hex used in taproot script path spending.\n *\n * This is the raw script bytes that define the spending conditions,\n * encoded as a hexadecimal string. Used when constructing the\n * tapLeafScript for PSBT signing.\n */\n payoutScript: string;\n\n /**\n * The taproot script hash (leaf hash) for the payout script.\n *\n * This is the tagged hash of the script used in taproot tree construction.\n * Required for computing the control block during script path spending.\n */\n taprootScriptHash: string;\n\n /**\n * The full scriptPubKey for the vault output address.\n *\n * This is the complete output script (OP_1 <32-byte-key>) that should be\n * used when creating the vault output in a peg-in transaction.\n */\n scriptPubKey: string;\n\n /**\n * The vault Bitcoin address derived from the script.\n *\n * A human-readable bech32m address (bc1p... for mainnet, tb1p... for testnet/signet)\n * that can be used to receive funds into the vault.\n */\n address: string;\n\n /**\n * Serialized control block for Taproot script path spend (hex encoded).\n *\n * Computed by the Rust WASM PeginPayoutConnector. Used directly in\n * tapLeafScript when building payout PSBTs.\n */\n payoutControlBlock: string;\n}\n\n/**\n * Create payout script and taproot information using WASM.\n *\n * This is a pure function that wraps the Rust WASM implementation.\n * The payout connector generates the necessary taproot scripts and information\n * required for signing payout transactions.\n *\n * @remarks\n * The generated script encodes spending conditions that require signatures from\n * the depositor and vault provider (or liquidators in challenge scenarios).\n * This script is used internally by {@link buildPayoutPsbt}.\n *\n * @param params - Payout script parameters defining vault participants and network\n * @returns Payout script and taproot information for PSBT construction\n *\n * @see {@link buildPayoutPsbt} - Use this for building complete payout PSBTs\n */\nexport async function createPayoutScript(\n params: PayoutScriptParams,\n): Promise<PayoutScriptResult> {\n // Call the WASM wrapper with the correct parameter structure\n const connector = await createPayoutConnector(\n {\n txGraphVersion: params.vaultCoreVersion,\n depositor: params.depositor,\n vaultProvider: params.vaultProvider,\n vaultKeepers: params.vaultKeepers,\n universalChallengers: params.universalChallengers,\n timelockPegin: params.timelockPegin,\n },\n params.network,\n );\n\n return {\n payoutScript: connector.payoutScript,\n taprootScriptHash: connector.taprootScriptHash,\n scriptPubKey: connector.scriptPubKey,\n address: connector.address,\n payoutControlBlock: connector.payoutControlBlock,\n };\n}\n","/**\n * Payout implicit-fee band validation (floor + ceiling).\n *\n * Bands the implicit fee of a VP-built payout transaction before the\n * depositor pre-signs it:\n * - Ceiling: the Ledger device's payout vsize model (`app-babylon-vault`\n * `sign_psbt_validate.c`, HLD v22 §4.9.7.1) extended by measured script\n * excess over its 34-byte assumption — blocks a VP deflating outputs and\n * burning the difference as miner fee.\n * - Floor: the minimum fee any known VP output-sizing model produces\n * (vault-wasm `computePayoutFeeFloor`) — a lower fee is provably\n * illegitimate and risks a payout that cannot relay at redemption time.\n *\n * Preconditions, enforced by the caller (`buildPayoutPsbt`):\n * - `assertPayoutFeeBandDomain` has accepted the rate and participant counts,\n * so the band runs exactly over the domain its dominance proof was swept.\n * - `out0Len` is the layout-trusted length of the PINNED outs[0] script.\n * `out1Len` is measured from the deliberately-unpinned VP commission\n * output and is UNTRUSTED: it feeds only the floor, where padding cannot\n * raise it (the fixed-34 model saturates the minimum) and shortening only\n * lowers it. It must never widen the ceiling — a VP-controlled length\n * there would buy burnable headroom.\n * - `implicitFeeSats` is `inputs − outputs` over verified prevouts, `>= 0`.\n *\n * @module primitives/psbt/assertPayoutFeeBand\n */\n\nimport { computePayoutFeeFloor } from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\n\n/**\n * Payout fee-bound vsize model: `maxVsize = BASE + PER_PARTICIPANT * (N + M)`\n * where N = vault keepers, M = universal challengers. Constants and comparison\n * match the Ledger device (`app-babylon-vault` `sign_psbt_validate.c`\n * MAX_PAYOUT_VSIZE_BASE/PER_PARTICIPANT; HLD v22 §4.9.7.1) — a conservative\n * upper estimate with ~13%+ headroom over the exact vsize the VP pays. For\n * payouts whose outs[0] script is <= 34 bytes our accept-set is a subset of\n * the device's: the device bound is FLAT (no script-excess term) and our fee\n * basis (true prevout fee; real graphs build Assert:0 as 546 + council fee)\n * is stricter than its `vault_amount + 546` proxy. A pinned outs[0] script\n * above 34 bytes extends our ceiling past the device's flat bound —\n * contract-legal, but such payouts cannot pass a device today (it also\n * hard-requires 34-byte output scripts).\n */\nconst MAX_PAYOUT_VSIZE_BASE = 500;\nconst MAX_PAYOUT_VSIZE_PER_PARTICIPANT = 55;\n\n/**\n * Inclusive range cap `[1, 0xffffffff]` for the tx-graph fee rate (sat/vB):\n * the device's intent parser rejects `base_fee_rate > UINT32_MAX`\n * (`vault_tlv.c` TAG_BASE_FEE_RATE). Mirroring it keeps our bound math in\n * safe integer range and refuses rates no device could ever approve.\n */\nconst MAX_BASE_FEE_RATE_SAT_PER_VB = 0xffffffffn;\n\n/**\n * Device cap on vault keeper and universal challenger counts (u8 fields,\n * each `[1, 32]` — `app-babylon-vault` `vault_intent.h`). Enforced at the\n * payout boundary so the fee-bound dominance proof's swept domain exactly\n * equals the accepted input domain.\n */\nconst MAX_PAYOUT_PARTICIPANTS_PER_ROLE = 32;\n\n/**\n * Per-output script length the device's flat payout fee bound implicitly\n * assumes (P2TR, 34 bytes). Measured non-anchor scripts above it extend the\n * ceiling linearly — the estimator's own growth rule — keeping device parity\n * for standard scripts and contract-correctness up to 128-byte ones.\n */\nconst PAYOUT_BOUND_ASSUMED_SCRIPT_LEN = 34;\n\n/** Shape/rate inputs the fee band is evaluated over. */\nexport interface PayoutFeeBandParams {\n /** Vault core (tx-graph) version — selects the floor's pinned model set. */\n vaultCoreVersion: number;\n /** Vault keeper count (N). */\n numVaultKeepers: number;\n /** Universal challenger count (M). */\n numUniversalChallengers: number;\n /** Security council size from the locked offchain params version. */\n councilSize: number;\n /** Version-locked tx-graph fee rate (sat/vB); anchors both band ends. */\n protocolFeeRate: bigint;\n}\n\n/**\n * Validate that the fee-band inputs lie in the proven/accepted domain:\n * `protocolFeeRate` in `[1, 0xffffffff]`, participant counts in `[1, 32]`,\n * `councilSize` a positive integer.\n *\n * @throws If `protocolFeeRate` is not a bigint within the device's range\n * @throws If a participant count is not an integer in the device range `[1, 32]`\n * @throws If `councilSize` is not an integer `>= 1` — the contract write path\n * (`ProtocolParams.sol`) rejects an empty council, and the WASM floor would\n * silently treat 0 as a 1-member council rather than erroring\n */\nexport function assertPayoutFeeBandDomain(params: PayoutFeeBandParams): void {\n // Fail fast on a rate the device's own parser would reject — also keeps the\n // fee-bound product within safe integer range.\n if (\n typeof params.protocolFeeRate !== \"bigint\" ||\n params.protocolFeeRate <= 0n ||\n params.protocolFeeRate > MAX_BASE_FEE_RATE_SAT_PER_VB\n ) {\n throw new Error(\n `protocolFeeRate must be in [1, ${MAX_BASE_FEE_RATE_SAT_PER_VB}] sat/vB, ` +\n `got ${params.protocolFeeRate}`,\n );\n }\n // Device participant range ([1, 32] per role, vault_intent.h) — also pins\n // the fee band to the domain its dominance proof was swept over\n // (accepted domain == proven domain).\n for (const [role, count] of [\n [\"keepers\", params.numVaultKeepers],\n [\"challengers\", params.numUniversalChallengers],\n ] as const) {\n if (\n !Number.isInteger(count) ||\n count < 1 ||\n count > MAX_PAYOUT_PARTICIPANTS_PER_ROLE\n ) {\n throw new Error(\n `Participant count for ${role} (${count}) is outside the device ` +\n `range [1, ${MAX_PAYOUT_PARTICIPANTS_PER_ROLE}].`,\n );\n }\n }\n // councilSize crosses the WASM boundary with no glue-side validation; a\n // non-integer would silently truncate at the u32 ABI and a 0 would be\n // silently promoted to a 1-member council by the pinned estimator.\n if (!Number.isInteger(params.councilSize) || params.councilSize < 1) {\n throw new Error(\n `councilSize must be an integer >= 1, got ${params.councilSize}`,\n );\n }\n}\n\n/**\n * Assert `floor <= implicitFeeSats <= ceiling` for a payout of this shape.\n * `out1Len` is `undefined` for the 2-output (no-commission) layouts.\n *\n * @throws If the fee is below the floor or above the extended device ceiling\n */\nexport async function assertPayoutFeeInBand(\n params: PayoutFeeBandParams,\n measured: {\n implicitFeeSats: number;\n out0Len: number;\n out1Len: number | undefined;\n },\n): Promise<void> {\n const { implicitFeeSats, out0Len, out1Len } = measured;\n const numParticipants =\n params.numVaultKeepers + params.numUniversalChallengers;\n const implicitFee = BigInt(implicitFeeSats);\n\n // Ceiling first: synchronous arithmetic, no WASM round-trip.\n // Only the PINNED outs[0] script extends the ceiling. out1Len is\n // VP-controlled (commission script deliberately unpinned) — including it\n // would let a padded script widen the burnable band by up to 94 vB x rate.\n // Honest long-commission builds still fit: the flat model's >=175 vB\n // headroom over the exact estimator vsize absorbs the 94 vB with >=81 vB\n // to spare across the entire accepted domain.\n const scriptExcess = Math.max(0, out0Len - PAYOUT_BOUND_ASSUMED_SCRIPT_LEN);\n const maxPayoutVsize =\n MAX_PAYOUT_VSIZE_BASE +\n MAX_PAYOUT_VSIZE_PER_PARTICIPANT * numParticipants +\n scriptExcess;\n const maxFeeSats = params.protocolFeeRate * BigInt(maxPayoutVsize);\n if (implicitFee > maxFeeSats) {\n throw new Error(\n `Payout implicit fee ${implicitFeeSats} sats exceeds the safety cap ` +\n `of ${maxFeeSats} sats (${params.protocolFeeRate} sat/vB x ` +\n `${maxPayoutVsize} vB for ${numParticipants} ` +\n `participants); refusing to sign payout.`,\n );\n }\n\n // Local challengers are exactly the keeper count for every claimer role\n // (btc-vault graph.rs derive_challengers: VKs, or VP + N-1 VKs).\n // TODO: memoize if keeper counts grow enough for batch flows to feel it.\n const minFeeSats = await computePayoutFeeFloor(\n params.vaultCoreVersion,\n params.numVaultKeepers,\n params.numUniversalChallengers,\n params.numVaultKeepers,\n params.councilSize,\n out0Len,\n out1Len,\n params.protocolFeeRate,\n );\n if (implicitFee < minFeeSats) {\n throw new Error(\n `Payout implicit fee ${implicitFeeSats} sats is below the floor of ` +\n `${minFeeSats} sats (the smallest fee any known vault-provider ` +\n `build produces for this shape); refusing to sign payout.`,\n );\n }\n}\n","/**\n * Payout PSBT Builder Primitives\n *\n * This module provides pure functions for building unsigned payout PSBTs and extracting\n * Schnorr signatures from signed PSBTs. It uses WASM-generated scripts from the payout\n * connector and bitcoinjs-lib for PSBT construction.\n *\n * The Payout transaction references the Assert transaction (input 1).\n *\n * @module primitives/psbt/payout\n */\n\nimport {\n type Network,\n tapInternalPubkey,\n} from \"@babylonlabs-io/babylon-tbv-rust-wasm\";\nimport { Psbt, Transaction, type TxInput, type TxOutput } from \"bitcoinjs-lib\";\nimport { Buffer } from \"buffer\";\nimport { createPayoutScript } from \"../scripts/payout\";\nimport {\n TAPSCRIPT_LEAF_VERSION,\n deriveBip86ScriptPubKeyHex,\n hexToUint8Array,\n isValidHex,\n stripHexPrefix,\n uint8ArrayToHex,\n} from \"../utils/bitcoin\";\nimport {\n assertPayoutFeeBandDomain,\n assertPayoutFeeInBand,\n} from \"./assertPayoutFeeBand\";\nimport {\n ASSERT_PAYOUT_OUTPUT_INDEX,\n BPS_DENOMINATOR,\n DEPOSITOR_PAYOUT_INPUT_COUNT,\n MAX_PAYOUT_SCRIPT_LEN,\n MAX_VP_COMMISSION_BPS_EXCLUSIVE,\n NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT,\n PAYOUT_ANCHOR_DUST_SATS,\n PEGIN_VAULT_OUTPUT_INDEX,\n VP_CLAIMER_PAYOUT_OUTPUT_COUNT,\n} from \"./constants\";\n\n/**\n * Number of items in a Taproot script-path spend witness stack for a\n * single-signature script: [signature, script, controlBlock].\n *\n * The current payout script requires exactly one depositor signature. If the\n * protocol evolves to require multiple signatures in the payout script, this\n * invariant and the finalized-PSBT extraction path must be revisited because\n * the first witness item would no longer necessarily be the depositor's.\n */\nconst TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE = 3;\n\n/**\n * Parameters for building an unsigned Payout PSBT\n *\n * Payout is used in the challenge path after Assert, when the claimer proves validity.\n * Input 1 references the Assert transaction.\n */\nexport interface PayoutParams {\n /**\n * Vault core (tx-graph) version the vault was registered under — the\n * vault's stamped on-chain `vaultCoreVersion`. Selects which graph's\n * payout connector scripts are derived.\n */\n vaultCoreVersion: number;\n\n /**\n * Payout transaction hex (unsigned)\n * This is the transaction that needs to be signed by the depositor\n */\n payoutTxHex: string;\n\n /**\n * Assert transaction hex\n * Payout input 1 references Assert output 0\n */\n assertTxHex: string;\n\n /**\n * Peg-in transaction hex\n * This transaction created the vault output that we're spending\n */\n peginTxHex: string;\n\n /**\n * Depositor's BTC public key (x-only, 64-char hex without 0x prefix)\n */\n depositorBtcPubkey: string;\n\n /**\n * Vault provider's BTC public key (x-only, 64-char hex)\n */\n vaultProviderBtcPubkey: string;\n\n /**\n * Vault keeper BTC public keys (x-only, 64-char hex)\n */\n vaultKeeperBtcPubkeys: string[];\n\n /**\n * Universal challenger BTC public keys (x-only, 64-char hex)\n */\n universalChallengerBtcPubkeys: string[];\n\n /**\n * CSV timelock in blocks for the PegIn output.\n */\n timelockPegin: number;\n\n /**\n * Bitcoin network\n */\n network: Network;\n\n /**\n * Claimer's x-only BTC public key (64-char hex, no prefix). Drives role\n * inference (VP / depositor-as-claimer / VK-claimer) inside `buildPayoutPsbt`.\n */\n claimerBtcPubkey: string;\n\n /**\n * On-chain registered depositor payout scriptPubKey (hex, 0x optional).\n * Expected outs[0].script for VP- and depositor-claimer roles; unused for\n * VK-claimer (its outs[0].script is derived from `claimerBtcPubkey`).\n */\n registeredPayoutScriptPubKey: string;\n\n /**\n * VP commission in basis points (`BTCVaultRegistry.vaultProviderCommissionBps`).\n * Caps the VP-claimer outs[1].value. The protocol minimum is enforced\n * upstream; here only `0 <= bps < 10_000` is checked, for safe cap math.\n */\n commissionBps: number;\n\n /**\n * Tx-graph fee rate (sat/vB) the graph was built with — the version-locked\n * `offchainParams.feeRate` at the vault's stamped `offchainParamsVersion`,\n * NOT a live read. Anchors both ends of the fee band.\n */\n protocolFeeRate: bigint;\n\n /**\n * Security council member count from the locked offchain params version.\n * Mirrors the upstream estimator's signature; at the current model pins the\n * council occupies a single taptree leaf regardless of size, so the floor\n * is council-size-invariant — passed for forward compatibility with future\n * pinned models.\n */\n councilSize: number;\n}\n\n/**\n * Result of building an unsigned payout PSBT\n */\nexport interface PayoutPsbtResult {\n /**\n * Unsigned PSBT hex ready for signing\n */\n psbtHex: string;\n}\n\n/**\n * Build unsigned Payout PSBT for depositor to sign.\n *\n * Payout is used in the **challenge path** when the claimer proves validity:\n * 1. Vault provider submits Claim transaction\n * 2. Challenge is raised during challenge period\n * 3. Claimer submits Assert transaction to prove validity\n * 4. Payout can be executed (references Assert tx)\n *\n * Payout transactions have the following structure:\n * - Input 0: from PeginTx output0 (signed by depositor)\n * - Input 1: from Assert output0 (NOT signed by depositor)\n *\n * @param params - Payout parameters\n * @returns Unsigned PSBT ready for depositor to sign\n *\n * @throws If payout transaction does not have exactly 2 inputs\n * @throws If input 0 does not spend PegIn:0 (vault UTXO)\n * @throws If input 1 does not spend Assert:0 (proof output)\n * @throws If previous output is not found for either input\n * @throws If sum of output values exceeds sum of input values (invalid tx)\n * @throws If the implicit fee (inputs − outputs) is outside the fee band —\n * below the floor or above the extended device ceiling (see\n * {@link assertPayoutFeeInBand})\n * @throws If `protocolFeeRate`, a participant count, or `councilSize` is\n * outside the accepted input domain (see {@link assertPayoutFeeBandDomain})\n * @throws If a non-anchor scriptPubKey length is outside `[1,\n * {@link MAX_PAYOUT_SCRIPT_LEN}]`\n * @throws If `claimerBtcPubkey` is not VP, depositor, or a registered VK\n * @throws If payout output count, outs[0] script, outs[last] anchor value, or\n * (VP-claimer) outs[1] commission cap do not match the protocol layout\n * @throws If `commissionBps` is not a non-negative integer below 10_000\n */\nexport async function buildPayoutPsbt(\n params: PayoutParams,\n): Promise<PayoutPsbtResult> {\n const feeBandParams = {\n vaultCoreVersion: params.vaultCoreVersion,\n numVaultKeepers: params.vaultKeeperBtcPubkeys.length,\n numUniversalChallengers: params.universalChallengerBtcPubkeys.length,\n councilSize: params.councilSize,\n protocolFeeRate: params.protocolFeeRate,\n };\n assertPayoutFeeBandDomain(feeBandParams);\n\n const payoutTx = Transaction.fromHex(stripHexPrefix(params.payoutTxHex));\n const peginTx = Transaction.fromHex(stripHexPrefix(params.peginTxHex));\n const assertTx = Transaction.fromHex(stripHexPrefix(params.assertTxHex));\n\n if (payoutTx.ins.length !== DEPOSITOR_PAYOUT_INPUT_COUNT) {\n throw new Error(\n `Payout transaction must have exactly ${DEPOSITOR_PAYOUT_INPUT_COUNT} ` +\n `inputs, got ${payoutTx.ins.length}`,\n );\n }\n const peginPrevOut = requirePrevOut(\n payoutTx.ins[0],\n 0,\n peginTx,\n \"PegIn\",\n PEGIN_VAULT_OUTPUT_INDEX,\n );\n const assertPrevOut = requirePrevOut(\n payoutTx.ins[1],\n 1,\n assertTx,\n \"Assert\",\n ASSERT_PAYOUT_OUTPUT_INDEX,\n );\n // Assert:0's value is deliberately NOT validated: the taproot sighash\n // commits to input 1's amount and outpoint, so a misstated value yields a\n // signature invalid against the real Assert tx — nothing to protect. (The\n // device's ==546 pin here is the known-buggy firmware behavior, Q15.)\n\n // Per-role output validation — blocks an extra attacker output or value\n // routed into a non-payout slot. Returns the layout-trusted script lengths\n // the fee band consumes.\n const { out0Len, out1Len } = assertPayoutOutputLayout(\n payoutTx,\n peginPrevOut.value,\n params,\n );\n\n const inputValueSats = peginPrevOut.value + assertPrevOut.value;\n let outputValueSats = 0;\n for (const out of payoutTx.outs) outputValueSats += out.value;\n if (outputValueSats > inputValueSats) {\n throw new Error(\n `Payout outputs (${outputValueSats} sats) exceed inputs ` +\n `(${inputValueSats} sats); invalid transaction.`,\n );\n }\n const implicitFeeSats = inputValueSats - outputValueSats;\n await assertPayoutFeeInBand(feeBandParams, {\n implicitFeeSats,\n out0Len,\n out1Len,\n });\n\n // Only assembly needs the WASM-derived script — derive it after the\n // transaction has passed every validation gate.\n const payoutConnector = await createPayoutScript({\n vaultCoreVersion: params.vaultCoreVersion,\n depositor: params.depositorBtcPubkey,\n vaultProvider: params.vaultProviderBtcPubkey,\n vaultKeepers: params.vaultKeeperBtcPubkeys,\n universalChallengers: params.universalChallengerBtcPubkeys,\n timelockPegin: params.timelockPegin,\n network: params.network,\n });\n\n return {\n psbtHex: assemblePayoutPsbt(\n payoutTx,\n peginPrevOut,\n assertPrevOut,\n payoutConnector,\n ),\n };\n}\n\n/**\n * Verify `payoutTx.ins[inputIndex]` spends `parentTx:expectedVout` (both txid\n * AND vout — the vout is the input-side anchor that prevents a malicious VP\n * from binding the depositor's signature to a different output of the same\n * parent) and return the referenced previous output.\n *\n * @internal Helper invoked by {@link buildPayoutPsbt}.\n */\nfunction requirePrevOut(\n input: TxInput,\n inputIndex: number,\n parentTx: Transaction,\n parentLabel: string,\n expectedVout: number,\n): TxOutput {\n const inputTxid = uint8ArrayToHex(\n new Uint8Array(input.hash).slice().reverse(),\n );\n const parentTxid = parentTx.getId();\n if (inputTxid !== parentTxid || input.index !== expectedVout) {\n throw new Error(\n `Input ${inputIndex} must spend ${parentLabel}:${expectedVout}. ` +\n `Expected ${parentTxid}:${expectedVout}, got ${inputTxid}:${input.index}`,\n );\n }\n const prevOut = parentTx.outs[input.index];\n if (!prevOut) {\n throw new Error(\n `Previous output not found for input ${inputIndex} ` +\n `(txid: ${inputTxid}, index: ${input.index})`,\n );\n }\n return prevOut;\n}\n\n/**\n * Assemble the unsigned PSBT from the validated payout transaction.\n *\n * IMPORTANT: For Taproot SIGHASH_DEFAULT (0x00), the sighash commits to ALL\n * inputs' prevouts, not just the one being signed — both inputs must be in\n * the PSBT so the wallet computes the sighash the VP expects.\n *\n * @internal Helper invoked by {@link buildPayoutPsbt}.\n */\nfunction assemblePayoutPsbt(\n payoutTx: Transaction,\n peginPrevOut: TxOutput,\n assertPrevOut: TxOutput,\n payoutConnector: { payoutScript: string; payoutControlBlock: string },\n): string {\n const psbt = new Psbt();\n psbt.setVersion(payoutTx.version);\n psbt.setLocktime(payoutTx.locktime);\n\n const [input0, input1] = payoutTx.ins;\n\n // Input 0: depositor signs via Taproot script path — carries tapLeafScript.\n psbt.addInput({\n hash: input0.hash,\n index: input0.index,\n sequence: input0.sequence,\n witnessUtxo: {\n script: peginPrevOut.script,\n value: peginPrevOut.value,\n },\n tapLeafScript: [\n {\n leafVersion: TAPSCRIPT_LEAF_VERSION,\n script: Buffer.from(hexToUint8Array(payoutConnector.payoutScript)),\n controlBlock: Buffer.from(\n hexToUint8Array(payoutConnector.payoutControlBlock),\n ),\n },\n ],\n tapInternalKey: Buffer.from(tapInternalPubkey),\n // sighashType omitted - defaults to SIGHASH_DEFAULT (0x00) for Taproot\n });\n\n // Input 1: from Assert — witnessUtxo only (in sighash, not signed by the\n // depositor), so no tapLeafScript.\n psbt.addInput({\n hash: input1.hash,\n index: input1.index,\n sequence: input1.sequence,\n witnessUtxo: {\n script: assertPrevOut.script,\n value: assertPrevOut.value,\n },\n });\n\n for (const output of payoutTx.outs) {\n psbt.addOutput({\n script: output.script,\n value: output.value,\n });\n }\n\n return psbt.toHex();\n}\n\n/**\n * Validate a payout transaction's output structure for the claimer's role,\n * keyed on `claimerBtcPubkey`. Pins per role: `outs.length`, `outs[0].script`,\n * `outs[last].value` (anchor dust), and (VP-claimer) `outs[1].value` capped at\n * `floor(peginValue × commissionBps / 10_000)`. Canonical layouts: VP-claimer\n * = [payout, commission, anchor]; depositor/VK-claimer = [payout, anchor].\n *\n * `outs[1].script` and `outs[last].script` are intentionally not pinned: the\n * value pins above bound depositor exposure regardless of where those outputs\n * are sent, so the value pins — not script pins — are load-bearing.\n *\n * Returns the layout-trusted non-anchor script lengths for the fee band:\n * `out0Len` from the pinned outs[0] script (registered payout script, or\n * derived BIP-86 for the VK-claimer role — see #2150 Stage 6 for the pending\n * registered-script switch); `out1Len` measured from the deliberately\n * unpinned VP-claimer commission output, `undefined` for the other roles.\n * Both are rejected outside the contract's registration cap `[1, 128]`.\n *\n * @internal Helper invoked by {@link buildPayoutPsbt}.\n */\nfunction assertPayoutOutputLayout(\n payoutTx: Transaction,\n peginValueSats: number,\n params: PayoutParams,\n): { out0Len: number; out1Len: number | undefined } {\n const {\n claimerBtcPubkey,\n vaultProviderBtcPubkey,\n depositorBtcPubkey,\n vaultKeeperBtcPubkeys,\n registeredPayoutScriptPubKey,\n commissionBps,\n } = params;\n\n if (!isValidHex(registeredPayoutScriptPubKey)) {\n throw new Error(\"Invalid registeredPayoutScriptPubKey: not valid hex\");\n }\n\n const claimer = stripHexPrefix(claimerBtcPubkey).toLowerCase();\n const vp = stripHexPrefix(vaultProviderBtcPubkey).toLowerCase();\n const dep = stripHexPrefix(depositorBtcPubkey).toLowerCase();\n const keepers = vaultKeeperBtcPubkeys.map((k) =>\n stripHexPrefix(k).toLowerCase(),\n );\n\n type Role = \"vp-claimer\" | \"depositor-as-claimer\" | \"vk-claimer\";\n let role: Role;\n let expectedOutCount: number;\n let expectedOut0ScriptHex: string;\n\n if (claimer === vp) {\n role = \"vp-claimer\";\n expectedOutCount = VP_CLAIMER_PAYOUT_OUTPUT_COUNT;\n expectedOut0ScriptHex = stripHexPrefix(registeredPayoutScriptPubKey);\n } else if (claimer === dep) {\n role = \"depositor-as-claimer\";\n expectedOutCount = NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT;\n expectedOut0ScriptHex = stripHexPrefix(registeredPayoutScriptPubKey);\n } else if (keepers.includes(claimer)) {\n role = \"vk-claimer\";\n expectedOutCount = NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT;\n expectedOut0ScriptHex = stripHexPrefix(deriveBip86ScriptPubKeyHex(claimer));\n } else {\n throw new Error(\n `Unknown claimer pubkey ${claimer}: not VP, depositor, or a registered vault keeper`,\n );\n }\n\n if (payoutTx.outs.length !== expectedOutCount) {\n throw new Error(\n `Payout transaction has ${payoutTx.outs.length} output(s), ` +\n `expected exactly ${expectedOutCount} for role ${role}.`,\n );\n }\n\n const expectedOut0Script = Buffer.from(expectedOut0ScriptHex, \"hex\");\n if (!payoutTx.outs[0].script.equals(expectedOut0Script)) {\n throw new Error(\n `Payout transaction output 0 does not pay the expected scriptPubKey for role ${role}`,\n );\n }\n\n const anchorIdx = expectedOutCount - 1;\n if (payoutTx.outs[anchorIdx].value !== PAYOUT_ANCHOR_DUST_SATS) {\n throw new Error(\n `Payout CPFP anchor (out ${anchorIdx}) value ${payoutTx.outs[anchorIdx].value} sats ` +\n `must equal ${PAYOUT_ANCHOR_DUST_SATS} sats`,\n );\n }\n\n if (role === \"vp-claimer\") {\n // Structural guard only — a non-negative integer below the bps\n // denominator, so the cap math `floor(peginValue * bps / 10_000)` is\n // meaningful. The protocol minimum is enforced at the trust boundary\n // (`prepareSigningContext`); a too-low value here is fail-safe.\n if (\n !Number.isInteger(commissionBps) ||\n commissionBps < 0 ||\n commissionBps >= MAX_VP_COMMISSION_BPS_EXCLUSIVE\n ) {\n throw new Error(\n `commissionBps must be an integer in ` +\n `[0, ${MAX_VP_COMMISSION_BPS_EXCLUSIVE}), got ${commissionBps}`,\n );\n }\n const maxCommissionSats = Math.floor(\n (peginValueSats * commissionBps) / BPS_DENOMINATOR,\n );\n if (payoutTx.outs[1].value > maxCommissionSats) {\n throw new Error(\n `Payout VP commission (out 1) value ${payoutTx.outs[1].value} sats ` +\n `exceeds cap ${maxCommissionSats} sats ` +\n `(${commissionBps} bps of peginValue=${peginValueSats})`,\n );\n }\n }\n\n const out0Len = expectedOut0Script.length;\n if (out0Len === 0 || out0Len > MAX_PAYOUT_SCRIPT_LEN) {\n throw new Error(\n `Payout receiver scriptPubKey length ${out0Len} is outside the ` +\n `contract's registration cap [1, ${MAX_PAYOUT_SCRIPT_LEN}]; ` +\n `refusing to sign payout.`,\n );\n }\n const out1Len =\n role === \"vp-claimer\" ? payoutTx.outs[1].script.length : undefined;\n if (\n out1Len !== undefined &&\n (out1Len === 0 || out1Len > MAX_PAYOUT_SCRIPT_LEN)\n ) {\n throw new Error(\n `Payout commission scriptPubKey length ${out1Len} is outside the ` +\n `contract's registration cap [1, ${MAX_PAYOUT_SCRIPT_LEN}]; ` +\n `refusing to sign payout.`,\n );\n }\n\n return { out0Len, out1Len };\n}\n\n/**\n * Extract Schnorr signature from signed payout PSBT.\n *\n * This function supports two cases:\n * 1. Non-finalized PSBT: Extracts from tapScriptSig field\n * 2. Finalized PSBT: Extracts from witness data\n *\n * The signature is returned as a 64-byte hex string (128 hex characters).\n * Payout signatures must use implicit Taproot SIGHASH_DEFAULT, which is\n * encoded by omitting the sighash byte.\n *\n * @param signedPsbtHex - Signed PSBT hex\n * @param depositorPubkey - Depositor's public key (x-only, 64-char hex)\n * @param inputIndex - Input index to extract signature from (default: 0)\n * @returns 64-byte Schnorr signature (128 hex characters, no sighash flag)\n *\n * @throws If no signature is found in the PSBT\n * @throws If the signature has an unexpected length\n */\nexport function extractPayoutSignature(\n signedPsbtHex: string,\n depositorPubkey: string,\n inputIndex = 0,\n): string {\n const signedPsbt = Psbt.fromHex(signedPsbtHex);\n\n if (inputIndex >= signedPsbt.data.inputs.length) {\n throw new Error(\n `Input index ${inputIndex} out of range (${signedPsbt.data.inputs.length} inputs)`,\n );\n }\n\n const input = signedPsbt.data.inputs[inputIndex];\n\n // Case 1: Non-finalized PSBT — extract from tapScriptSig\n if (input.tapScriptSig && input.tapScriptSig.length > 0) {\n const depositorPubkeyBytes = hexToUint8Array(depositorPubkey);\n\n for (const sigEntry of input.tapScriptSig) {\n if (sigEntry.pubkey.equals(Buffer.from(depositorPubkeyBytes))) {\n return extractSchnorrSig(sigEntry.signature, inputIndex);\n }\n }\n\n throw new Error(\n `No signature found for depositor pubkey: ${depositorPubkey} at input ${inputIndex}`,\n );\n }\n\n // Case 2: Finalized PSBT — extract from finalScriptWitness\n // Taproot single-signature script-path witness: [signature, script, controlBlock].\n // Enforce the exact stack size so that if a wallet produces an unexpected\n // finalization (e.g. a multi-signature stack, an annex, or malformed data),\n // we fail loudly instead of silently returning witnessStack[0] which may\n // not be the depositor's signature.\n if (input.finalScriptWitness && input.finalScriptWitness.length > 0) {\n const witnessStack = parseWitnessStack(input.finalScriptWitness);\n if (witnessStack.length !== TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE) {\n throw new Error(\n `Unexpected finalized witness stack size at input ${inputIndex}: ` +\n `expected ${TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE} items (signature, script, controlBlock), ` +\n `got ${witnessStack.length}`,\n );\n }\n return extractSchnorrSig(witnessStack[0], inputIndex);\n }\n\n throw new Error(\n `No tapScriptSig or finalScriptWitness found in signed PSBT at input ${inputIndex}`,\n );\n}\n\n/**\n * Extract and validate a 64-byte Schnorr signature.\n * Rejects 65-byte signatures because the appended sighash byte changes the\n * Taproot message being signed; stripping it would produce an unverifiable\n * SIGHASH_DEFAULT signature.\n * @internal\n */\nfunction extractSchnorrSig(sig: Uint8Array, inputIndex: number): string {\n if (sig.length === 64) {\n return uint8ArrayToHex(new Uint8Array(sig));\n }\n if (sig.length === 65) {\n throw new Error(\n `Unexpected sighash byte 0x${sig[64].toString(16).padStart(2, \"0\")} at input ${inputIndex}. ` +\n \"Expected implicit SIGHASH_DEFAULT as a 64-byte signature.\",\n );\n }\n throw new Error(\n `Unexpected signature length at input ${inputIndex}: ${sig.length}`,\n );\n}\n\n/**\n * Parse a BIP-141 serialized witness stack into individual stack items.\n * Format: [varint item_count] [varint len, data]...\n *\n * Throws on malformed input (truncated buffer, 8-byte varints, or trailing\n * bytes) so callers never receive silently-corrupted witness items.\n * @internal\n */\nfunction parseWitnessStack(witness: Buffer): Buffer[] {\n const items: Buffer[] = [];\n let offset = 0;\n\n const requireBytes = (n: number): void => {\n if (offset + n > witness.length) {\n throw new Error(\n `Malformed witness data: need ${n} byte(s) at offset ${offset}, only ${witness.length - offset} remaining`,\n );\n }\n };\n\n const readVarInt = (): number => {\n requireBytes(1);\n const first = witness[offset++];\n if (first < 0xfd) return first;\n if (first === 0xfd) {\n requireBytes(2);\n const val = (witness[offset] | (witness[offset + 1] << 8)) >>> 0;\n offset += 2;\n return val;\n }\n if (first === 0xfe) {\n requireBytes(4);\n const val =\n (witness[offset] |\n (witness[offset + 1] << 8) |\n (witness[offset + 2] << 16) |\n (witness[offset + 3] << 24)) >>>\n 0;\n offset += 4;\n return val;\n }\n // 0xff — 8-byte varint. Not used for witness sizes in practice and JS\n // numbers cannot represent all 64-bit values exactly, so reject rather\n // than risk silent truncation.\n throw new Error(\n `Malformed witness data: 8-byte varint (0xff) not supported at offset ${offset - 1}`,\n );\n };\n\n const count = readVarInt();\n for (let i = 0; i < count; i++) {\n const len = readVarInt();\n requireBytes(len);\n items.push(Buffer.from(witness.subarray(offset, offset + len)));\n offset += len;\n }\n\n if (offset !== witness.length) {\n throw new Error(\n `Malformed witness data: ${witness.length - offset} trailing byte(s) after parsing ${count} item(s)`,\n );\n }\n\n return items;\n}\n","/**\n * Asserts a wallet-returned PSBT encodes the same unsigned transaction\n * as the locally-built PSBT we asked the wallet to sign. Per-input PSBT\n * metadata (witnessUtxo, tapLeafScript, sighashType) is intentionally NOT\n * compared — those fields are committed to the Schnorr sighash and the\n * vault provider's `verify_depositor_signature` rejects mismatches there.\n * This primitive defends the path where a colluding VP would otherwise\n * accept a wallet-substituted signature.\n */\n\nimport { Buffer } from \"buffer\";\n\nimport { Psbt } from \"bitcoinjs-lib\";\n\n/**\n * Thrown when a wallet-returned PSBT encodes a different unsigned\n * transaction than the one the caller asked the wallet to sign.\n */\nexport class PsbtSubstitutionError extends Error {\n constructor(detail: string) {\n super(\n `Wallet returned a PSBT for a different transaction: ${detail}`,\n );\n this.name = \"PsbtSubstitutionError\";\n }\n}\n\nexport interface AssertPsbtUnsignedTxMatchesParams {\n /** PSBT we built locally and asked the wallet to sign. */\n requestedPsbtHex: string;\n /** PSBT the wallet returned after signing. */\n returnedPsbtHex: string;\n}\n\nfunction parsePsbt(label: \"requested\" | \"returned\", hex: string): Psbt {\n try {\n return Psbt.fromHex(hex);\n } catch (cause) {\n const reason = cause instanceof Error ? cause.message : String(cause);\n throw new Error(`Failed to parse ${label} PSBT: ${reason}`);\n }\n}\n\n/**\n * Length of the hex prefix included in mismatch errors. Short enough that\n * full prevout txids and output scriptPubKeys never reach logs / error\n * trackers, long enough to disambiguate during forensic triage.\n */\nconst REDACTED_HEX_PREFIX_LEN = 8;\n\nfunction redactHex(buf: Buffer): string {\n return `${buf.toString(\"hex\").slice(0, REDACTED_HEX_PREFIX_LEN)}…`;\n}\n\n/**\n * `bitcoinjs-lib` exposes `txInputs[i].hash` in internal little-endian form;\n * a human reading logs expects the big-endian txid an explorer would show.\n * Reverse before truncating so the surfaced prefix matches what an operator\n * can search for.\n */\nfunction redactTxid(internalHash: Buffer): string {\n const reversed = Buffer.from(internalHash).reverse();\n return redactHex(reversed);\n}\n\n/**\n * Compare two PSBTs and throw `PsbtSubstitutionError` unless they encode\n * the same unsigned transaction (version, locktime, inputs, outputs).\n *\n * @throws PsbtSubstitutionError on any mismatch in the unsigned tx\n * @throws Error if either PSBT cannot be parsed\n */\nexport function assertPsbtUnsignedTxMatches(\n params: AssertPsbtUnsignedTxMatchesParams,\n): void {\n const requested = parsePsbt(\"requested\", params.requestedPsbtHex);\n const returned = parsePsbt(\"returned\", params.returnedPsbtHex);\n\n if (requested.version !== returned.version) {\n throw new PsbtSubstitutionError(\n `tx version differs (requested=${requested.version}, returned=${returned.version})`,\n );\n }\n if (requested.locktime !== returned.locktime) {\n throw new PsbtSubstitutionError(\n `tx locktime differs (requested=${requested.locktime}, returned=${returned.locktime})`,\n );\n }\n if (requested.txInputs.length !== returned.txInputs.length) {\n throw new PsbtSubstitutionError(\n `input count differs (requested=${requested.txInputs.length}, returned=${returned.txInputs.length})`,\n );\n }\n if (requested.txOutputs.length !== returned.txOutputs.length) {\n throw new PsbtSubstitutionError(\n `output count differs (requested=${requested.txOutputs.length}, returned=${returned.txOutputs.length})`,\n );\n }\n for (let i = 0; i < requested.txInputs.length; i++) {\n const r = requested.txInputs[i];\n const s = returned.txInputs[i];\n if (!r.hash.equals(s.hash)) {\n throw new PsbtSubstitutionError(\n `input ${i} prevout txid differs (requested=${redactTxid(r.hash)}, returned=${redactTxid(s.hash)})`,\n );\n }\n if (r.index !== s.index) {\n throw new PsbtSubstitutionError(\n `input ${i} prevout vout differs (requested=${r.index}, returned=${s.index})`,\n );\n }\n if (r.sequence !== s.sequence) {\n throw new PsbtSubstitutionError(\n `input ${i} sequence differs (requested=${r.sequence}, returned=${s.sequence})`,\n );\n }\n }\n for (let i = 0; i < requested.txOutputs.length; i++) {\n const r = requested.txOutputs[i];\n const s = returned.txOutputs[i];\n if (!r.script.equals(s.script)) {\n throw new PsbtSubstitutionError(\n `output ${i} scriptPubKey differs (requested=${redactHex(r.script)}, returned=${redactHex(s.script)})`,\n );\n }\n if (r.value !== s.value) {\n throw new PsbtSubstitutionError(\n `output ${i} value differs (requested=${r.value}, returned=${s.value})`,\n );\n }\n }\n}\n","/**\n * Independent BIP-340 verification of a wallet-returned Taproot script-path\n * Schnorr signature against an independently-recomputed sighash.\n *\n * Critical Path #7 (CLAUDE.md): the SDK requests script-path signatures with\n * `useTweakedSigner: false, autoFinalized: false`. Wallet support for the\n * untweaked-key flag is inconsistent — older OKX / mobile bridges silently sign\n * with the *tweaked* key, Keystone ignores the flag — and a compromised\n * extension can stuff a 64-byte stub into `tapScriptSig`. A bad signature that\n * the SDK forwards is only caught on broadcast; in the worst case it passes the\n * VP off-chain but Bitcoin rejects it, leaving the depositor's BTC locked in the\n * HTLC until `timelockRefund` matures. This guard rejects such signatures before\n * they are trusted.\n *\n * Why verify against the *locally-built* PSBT, not the wallet-returned one:\n * `assertPsbtUnsignedTxMatches` pins the unsigned transaction but deliberately\n * skips per-input metadata (`witnessUtxo`, `tapLeafScript`). A malicious wallet\n * could rewrite those consistently in the returned PSBT so a wrong-message\n * signature self-validates. The trusted prevout scripts/values and leaf script\n * therefore come from the PSBT we built ourselves (derived from on-chain / WASM\n * sources); only the 64-byte signature comes from the wallet.\n *\n * Reuses the exact primitives `bip322Verify.ts` already depends on — no new\n * dependency:\n * - `@bitcoin-js/tiny-secp256k1-asmjs` → `verifySchnorr`\n * - `bitcoinjs-lib` → `Transaction.hashForWitnessV1`, `crypto.taggedHash` (TapLeaf hash)\n *\n * @module tbv/core/primitives/psbt/verifyScriptPathSchnorrSignature\n */\n\nimport * as ecc from \"@bitcoin-js/tiny-secp256k1-asmjs\";\nimport { Psbt, Transaction, crypto as bcrypto } from \"bitcoinjs-lib\";\n\nimport { Buffer } from \"buffer\";\n\nimport {\n SCHNORR_SIG_HEX_LEN,\n TAPSCRIPT_LEAF_VERSION,\n X_ONLY_PUBKEY_HEX_LEN,\n hexToUint8Array,\n stripHexPrefix,\n} from \"../utils/bitcoin\";\n\n// Bitcoin CompactSize (varint) prefix markers — values fixed by the protocol.\n// https://developer.bitcoin.org/reference/transactions.html#compactsize-unsigned-integers\nconst COMPACT_SIZE_UINT16_PREFIX = 0xfd; // value in [0xfd, 0xffff] → 0xfd + uint16 LE\nconst COMPACT_SIZE_UINT32_PREFIX = 0xfe; // value in [0x10000, 0xffffffff] → 0xfe + uint32 LE\nconst COMPACT_SIZE_UINT16_MAX = 0xffff;\nconst COMPACT_SIZE_UINT32_MAX = 0xffffffff;\n\n/**\n * Encode a length as a Bitcoin CompactSize (varint). Tapscript leaf scripts can\n * exceed 252 bytes (WOTS scripts), so the multi-byte forms are required, not\n * just the single-byte fast path.\n */\nfunction encodeCompactSize(n: number): Buffer {\n if (n < COMPACT_SIZE_UINT16_PREFIX) {\n return Buffer.from([n]);\n }\n if (n <= COMPACT_SIZE_UINT16_MAX) {\n const value = Buffer.alloc(2); // uint16, little-endian\n value.writeUInt16LE(n);\n return Buffer.concat([Buffer.from([COMPACT_SIZE_UINT16_PREFIX]), value]);\n }\n if (n <= COMPACT_SIZE_UINT32_MAX) {\n const value = Buffer.alloc(4); // uint32, little-endian\n value.writeUInt32LE(n);\n return Buffer.concat([Buffer.from([COMPACT_SIZE_UINT32_PREFIX]), value]);\n }\n throw new Error(`Script too large to encode as CompactSize: ${n} bytes`);\n}\n\n/** BIP-341 tag for the TapLeaf hash. */\nconst TAPLEAF_TAG = \"TapLeaf\";\n\n/**\n * Compute the BIP-341 TapLeaf hash for a tapscript leaf:\n * `tagged_hash(\"TapLeaf\", leaf_version || compact_size(script) || script)`.\n */\nfunction computeTapLeafHash(leafVersion: number, script: Uint8Array): Buffer {\n const preimage = Buffer.concat([\n Buffer.from([leafVersion]),\n encodeCompactSize(script.length),\n Buffer.from(script),\n ]);\n return bcrypto.taggedHash(TAPLEAF_TAG, preimage);\n}\n\nexport interface VerifyScriptPathSchnorrSignatureParams {\n /**\n * Hex of the PSBT we built locally and sent to the wallet (the trusted\n * source of prevout scripts/values and the leaf script). NOT the\n * wallet-returned PSBT.\n */\n requestedPsbtHex: string;\n /** The 64-byte Schnorr signature extracted from the wallet's response (128 hex chars). */\n signatureHex: string;\n /** X-only public key (64 hex chars) the wallet signed the script-path leaf with. */\n signerXOnlyPubkeyHex: string;\n /** Index of the input the signature is for. */\n inputIndex: number;\n}\n\n/**\n * Assert that `signatureHex` is a valid BIP-340 Schnorr signature by the\n * `signerXOnlyPubkeyHex` key over the Taproot script-path sighash of\n * `requestedPsbtHex` input `inputIndex` (SIGHASH_DEFAULT).\n *\n * @throws If the requested PSBT is malformed, lacks the prevout/leaf data needed\n * to recompute the sighash, or the signature does not verify.\n */\nexport function assertScriptPathSchnorrSignature(\n params: VerifyScriptPathSchnorrSignatureParams,\n): void {\n const { requestedPsbtHex, signatureHex, signerXOnlyPubkeyHex, inputIndex } =\n params;\n\n const signatureRaw = stripHexPrefix(signatureHex);\n if (signatureRaw.length !== SCHNORR_SIG_HEX_LEN) {\n throw new Error(\n `Schnorr signature for input ${inputIndex} must be ${SCHNORR_SIG_HEX_LEN} hex chars ` +\n `(64 bytes), got ${signatureRaw.length}.`,\n );\n }\n\n const signerXOnly = stripHexPrefix(signerXOnlyPubkeyHex);\n if (signerXOnly.length !== X_ONLY_PUBKEY_HEX_LEN) {\n throw new Error(\n `Signer x-only pubkey for input ${inputIndex} must be ${X_ONLY_PUBKEY_HEX_LEN} hex chars ` +\n `(32 bytes), got ${signerXOnly.length}.`,\n );\n }\n\n const psbt = Psbt.fromHex(requestedPsbtHex);\n\n if (inputIndex < 0 || inputIndex >= psbt.data.inputs.length) {\n throw new Error(\n `Input index ${inputIndex} out of range (${psbt.data.inputs.length} inputs).`,\n );\n }\n\n // Taproot's sighash commits to every input's prevout (script + value), so all\n // inputs must carry a witnessUtxo. A missing one is a build error, not a\n // value we can default — fail loudly.\n const prevOutScripts: Buffer[] = [];\n const values: number[] = [];\n for (let i = 0; i < psbt.data.inputs.length; i++) {\n const witnessUtxo = psbt.data.inputs[i].witnessUtxo;\n if (!witnessUtxo) {\n throw new Error(\n `Cannot verify signature: input ${i} of the requested PSBT has no witnessUtxo ` +\n `(required to recompute the Taproot sighash).`,\n );\n }\n prevOutScripts.push(witnessUtxo.script);\n values.push(witnessUtxo.value);\n }\n\n // The signed input must expose exactly one tapLeafScript — the leaf the\n // depositor signs. Zero means we sent the wrong PSBT; more than one means an\n // ambiguous spend path we never construct for a single-signature input.\n const tapLeafScripts = psbt.data.inputs[inputIndex].tapLeafScript;\n if (!tapLeafScripts || tapLeafScripts.length !== 1) {\n throw new Error(\n `Cannot verify signature: input ${inputIndex} of the requested PSBT must have exactly ` +\n `one tapLeafScript, got ${tapLeafScripts?.length ?? 0}.`,\n );\n }\n const leaf = tapLeafScripts[0];\n if (leaf.leafVersion !== TAPSCRIPT_LEAF_VERSION) {\n throw new Error(\n `Cannot verify signature: input ${inputIndex} tapLeafScript has leaf version ` +\n `0x${leaf.leafVersion.toString(16)}, expected 0x${TAPSCRIPT_LEAF_VERSION.toString(16)}.`,\n );\n }\n\n const leafHash = computeTapLeafHash(leaf.leafVersion, leaf.script);\n\n // Reconstruct the unsigned transaction from the requested PSBT using only\n // public bitcoinjs-lib API (same pattern as bip322Verify.ts), then compute the\n // BIP-341 script-path sighash with SIGHASH_DEFAULT.\n const tx = new Transaction();\n tx.version = psbt.version;\n tx.locktime = psbt.locktime;\n for (const input of psbt.txInputs) {\n tx.addInput(input.hash, input.index, input.sequence);\n }\n for (const output of psbt.txOutputs) {\n tx.addOutput(output.script, output.value);\n }\n\n const sighash = tx.hashForWitnessV1(\n inputIndex,\n prevOutScripts,\n values,\n Transaction.SIGHASH_DEFAULT,\n leafHash,\n );\n\n const isValid = ecc.verifySchnorr(\n sighash,\n hexToUint8Array(signerXOnly),\n hexToUint8Array(signatureRaw),\n );\n\n if (!isValid) {\n throw new Error(\n `Schnorr signature for input ${inputIndex} (signer ${signerXOnly}) does not verify ` +\n `against the expected Taproot script-path sighash. The wallet may have signed with ` +\n `the tweaked key, signed a different transaction, or returned an invalid signature.`,\n );\n }\n}\n"],"names":["assertWasmPeginSizing","result","params","expectedCount","expectedClaimValue","computeMinClaimValue","anchor","peginP2aAnchorOutput","anchorValue","expectedPeginFee","computeMinPeginFee","expectedReserve","maxImpliedReserve","MAX_REASONABLE_PEGIN_VBYTES","i","requested","peginAmount","htlcValue","impliedReserve","assertEncodedHtlcOutputsMatch","outputs","htlcValues","htlcScriptPubKeys","encodedValue","encodedScript","expectedScript","AUTH_ANCHOR_HASH_HEX_LEN","HEX_PATTERN","buildPrePeginPsbt","authAnchorHash","normalizeAuthAnchorHash","createPrePeginTransaction","minPeginFee","parsed","parseUnfundedWasmTransaction","totalOutputValue","sum","o","authAnchorVout","value","cleaned","buildPeginTxFromFundedPrePegin","buildPeginTxFromPrePegin","assertPeginTxShape","PEGIN_BASE_OUTPUT_COUNT","PEGIN_DEPOSITOR_CLAIM_VOUT","version","validatePeginP2aAnchor","expectedOutputCount","peginTx","Transaction","stripHexPrefix","fundedPrePeginTxid","inputTxid","uint8ArrayToHex","requestedAmount","encodedVaultOut","encodedVaultScript","expectedVaultScript","encodedTxid","encodedClaimOut","expectedClaimScript","deriveDepositorClaimScriptPubKey","depositorPubkey","claimLeafScript","bscript","Buffer","hexToUint8Array","opcodes","output","payments","tapInternalPubkey","createPayoutScript","connector","createPayoutConnector","MAX_PAYOUT_VSIZE_BASE","MAX_PAYOUT_VSIZE_PER_PARTICIPANT","MAX_BASE_FEE_RATE_SAT_PER_VB","MAX_PAYOUT_PARTICIPANTS_PER_ROLE","PAYOUT_BOUND_ASSUMED_SCRIPT_LEN","assertPayoutFeeBandDomain","role","count","assertPayoutFeeInBand","measured","implicitFeeSats","out0Len","out1Len","numParticipants","implicitFee","scriptExcess","maxPayoutVsize","maxFeeSats","minFeeSats","computePayoutFeeFloor","TAPROOT_SINGLE_SIG_WITNESS_STACK_SIZE","buildPayoutPsbt","feeBandParams","payoutTx","assertTx","DEPOSITOR_PAYOUT_INPUT_COUNT","peginPrevOut","requirePrevOut","PEGIN_VAULT_OUTPUT_INDEX","assertPrevOut","ASSERT_PAYOUT_OUTPUT_INDEX","assertPayoutOutputLayout","inputValueSats","outputValueSats","out","payoutConnector","assemblePayoutPsbt","input","inputIndex","parentTx","parentLabel","expectedVout","parentTxid","prevOut","psbt","Psbt","input0","input1","TAPSCRIPT_LEAF_VERSION","peginValueSats","claimerBtcPubkey","vaultProviderBtcPubkey","depositorBtcPubkey","vaultKeeperBtcPubkeys","registeredPayoutScriptPubKey","commissionBps","isValidHex","claimer","vp","dep","keepers","k","expectedOutCount","expectedOut0ScriptHex","VP_CLAIMER_PAYOUT_OUTPUT_COUNT","NON_VP_CLAIMER_PAYOUT_OUTPUT_COUNT","deriveBip86ScriptPubKeyHex","expectedOut0Script","anchorIdx","PAYOUT_ANCHOR_DUST_SATS","MAX_VP_COMMISSION_BPS_EXCLUSIVE","maxCommissionSats","BPS_DENOMINATOR","MAX_PAYOUT_SCRIPT_LEN","extractPayoutSignature","signedPsbtHex","signedPsbt","depositorPubkeyBytes","sigEntry","extractSchnorrSig","witnessStack","parseWitnessStack","sig","witness","items","offset","requireBytes","n","readVarInt","first","val","len","PsbtSubstitutionError","detail","parsePsbt","label","hex","cause","reason","REDACTED_HEX_PREFIX_LEN","redactHex","buf","redactTxid","internalHash","reversed","assertPsbtUnsignedTxMatches","returned","s","COMPACT_SIZE_UINT16_PREFIX","COMPACT_SIZE_UINT32_PREFIX","COMPACT_SIZE_UINT16_MAX","COMPACT_SIZE_UINT32_MAX","encodeCompactSize","TAPLEAF_TAG","computeTapLeafHash","leafVersion","script","preimage","bcrypto","assertScriptPathSchnorrSignature","requestedPsbtHex","signatureHex","signerXOnlyPubkeyHex","signatureRaw","SCHNORR_SIG_HEX_LEN","signerXOnly","X_ONLY_PUBKEY_HEX_LEN","prevOutScripts","values","witnessUtxo","tapLeafScripts","leaf","leafHash","tx","sighash","ecc"],"mappings":"wjBAoDA,eAAsBA,EACpBC,EACAC,EACiB,CACjB,MAAMC,EAAgBD,EAAO,aAAa,OAI1C,GAAID,EAAO,WAAW,SAAWE,EAC/B,MAAM,IAAI,MACR,2BAA2BF,EAAO,WAAW,MAAM,4BACrCE,CAAa,+BAAA,EAG/B,GACEF,EAAO,aAAa,SAAWE,GAC/BF,EAAO,kBAAkB,SAAWE,GACpCF,EAAO,cAAc,SAAWE,EAEhC,MAAM,IAAI,MACR,gEACiBF,EAAO,WAAW,MAAM,kBACvBA,EAAO,aAAa,MAAM,uBACrBA,EAAO,kBAAkB,MAAM,mBACnCA,EAAO,cAAc,MAAM,eAChCE,CAAa,QAAA,EAO/B,GAAIF,EAAO,qBAAuB,GAChC,MAAM,IAAI,MACR,4DACKA,EAAO,mBAAmB,iBAAA,EAGnC,MAAMG,EAAqB,MAAMC,EAAAA,qBAE/BH,EAAO,iBACPA,EAAO,oBACPA,EAAO,2BAA2B,OAClCA,EAAO,cACPA,EAAO,YACPA,EAAO,OAAA,EAET,GAAID,EAAO,sBAAwBG,EACjC,MAAM,IAAI,MACR,sCAAsCH,EAAO,mBAAmB,kEAE3DG,CAAkB,sBAAsBF,EAAO,gBAAgB,yBAC3CA,EAAO,mBAAmB,6BACtBA,EAAO,2BAA2B,MAAM,mBAClDA,EAAO,aAAa,iBAAiBA,EAAO,WAAW,aAC7DA,EAAO,OAAO,IAAA,EAU/B,MAAMI,EAAS,MAAMC,uBAAqBL,EAAO,gBAAgB,EAC3DM,GAAcF,GAAA,YAAAA,EAAQ,QAAS,GAC/BG,EAAmB,MAAMC,EAAAA,mBAC7BR,EAAO,iBACPA,EAAO,mBAAmB,OAC1BA,EAAO,2BAA2B,OAClCA,EAAO,eAAA,EAEHS,EAAkBF,EAAmBD,EAMrCI,EACJV,EAAO,gBAAkBW,EAAAA,4BAE3B,QAASC,EAAI,EAAGA,EAAIX,EAAeW,IAAK,CACtC,MAAMC,EAAYb,EAAO,aAAaY,CAAC,EACjCE,EAAcf,EAAO,aAAaa,CAAC,EACnCG,EAAYhB,EAAO,WAAWa,CAAC,EAOrC,GAAIE,IAAgBD,EAClB,MAAM,IAAI,MACR,8BAA8BD,CAAC,KAAKE,CAAW,wCACzBD,CAAS,sFAAA,EAInC,GAAIC,GAAe,GACjB,MAAM,IAAI,MACR,8BAA8BF,CAAC,sBAAsBE,CAAW,kBAAA,EAIpE,GAAIC,GAAa,GACf,MAAM,IAAI,MACR,4BAA4BH,CAAC,sBAAsBG,CAAS,kBAAA,EAShE,MAAMC,EAAiBD,EAAYD,EAAcf,EAAO,oBAKxD,GAAIiB,GAAkB,GACpB,MAAM,IAAI,MACR,4BAA4BJ,CAAC,KAAKG,CAAS,wCACpBD,CAAW,0BAC7Bf,EAAO,mBAAmB,uCAClBiB,CAAc,IAAA,EAG/B,GAAIA,EAAiBN,EACnB,MAAM,IAAI,MACR,2CAA2CE,CAAC,MAAMI,CAAc,sCACzBN,CAAiB,yBAClCV,EAAO,eAAe,MACvCW,EAAAA,2BAA2B,uBAAuBI,CAAS,4BAAA,EAIpE,GAAIC,IAAmBP,EACrB,MAAM,IAAI,MACR,4BAA4BG,CAAC,KAAKG,CAAS,0CAChBC,CAAc,0BACpCP,CAAe,qBAAqBF,CAAgB,gBAC1CD,CAAW,yBACrBN,EAAO,gBAAgB,kBACvBA,EAAO,mBAAmB,MAAM,0BAChCA,EAAO,2BAA2B,MAAM,qBACxCA,EAAO,eAAe,IAAA,CAGjC,CAEA,OAAOO,CACT,CAwBO,SAASU,EACdC,EACAC,EACAC,EACM,CACN,GAAIF,EAAQ,OAASC,EAAW,OAC9B,MAAM,IAAI,MACR,4BAA4BD,EAAQ,MAAM,8BACrCC,EAAW,MAAM,4CAAA,EAI1B,QAASP,EAAI,EAAGA,EAAIO,EAAW,OAAQP,IAAK,CAC1C,MAAMS,EAAe,OAAOH,EAAQN,CAAC,EAAE,KAAK,EAC5C,GAAIS,IAAiBF,EAAWP,CAAC,EAC/B,MAAM,IAAI,MACR,iCAAiCA,CAAC,WAAWS,CAAY,+CAClBF,EAAWP,CAAC,CAAC,4DAAA,EAKxD,MAAMU,EAAgBJ,EAAQN,CAAC,EAAE,OAAO,SAAS,KAAK,EAAE,YAAA,EAClDW,EAAiBH,EAAkBR,CAAC,EAAE,YAAA,EAC5C,GAAIU,IAAkBC,EACpB,MAAM,IAAI,MACR,iCAAiCX,CAAC,kBAAkBU,CAAa,sDACfC,CAAc,GAAA,CAGtE,CACF,CCzKA,MAAMC,EAA2B,GAE3BC,EAAc,iBAyFpB,eAAsBC,EACpB1B,EAC6B,CAC7B,MAAM2B,EAAiBC,EAAwB5B,EAAO,cAAc,EAE9DD,EAAS,MAAM8B,4BAA0B,CAC7C,eAAgB7B,EAAO,iBACvB,gBAAiBA,EAAO,gBACxB,oBAAqBA,EAAO,oBAC5B,mBAAoBA,EAAO,mBAC3B,2BAA4BA,EAAO,2BACnC,UAAW,CAAC,GAAGA,EAAO,SAAS,EAC/B,eAAgBA,EAAO,eACvB,aAAc,CAAC,GAAGA,EAAO,YAAY,EACrC,QAASA,EAAO,QAChB,gBAAiBA,EAAO,gBACxB,oBAAqBA,EAAO,oBAC5B,cAAeA,EAAO,cACtB,YAAaA,EAAO,YACpB,QAASA,EAAO,QAChB,eAAA2B,CAAA,CACD,EAMKG,EAAc,MAAMhC,EAAsBC,EAAQC,CAAM,EAKxD+B,EAASC,EAAAA,6BAA6BjC,EAAO,KAAK,EAMxDkB,EACEc,EAAO,QACPhC,EAAO,WACPA,EAAO,iBAAA,EAGT,MAAMkC,EAAmBF,EAAO,QAAQ,OACtC,CAACG,EAAKC,IAAMD,EAAM,OAAOC,EAAE,KAAK,EAChC,EAAA,EAKIC,EACJT,IAAmB,OAAY5B,EAAO,WAAW,OAAS,KAE5D,MAAO,CACL,QAASA,EAAO,MAChB,iBAAAkC,EACA,WAAYlC,EAAO,WACnB,kBAAmBA,EAAO,kBAC1B,cAAeA,EAAO,cACtB,aAAcA,EAAO,aACrB,oBAAqBA,EAAO,oBAC5B,eAAAqC,EACA,YAAAN,CAAA,CAEJ,CAMO,SAASF,EACdS,EACoB,CACpB,GAAIA,IAAU,OAAW,OACzB,MAAMC,EACJD,EAAM,WAAW,IAAI,GAAKA,EAAM,WAAW,IAAI,EAAIA,EAAM,MAAM,CAAC,EAAIA,EACtE,GACEC,EAAQ,SAAWd,GACnB,CAACC,EAAY,KAAKa,CAAO,EAEzB,MAAM,IAAI,MACR,uCAAuCd,CAAwB,qCAAqCc,EAAQ,MAAM,EAAA,EAGtH,OAAOA,EAAQ,YAAA,CACjB,CAYA,eAAsBC,EACpBvC,EACwB,CAMxB,MAAMD,EAAS,MAAMyC,EAAAA,yBACnB,CACE,eAAgBxC,EAAO,eAAe,iBACtC,gBAAiBA,EAAO,eAAe,gBACvC,oBAAqBA,EAAO,eAAe,oBAC3C,mBAAoBA,EAAO,eAAe,mBAC1C,2BACEA,EAAO,eAAe,2BACxB,UAAW,CAAC,GAAGA,EAAO,eAAe,SAAS,EAC9C,eAAgBA,EAAO,eAAe,eACtC,aAAc,CAAC,GAAGA,EAAO,eAAe,YAAY,EACpD,QAASA,EAAO,eAAe,QAC/B,gBAAiBA,EAAO,eAAe,gBACvC,oBAAqBA,EAAO,eAAe,oBAC3C,cAAeA,EAAO,eAAe,cACrC,YAAaA,EAAO,eAAe,YACnC,QAASA,EAAO,eAAe,QAC/B,eAAgB4B,EACd5B,EAAO,eAAe,cAAA,CACxB,EAEFA,EAAO,cACPA,EAAO,oBACPA,EAAO,QAAA,EAGT,aAAMyC,EAAmB1C,EAAQC,CAAM,EAEhC,CACL,MAAOD,EAAO,MACd,KAAMA,EAAO,KACb,kBAAmBA,EAAO,kBAC1B,WAAYA,EAAO,UAAA,CAEvB,CAOA,MAAM2C,EAA0B,EAM1BC,EAA6B,EAkBnC,eAAeF,EACb1C,EAMAC,EACe,CACf,MAAM4C,EAAU5C,EAAO,eAAe,iBAEtC,MAAM6C,yBAAuBD,EAAS7C,EAAO,KAAK,EAElD,MAAMK,EAAS,MAAMC,EAAAA,qBAAqBuC,CAAO,EAC3CE,EAAsBJ,GAA2BtC,EAAS,EAAI,GAE9D2C,EAAUC,EAAAA,YAAY,QAAQC,EAAAA,eAAelD,EAAO,KAAK,CAAC,EAQhE,GAAIgD,EAAQ,IAAI,SAAW,EACzB,MAAM,IAAI,MACR,gBAAgBA,EAAQ,IAAI,MAAM,8DAAA,EAItC,MAAMG,EAAqBF,EAAAA,YAAY,QACrCC,EAAAA,eAAejD,EAAO,mBAAmB,CAAA,EACzC,MAAA,EACImD,EAAYC,EAAAA,gBAChB,IAAI,WAAWL,EAAQ,IAAI,CAAC,EAAE,IAAI,EAAE,MAAA,EAAQ,QAAA,CAAQ,EAEtD,GAAII,IAAcD,EAChB,MAAM,IAAI,MACR,2BAA2BC,CAAS,mCAC/BD,CAAkB,GAAA,EAG3B,GAAIH,EAAQ,IAAI,CAAC,EAAE,QAAU/C,EAAO,SAClC,MAAM,IAAI,MACR,uCAAuC+C,EAAQ,IAAI,CAAC,EAAE,KAAK,sCACrB/C,EAAO,QAAQ,GAAA,EAIzD,GAAI+C,EAAQ,KAAK,SAAWD,EAC1B,MAAM,IAAI,MACR,gBAAgBC,EAAQ,KAAK,MAAM,gCAC9BD,CAAmB,yBAAyBF,CAAO,4BACpCxC,EAAS,gBAAkB,EAAE,IAAA,EAIrD,MAAMiD,EACJrD,EAAO,eAAe,aAAaA,EAAO,QAAQ,EACpD,GAAID,EAAO,aAAesD,EACxB,MAAM,IAAI,MACR,4BAA4BtD,EAAO,UAAU,+CAChBsD,CAAe,aACvCrD,EAAO,QAAQ,0EAAA,EAKxB,MAAMsD,EAAkBP,EAAQ,KAAK,CAAC,EACtC,GAAI,OAAOO,EAAgB,KAAK,IAAMvD,EAAO,WAC3C,MAAM,IAAI,MACR,oCAAoCuD,EAAgB,KAAK,gDACjBvD,EAAO,UAAU,GAAA,EAG7D,MAAMwD,EAAqBD,EAAgB,OAAO,SAAS,KAAK,EAC1DE,EAAsBP,EAAAA,eAC1BlD,EAAO,iBAAA,EACP,YAAA,EACF,GAAIwD,EAAmB,YAAA,IAAkBC,EACvC,MAAM,IAAI,MACR,2CAA2CD,CAAkB,uDAExDxD,EAAO,iBAAiB,GAAA,EAIjC,MAAM0D,EAAcV,EAAQ,MAAA,EAC5B,GAAIU,IAAgBR,EAAAA,eAAelD,EAAO,IAAI,EAAE,cAC9C,MAAM,IAAI,MACR,sBAAsB0D,CAAW,0CACvB1D,EAAO,IAAI,GAAA,EAWzB,MAAMG,EAAqB,MAAMC,EAAAA,qBAC/ByC,EACA5C,EAAO,eAAe,oBACtBA,EAAO,eAAe,2BAA2B,OACjDA,EAAO,eAAe,cACtBA,EAAO,eAAe,YACtBA,EAAO,eAAe,OAAA,EAElB0D,EAAkBX,EAAQ,KAAKJ,CAA0B,EAC/D,GAAI,OAAOe,EAAgB,KAAK,IAAMxD,EACpC,MAAM,IAAI,MACR,8CAA8CwD,EAAgB,KAAK,0DAE9DxD,CAAkB,yBAAyB0C,CAAO,GAAA,EAI3D,MAAMe,EAAsBC,EAC1B5D,EAAO,eAAe,eAAA,EAExB,GAAI,CAAC0D,EAAgB,OAAO,OAAOC,CAAmB,EACpD,MAAM,IAAI,MACR,qDACKD,EAAgB,OAAO,SAAS,KAAK,CAAC,2DAEtCC,EAAoB,SAAS,KAAK,CAAC,IAAA,CAG9C,CASA,SAASC,EAAiCC,EAAiC,CACzE,MAAMC,EAAkBC,EAAAA,OAAQ,QAAQ,CACtCC,EAAAA,OAAO,KAAKC,kBAAgBJ,CAAe,CAAC,EAC5CK,UAAQ,WAAA,CACT,EACK,CAAE,OAAAC,CAAA,EAAWC,EAAAA,SAAS,KAAK,CAC/B,eAAgBJ,EAAAA,OAAO,KAAKK,mBAAiB,EAC7C,WAAY,CAAE,OAAQP,CAAA,CAAgB,CACvC,EACD,GAAI,CAACK,EACH,MAAM,IAAI,MACR,oFAAA,EAGJ,OAAOA,CACT,CCtWA,eAAsBG,EACpBtE,EAC6B,CAE7B,MAAMuE,EAAY,MAAMC,EAAAA,sBACtB,CACE,eAAgBxE,EAAO,iBACvB,UAAWA,EAAO,UAClB,cAAeA,EAAO,cACtB,aAAcA,EAAO,aACrB,qBAAsBA,EAAO,qBAC7B,cAAeA,EAAO,aAAA,EAExBA,EAAO,OAAA,EAGT,MAAO,CACL,aAAcuE,EAAU,aACxB,kBAAmBA,EAAU,kBAC7B,aAAcA,EAAU,aACxB,QAASA,EAAU,QACnB,mBAAoBA,EAAU,kBAAA,CAElC,CCjIA,MAAME,EAAwB,IACxBC,EAAmC,GAQnCC,EAA+B,YAQ/BC,EAAmC,GAQnCC,GAAkC,GA2BjC,SAASC,GAA0B9E,EAAmC,CAG3E,GACE,OAAOA,EAAO,iBAAoB,UAClCA,EAAO,iBAAmB,IAC1BA,EAAO,gBAAkB2E,EAEzB,MAAM,IAAI,MACR,kCAAkCA,CAA4B,iBACrD3E,EAAO,eAAe,EAAA,EAMnC,SAAW,CAAC+E,EAAMC,CAAK,GAAK,CAC1B,CAAC,UAAWhF,EAAO,eAAe,EAClC,CAAC,cAAeA,EAAO,uBAAuB,CAAA,EAE9C,GACE,CAAC,OAAO,UAAUgF,CAAK,GACvBA,EAAQ,GACRA,EAAQJ,EAER,MAAM,IAAI,MACR,yBAAyBG,CAAI,KAAKC,CAAK,qCACxBJ,CAAgC,IAAA,EAOrD,GAAI,CAAC,OAAO,UAAU5E,EAAO,WAAW,GAAKA,EAAO,YAAc,EAChE,MAAM,IAAI,MACR,4CAA4CA,EAAO,WAAW,EAAA,CAGpE,CAQA,eAAsBiF,GACpBjF,EACAkF,EAKe,CACf,KAAM,CAAE,gBAAAC,EAAiB,QAAAC,EAAS,QAAAC,CAAA,EAAYH,EACxCI,EACJtF,EAAO,gBAAkBA,EAAO,wBAC5BuF,EAAc,OAAOJ,CAAe,EASpCK,EAAe,KAAK,IAAI,EAAGJ,EAAUP,EAA+B,EACpEY,EACJhB,EACAC,EAAmCY,EACnCE,EACIE,EAAa1F,EAAO,gBAAkB,OAAOyF,CAAc,EACjE,GAAIF,EAAcG,EAChB,MAAM,IAAI,MACR,uBAAuBP,CAAe,mCAC9BO,CAAU,UAAU1F,EAAO,eAAe,aAC7CyF,CAAc,WAAWH,CAAe,0CAAA,EAQjD,MAAMK,EAAa,MAAMC,EAAAA,sBACvB5F,EAAO,iBACPA,EAAO,gBACPA,EAAO,wBACPA,EAAO,gBACPA,EAAO,YACPoF,EACAC,EACArF,EAAO,eAAA,EAET,GAAIuF,EAAcI,EAChB,MAAM,IAAI,MACR,uBAAuBR,CAAe,+BACjCQ,CAAU,2GAAA,CAIrB,CCjJA,MAAME,EAAwC,EAgJ9C,eAAsBC,GACpB9F,EAC2B,CAC3B,MAAM+F,EAAgB,CACpB,iBAAkB/F,EAAO,iBACzB,gBAAiBA,EAAO,sBAAsB,OAC9C,wBAAyBA,EAAO,8BAA8B,OAC9D,YAAaA,EAAO,YACpB,gBAAiBA,EAAO,eAAA,EAE1B8E,GAA0BiB,CAAa,EAEvC,MAAMC,EAAWhD,EAAAA,YAAY,QAAQC,EAAAA,eAAejD,EAAO,WAAW,CAAC,EACjE+C,EAAUC,EAAAA,YAAY,QAAQC,EAAAA,eAAejD,EAAO,UAAU,CAAC,EAC/DiG,EAAWjD,EAAAA,YAAY,QAAQC,EAAAA,eAAejD,EAAO,WAAW,CAAC,EAEvE,GAAIgG,EAAS,IAAI,SAAWE,+BAC1B,MAAM,IAAI,MACR,wCAAwCA,EAAAA,4BAA4B,gBACnDF,EAAS,IAAI,MAAM,EAAA,EAGxC,MAAMG,EAAeC,EACnBJ,EAAS,IAAI,CAAC,EACd,EACAjD,EACA,QACAsD,EAAAA,wBAAA,EAEIC,EAAgBF,EACpBJ,EAAS,IAAI,CAAC,EACd,EACAC,EACA,SACAM,EAAAA,0BAAA,EAUI,CAAE,QAAAnB,EAAS,QAAAC,CAAA,EAAYmB,GAC3BR,EACAG,EAAa,MACbnG,CAAA,EAGIyG,EAAiBN,EAAa,MAAQG,EAAc,MAC1D,IAAII,EAAkB,EACtB,UAAWC,KAAOX,EAAS,KAAMU,GAAmBC,EAAI,MACxD,GAAID,EAAkBD,EACpB,MAAM,IAAI,MACR,mBAAmBC,CAAe,yBAC5BD,CAAc,8BAAA,EAGxB,MAAMtB,EAAkBsB,EAAiBC,EACzC,MAAMzB,GAAsBc,EAAe,CACzC,gBAAAZ,EACA,QAAAC,EACA,QAAAC,CAAA,CACD,EAID,MAAMuB,EAAkB,MAAMtC,EAAmB,CAC/C,iBAAkBtE,EAAO,iBACzB,UAAWA,EAAO,mBAClB,cAAeA,EAAO,uBACtB,aAAcA,EAAO,sBACrB,qBAAsBA,EAAO,8BAC7B,cAAeA,EAAO,cACtB,QAASA,EAAO,OAAA,CACjB,EAED,MAAO,CACL,QAAS6G,GACPb,EACAG,EACAG,EACAM,CAAA,CACF,CAEJ,CAUA,SAASR,EACPU,EACAC,EACAC,EACAC,EACAC,EACU,CACV,MAAM/D,EAAYC,EAAAA,gBAChB,IAAI,WAAW0D,EAAM,IAAI,EAAE,MAAA,EAAQ,QAAA,CAAQ,EAEvCK,EAAaH,EAAS,MAAA,EAC5B,GAAI7D,IAAcgE,GAAcL,EAAM,QAAUI,EAC9C,MAAM,IAAI,MACR,SAASH,CAAU,eAAeE,CAAW,IAAIC,CAAY,cAC/CC,CAAU,IAAID,CAAY,SAAS/D,CAAS,IAAI2D,EAAM,KAAK,EAAA,EAG7E,MAAMM,EAAUJ,EAAS,KAAKF,EAAM,KAAK,EACzC,GAAI,CAACM,EACH,MAAM,IAAI,MACR,uCAAuCL,CAAU,WACrC5D,CAAS,YAAY2D,EAAM,KAAK,GAAA,EAGhD,OAAOM,CACT,CAWA,SAASP,GACPb,EACAG,EACAG,EACAM,EACQ,CACR,MAAMS,EAAO,IAAIC,OACjBD,EAAK,WAAWrB,EAAS,OAAO,EAChCqB,EAAK,YAAYrB,EAAS,QAAQ,EAElC,KAAM,CAACuB,EAAQC,CAAM,EAAIxB,EAAS,IAGlCqB,EAAK,SAAS,CACZ,KAAME,EAAO,KACb,MAAOA,EAAO,MACd,SAAUA,EAAO,SACjB,YAAa,CACX,OAAQpB,EAAa,OACrB,MAAOA,EAAa,KAAA,EAEtB,cAAe,CACb,CACE,YAAasB,EAAAA,uBACb,OAAQzD,EAAAA,OAAO,KAAKC,EAAAA,gBAAgB2C,EAAgB,YAAY,CAAC,EACjE,aAAc5C,EAAAA,OAAO,KACnBC,EAAAA,gBAAgB2C,EAAgB,kBAAkB,CAAA,CACpD,CACF,EAEF,eAAgB5C,EAAAA,OAAO,KAAKK,EAAAA,iBAAiB,CAAA,CAE9C,EAIDgD,EAAK,SAAS,CACZ,KAAMG,EAAO,KACb,MAAOA,EAAO,MACd,SAAUA,EAAO,SACjB,YAAa,CACX,OAAQlB,EAAc,OACtB,MAAOA,EAAc,KAAA,CACvB,CACD,EAED,UAAWnC,KAAU6B,EAAS,KAC5BqB,EAAK,UAAU,CACb,OAAQlD,EAAO,OACf,MAAOA,EAAO,KAAA,CACf,EAGH,OAAOkD,EAAK,MAAA,CACd,CAsBA,SAASb,GACPR,EACA0B,EACA1H,EACkD,CAClD,KAAM,CACJ,iBAAA2H,EACA,uBAAAC,EACA,mBAAAC,EACA,sBAAAC,EACA,6BAAAC,EACA,cAAAC,CAAA,EACEhI,EAEJ,GAAI,CAACiI,EAAAA,WAAWF,CAA4B,EAC1C,MAAM,IAAI,MAAM,qDAAqD,EAGvE,MAAMG,EAAUjF,EAAAA,eAAe0E,CAAgB,EAAE,YAAA,EAC3CQ,EAAKlF,EAAAA,eAAe2E,CAAsB,EAAE,YAAA,EAC5CQ,EAAMnF,EAAAA,eAAe4E,CAAkB,EAAE,YAAA,EACzCQ,EAAUP,EAAsB,IAAKQ,GACzCrF,EAAAA,eAAeqF,CAAC,EAAE,YAAA,CAAY,EAIhC,IAAIvD,EACAwD,EACAC,EAEJ,GAAIN,IAAYC,EACdpD,EAAO,aACPwD,EAAmBE,EAAAA,+BACnBD,EAAwBvF,EAAAA,eAAe8E,CAA4B,UAC1DG,IAAYE,EACrBrD,EAAO,uBACPwD,EAAmBG,EAAAA,mCACnBF,EAAwBvF,EAAAA,eAAe8E,CAA4B,UAC1DM,EAAQ,SAASH,CAAO,EACjCnD,EAAO,aACPwD,EAAmBG,EAAAA,mCACnBF,EAAwBvF,EAAAA,eAAe0F,6BAA2BT,CAAO,CAAC,MAE1E,OAAM,IAAI,MACR,0BAA0BA,CAAO,mDAAA,EAIrC,GAAIlC,EAAS,KAAK,SAAWuC,EAC3B,MAAM,IAAI,MACR,0BAA0BvC,EAAS,KAAK,MAAM,gCACxBuC,CAAgB,aAAaxD,CAAI,GAAA,EAI3D,MAAM6D,EAAqB5E,EAAAA,OAAO,KAAKwE,EAAuB,KAAK,EACnE,GAAI,CAACxC,EAAS,KAAK,CAAC,EAAE,OAAO,OAAO4C,CAAkB,EACpD,MAAM,IAAI,MACR,+EAA+E7D,CAAI,EAAA,EAIvF,MAAM8D,EAAYN,EAAmB,EACrC,GAAIvC,EAAS,KAAK6C,CAAS,EAAE,QAAUC,EAAAA,wBACrC,MAAM,IAAI,MACR,2BAA2BD,CAAS,WAAW7C,EAAS,KAAK6C,CAAS,EAAE,KAAK,oBAC7DC,EAAAA,uBAAuB,OAAA,EAI3C,GAAI/D,IAAS,aAAc,CAKzB,GACE,CAAC,OAAO,UAAUiD,CAAa,GAC/BA,EAAgB,GAChBA,GAAiBe,kCAEjB,MAAM,IAAI,MACR,2CACSA,EAAAA,+BAA+B,UAAUf,CAAa,EAAA,EAGnE,MAAMgB,EAAoB,KAAK,MAC5BtB,EAAiBM,EAAiBiB,EAAAA,eAAA,EAErC,GAAIjD,EAAS,KAAK,CAAC,EAAE,MAAQgD,EAC3B,MAAM,IAAI,MACR,sCAAsChD,EAAS,KAAK,CAAC,EAAE,KAAK,qBAC3CgD,CAAiB,UAC5BhB,CAAa,sBAAsBN,CAAc,GAAA,CAG7D,CAEA,MAAMtC,EAAUwD,EAAmB,OACnC,GAAIxD,IAAY,GAAKA,EAAU8D,wBAC7B,MAAM,IAAI,MACR,uCAAuC9D,CAAO,mDACT8D,EAAAA,qBAAqB,6BAAA,EAI9D,MAAM7D,EACJN,IAAS,aAAeiB,EAAS,KAAK,CAAC,EAAE,OAAO,OAAS,OAC3D,GACEX,IAAY,SACXA,IAAY,GAAKA,EAAU6D,EAAAA,uBAE5B,MAAM,IAAI,MACR,yCAAyC7D,CAAO,mDACX6D,EAAAA,qBAAqB,6BAAA,EAK9D,MAAO,CAAE,QAAA9D,EAAS,QAAAC,CAAA,CACpB,CAqBO,SAAS8D,GACdC,EACAvF,EACAkD,EAAa,EACL,CACR,MAAMsC,EAAa/B,EAAAA,KAAK,QAAQ8B,CAAa,EAE7C,GAAIrC,GAAcsC,EAAW,KAAK,OAAO,OACvC,MAAM,IAAI,MACR,eAAetC,CAAU,kBAAkBsC,EAAW,KAAK,OAAO,MAAM,UAAA,EAI5E,MAAMvC,EAAQuC,EAAW,KAAK,OAAOtC,CAAU,EAG/C,GAAID,EAAM,cAAgBA,EAAM,aAAa,OAAS,EAAG,CACvD,MAAMwC,EAAuBrF,EAAAA,gBAAgBJ,CAAe,EAE5D,UAAW0F,KAAYzC,EAAM,aAC3B,GAAIyC,EAAS,OAAO,OAAOvF,EAAAA,OAAO,KAAKsF,CAAoB,CAAC,EAC1D,OAAOE,EAAkBD,EAAS,UAAWxC,CAAU,EAI3D,MAAM,IAAI,MACR,4CAA4ClD,CAAe,aAAakD,CAAU,EAAA,CAEtF,CAQA,GAAID,EAAM,oBAAsBA,EAAM,mBAAmB,OAAS,EAAG,CACnE,MAAM2C,EAAeC,GAAkB5C,EAAM,kBAAkB,EAC/D,GAAI2C,EAAa,SAAW5D,EAC1B,MAAM,IAAI,MACR,oDAAoDkB,CAAU,cAChDlB,CAAqC,iDAC1C4D,EAAa,MAAM,EAAA,EAGhC,OAAOD,EAAkBC,EAAa,CAAC,EAAG1C,CAAU,CACtD,CAEA,MAAM,IAAI,MACR,uEAAuEA,CAAU,EAAA,CAErF,CASA,SAASyC,EAAkBG,EAAiB5C,EAA4B,CACtE,GAAI4C,EAAI,SAAW,GACjB,OAAOvG,kBAAgB,IAAI,WAAWuG,CAAG,CAAC,EAE5C,MAAIA,EAAI,SAAW,GACX,IAAI,MACR,6BAA6BA,EAAI,EAAE,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,aAAa5C,CAAU,6DAAA,EAIvF,IAAI,MACR,wCAAwCA,CAAU,KAAK4C,EAAI,MAAM,EAAA,CAErE,CAUA,SAASD,GAAkBE,EAA2B,CACpD,MAAMC,EAAkB,CAAA,EACxB,IAAIC,EAAS,EAEb,MAAMC,EAAgBC,GAAoB,CACxC,GAAIF,EAASE,EAAIJ,EAAQ,OACvB,MAAM,IAAI,MACR,gCAAgCI,CAAC,sBAAsBF,CAAM,UAAUF,EAAQ,OAASE,CAAM,YAAA,CAGpG,EAEMG,EAAa,IAAc,CAC/BF,EAAa,CAAC,EACd,MAAMG,EAAQN,EAAQE,GAAQ,EAC9B,GAAII,EAAQ,IAAM,OAAOA,EACzB,GAAIA,IAAU,IAAM,CAClBH,EAAa,CAAC,EACd,MAAMI,GAAOP,EAAQE,CAAM,EAAKF,EAAQE,EAAS,CAAC,GAAK,KAAQ,EAC/D,OAAAA,GAAU,EACHK,CACT,CACA,GAAID,IAAU,IAAM,CAClBH,EAAa,CAAC,EACd,MAAMI,GACHP,EAAQE,CAAM,EACZF,EAAQE,EAAS,CAAC,GAAK,EACvBF,EAAQE,EAAS,CAAC,GAAK,GACvBF,EAAQE,EAAS,CAAC,GAAK,MAC1B,EACF,OAAAA,GAAU,EACHK,CACT,CAIA,MAAM,IAAI,MACR,wEAAwEL,EAAS,CAAC,EAAA,CAEtF,EAEM9E,EAAQiF,EAAA,EACd,QAASrJ,EAAI,EAAGA,EAAIoE,EAAOpE,IAAK,CAC9B,MAAMwJ,EAAMH,EAAA,EACZF,EAAaK,CAAG,EAChBP,EAAM,KAAK7F,EAAAA,OAAO,KAAK4F,EAAQ,SAASE,EAAQA,EAASM,CAAG,CAAC,CAAC,EAC9DN,GAAUM,CACZ,CAEA,GAAIN,IAAWF,EAAQ,OACrB,MAAM,IAAI,MACR,2BAA2BA,EAAQ,OAASE,CAAM,mCAAmC9E,CAAK,UAAA,EAI9F,OAAO6E,CACT,CCzpBO,MAAMQ,UAA8B,KAAM,CAC/C,YAAYC,EAAgB,CAC1B,MACE,uDAAuDA,CAAM,EAAA,EAE/D,KAAK,KAAO,uBACd,CACF,CASA,SAASC,EAAUC,EAAiCC,EAAmB,CACrE,GAAI,CACF,OAAOnD,EAAAA,KAAK,QAAQmD,CAAG,CACzB,OAASC,EAAO,CACd,MAAMC,EAASD,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACpE,MAAM,IAAI,MAAM,mBAAmBF,CAAK,UAAUG,CAAM,EAAE,CAC5D,CACF,CAOA,MAAMC,GAA0B,EAEhC,SAASC,EAAUC,EAAqB,CACtC,MAAO,GAAGA,EAAI,SAAS,KAAK,EAAE,MAAM,EAAGF,EAAuB,CAAC,GACjE,CAQA,SAASG,EAAWC,EAA8B,CAChD,MAAMC,EAAWjH,EAAAA,OAAO,KAAKgH,CAAY,EAAE,QAAA,EAC3C,OAAOH,EAAUI,CAAQ,CAC3B,CASO,SAASC,GACdlL,EACM,CACN,MAAMa,EAAY0J,EAAU,YAAavK,EAAO,gBAAgB,EAC1DmL,EAAWZ,EAAU,WAAYvK,EAAO,eAAe,EAE7D,GAAIa,EAAU,UAAYsK,EAAS,QACjC,MAAM,IAAId,EACR,iCAAiCxJ,EAAU,OAAO,cAAcsK,EAAS,OAAO,GAAA,EAGpF,GAAItK,EAAU,WAAasK,EAAS,SAClC,MAAM,IAAId,EACR,kCAAkCxJ,EAAU,QAAQ,cAAcsK,EAAS,QAAQ,GAAA,EAGvF,GAAItK,EAAU,SAAS,SAAWsK,EAAS,SAAS,OAClD,MAAM,IAAId,EACR,kCAAkCxJ,EAAU,SAAS,MAAM,cAAcsK,EAAS,SAAS,MAAM,GAAA,EAGrG,GAAItK,EAAU,UAAU,SAAWsK,EAAS,UAAU,OACpD,MAAM,IAAId,EACR,mCAAmCxJ,EAAU,UAAU,MAAM,cAAcsK,EAAS,UAAU,MAAM,GAAA,EAGxG,QAASvK,EAAI,EAAGA,EAAIC,EAAU,SAAS,OAAQD,IAAK,CAClD,MAAM,EAAIC,EAAU,SAASD,CAAC,EACxBwK,EAAID,EAAS,SAASvK,CAAC,EAC7B,GAAI,CAAC,EAAE,KAAK,OAAOwK,EAAE,IAAI,EACvB,MAAM,IAAIf,EACR,SAASzJ,CAAC,oCAAoCmK,EAAW,EAAE,IAAI,CAAC,cAAcA,EAAWK,EAAE,IAAI,CAAC,GAAA,EAGpG,GAAI,EAAE,QAAUA,EAAE,MAChB,MAAM,IAAIf,EACR,SAASzJ,CAAC,oCAAoC,EAAE,KAAK,cAAcwK,EAAE,KAAK,GAAA,EAG9E,GAAI,EAAE,WAAaA,EAAE,SACnB,MAAM,IAAIf,EACR,SAASzJ,CAAC,gCAAgC,EAAE,QAAQ,cAAcwK,EAAE,QAAQ,GAAA,CAGlF,CACA,QAASxK,EAAI,EAAGA,EAAIC,EAAU,UAAU,OAAQD,IAAK,CACnD,MAAM,EAAIC,EAAU,UAAUD,CAAC,EACzBwK,EAAID,EAAS,UAAUvK,CAAC,EAC9B,GAAI,CAAC,EAAE,OAAO,OAAOwK,EAAE,MAAM,EAC3B,MAAM,IAAIf,EACR,UAAUzJ,CAAC,oCAAoCiK,EAAU,EAAE,MAAM,CAAC,cAAcA,EAAUO,EAAE,MAAM,CAAC,GAAA,EAGvG,GAAI,EAAE,QAAUA,EAAE,MAChB,MAAM,IAAIf,EACR,UAAUzJ,CAAC,6BAA6B,EAAE,KAAK,cAAcwK,EAAE,KAAK,GAAA,CAG1E,CACF,CCtFA,MAAMC,EAA6B,IAC7BC,GAA6B,IAC7BC,GAA0B,MAC1BC,GAA0B,WAOhC,SAASC,GAAkBzB,EAAmB,CAC5C,GAAIA,EAAIqB,EACN,OAAOrH,SAAO,KAAK,CAACgG,CAAC,CAAC,EAExB,GAAIA,GAAKuB,GAAyB,CAChC,MAAMlJ,EAAQ2B,EAAAA,OAAO,MAAM,CAAC,EAC5B,OAAA3B,EAAM,cAAc2H,CAAC,EACdhG,EAAAA,OAAO,OAAO,CAACA,EAAAA,OAAO,KAAK,CAACqH,CAA0B,CAAC,EAAGhJ,CAAK,CAAC,CACzE,CACA,GAAI2H,GAAKwB,GAAyB,CAChC,MAAMnJ,EAAQ2B,EAAAA,OAAO,MAAM,CAAC,EAC5B,OAAA3B,EAAM,cAAc2H,CAAC,EACdhG,EAAAA,OAAO,OAAO,CAACA,EAAAA,OAAO,KAAK,CAACsH,EAA0B,CAAC,EAAGjJ,CAAK,CAAC,CACzE,CACA,MAAM,IAAI,MAAM,8CAA8C2H,CAAC,QAAQ,CACzE,CAGA,MAAM0B,GAAc,UAMpB,SAASC,GAAmBC,EAAqBC,EAA4B,CAC3E,MAAMC,EAAW9H,EAAAA,OAAO,OAAO,CAC7BA,SAAO,KAAK,CAAC4H,CAAW,CAAC,EACzBH,GAAkBI,EAAO,MAAM,EAC/B7H,EAAAA,OAAO,KAAK6H,CAAM,CAAA,CACnB,EACD,OAAOE,SAAQ,WAAWL,GAAaI,CAAQ,CACjD,CAyBO,SAASE,GACdhM,EACM,CACN,KAAM,CAAE,iBAAAiM,EAAkB,aAAAC,EAAc,qBAAAC,EAAsB,WAAApF,GAC5D/G,EAEIoM,EAAenJ,EAAAA,eAAeiJ,CAAY,EAChD,GAAIE,EAAa,SAAWC,sBAC1B,MAAM,IAAI,MACR,+BAA+BtF,CAAU,YAAYsF,EAAAA,mBAAmB,8BACnDD,EAAa,MAAM,GAAA,EAI5C,MAAME,EAAcrJ,EAAAA,eAAekJ,CAAoB,EACvD,GAAIG,EAAY,SAAWC,wBACzB,MAAM,IAAI,MACR,kCAAkCxF,CAAU,YAAYwF,EAAAA,qBAAqB,8BACxDD,EAAY,MAAM,GAAA,EAI3C,MAAMjF,EAAOC,EAAAA,KAAK,QAAQ2E,CAAgB,EAE1C,GAAIlF,EAAa,GAAKA,GAAcM,EAAK,KAAK,OAAO,OACnD,MAAM,IAAI,MACR,eAAeN,CAAU,kBAAkBM,EAAK,KAAK,OAAO,MAAM,WAAA,EAOtE,MAAMmF,EAA2B,CAAA,EAC3BC,EAAmB,CAAA,EACzB,QAAS7L,EAAI,EAAGA,EAAIyG,EAAK,KAAK,OAAO,OAAQzG,IAAK,CAChD,MAAM8L,EAAcrF,EAAK,KAAK,OAAOzG,CAAC,EAAE,YACxC,GAAI,CAAC8L,EACH,MAAM,IAAI,MACR,kCAAkC9L,CAAC,wFAAA,EAIvC4L,EAAe,KAAKE,EAAY,MAAM,EACtCD,EAAO,KAAKC,EAAY,KAAK,CAC/B,CAKA,MAAMC,EAAiBtF,EAAK,KAAK,OAAON,CAAU,EAAE,cACpD,GAAI,CAAC4F,GAAkBA,EAAe,SAAW,EAC/C,MAAM,IAAI,MACR,kCAAkC5F,CAAU,oEAChB4F,GAAA,YAAAA,EAAgB,SAAU,CAAC,GAAA,EAG3D,MAAMC,EAAOD,EAAe,CAAC,EAC7B,GAAIC,EAAK,cAAgBnF,yBACvB,MAAM,IAAI,MACR,kCAAkCV,CAAU,qCACrC6F,EAAK,YAAY,SAAS,EAAE,CAAC,gBAAgBnF,EAAAA,uBAAuB,SAAS,EAAE,CAAC,GAAA,EAI3F,MAAMoF,EAAWlB,GAAmBiB,EAAK,YAAaA,EAAK,MAAM,EAK3DE,EAAK,IAAI9J,cACf8J,EAAG,QAAUzF,EAAK,QAClByF,EAAG,SAAWzF,EAAK,SACnB,UAAWP,KAASO,EAAK,SACvByF,EAAG,SAAShG,EAAM,KAAMA,EAAM,MAAOA,EAAM,QAAQ,EAErD,UAAW3C,KAAUkD,EAAK,UACxByF,EAAG,UAAU3I,EAAO,OAAQA,EAAO,KAAK,EAG1C,MAAM4I,EAAUD,EAAG,iBACjB/F,EACAyF,EACAC,EACAzJ,EAAAA,YAAY,gBACZ6J,CAAA,EASF,GAAI,CANYG,EAAI,cAClBD,EACA9I,EAAAA,gBAAgBqI,CAAW,EAC3BrI,EAAAA,gBAAgBmI,CAAY,CAAA,EAI5B,MAAM,IAAI,MACR,+BAA+BrF,CAAU,YAAYuF,CAAW,wLAAA,CAKtE"}