@sip-protocol/sdk 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
  4. package/dist/browser.d.mts +10 -4
  5. package/dist/browser.d.ts +10 -4
  6. package/dist/browser.js +48874 -18336
  7. package/dist/browser.mjs +674 -48
  8. package/dist/chunk-4GRJ5MAW.mjs +152 -0
  9. package/dist/chunk-5D7A3L3W.mjs +717 -0
  10. package/dist/chunk-64AYA5F5.mjs +7834 -0
  11. package/dist/chunk-GMDGB22A.mjs +379 -0
  12. package/dist/chunk-I534WKN7.mjs +328 -0
  13. package/dist/chunk-IBZVA5Y7.mjs +1003 -0
  14. package/dist/chunk-PRRZAWJE.mjs +223 -0
  15. package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
  16. package/dist/chunk-YWGJ77A2.mjs +33806 -0
  17. package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
  18. package/dist/constants-LHAAUC2T.mjs +51 -0
  19. package/dist/dist-2OGQ7FED.mjs +3957 -0
  20. package/dist/dist-IFHPYLDX.mjs +254 -0
  21. package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
  22. package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
  23. package/dist/index-DXh2IGkz.d.ts +24681 -0
  24. package/dist/index-DeE1ZzA4.d.mts +24681 -0
  25. package/dist/index.d.mts +9 -3
  26. package/dist/index.d.ts +9 -3
  27. package/dist/index.js +48676 -17318
  28. package/dist/index.mjs +583 -19
  29. package/dist/interface-Bf7w1PLW.d.mts +679 -0
  30. package/dist/interface-Bf7w1PLW.d.ts +679 -0
  31. package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
  32. package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
  33. package/dist/proofs/halo2.d.mts +151 -0
  34. package/dist/proofs/halo2.d.ts +151 -0
  35. package/dist/proofs/halo2.js +350 -0
  36. package/dist/proofs/halo2.mjs +11 -0
  37. package/dist/proofs/kimchi.d.mts +160 -0
  38. package/dist/proofs/kimchi.d.ts +160 -0
  39. package/dist/proofs/kimchi.js +431 -0
  40. package/dist/proofs/kimchi.mjs +13 -0
  41. package/dist/proofs/noir.d.mts +1 -1
  42. package/dist/proofs/noir.d.ts +1 -1
  43. package/dist/proofs/noir.js +74 -18
  44. package/dist/proofs/noir.mjs +84 -24
  45. package/dist/solana-U3MEGU7W.mjs +280 -0
  46. package/dist/validity_proof-3POXLPNY.mjs +21 -0
  47. package/package.json +54 -21
  48. package/src/adapters/index.ts +41 -0
  49. package/src/adapters/jupiter.ts +571 -0
  50. package/src/adapters/near-intents.ts +135 -0
  51. package/src/advisor/advisor.ts +653 -0
  52. package/src/advisor/index.ts +54 -0
  53. package/src/advisor/tools.ts +303 -0
  54. package/src/advisor/types.ts +164 -0
  55. package/src/chains/ethereum/announcement.ts +536 -0
  56. package/src/chains/ethereum/bnb-optimizations.ts +474 -0
  57. package/src/chains/ethereum/commitment.ts +522 -0
  58. package/src/chains/ethereum/constants.ts +462 -0
  59. package/src/chains/ethereum/deployment.ts +596 -0
  60. package/src/chains/ethereum/gas-estimation.ts +538 -0
  61. package/src/chains/ethereum/index.ts +268 -0
  62. package/src/chains/ethereum/optimizations.ts +614 -0
  63. package/src/chains/ethereum/privacy-adapter.ts +855 -0
  64. package/src/chains/ethereum/registry.ts +584 -0
  65. package/src/chains/ethereum/rpc.ts +905 -0
  66. package/src/chains/ethereum/stealth.ts +491 -0
  67. package/src/chains/ethereum/token.ts +790 -0
  68. package/src/chains/ethereum/transfer.ts +637 -0
  69. package/src/chains/ethereum/types.ts +456 -0
  70. package/src/chains/ethereum/viewing-key.ts +455 -0
  71. package/src/chains/near/commitment.ts +608 -0
  72. package/src/chains/near/constants.ts +284 -0
  73. package/src/chains/near/function-call.ts +871 -0
  74. package/src/chains/near/history.ts +654 -0
  75. package/src/chains/near/implicit-account.ts +840 -0
  76. package/src/chains/near/index.ts +393 -0
  77. package/src/chains/near/native-transfer.ts +658 -0
  78. package/src/chains/near/nep141.ts +775 -0
  79. package/src/chains/near/privacy-adapter.ts +889 -0
  80. package/src/chains/near/resolver.ts +971 -0
  81. package/src/chains/near/rpc.ts +1016 -0
  82. package/src/chains/near/stealth.ts +419 -0
  83. package/src/chains/near/types.ts +317 -0
  84. package/src/chains/near/viewing-key.ts +876 -0
  85. package/src/chains/solana/anchor-transfer.ts +386 -0
  86. package/src/chains/solana/commitment.ts +577 -0
  87. package/src/chains/solana/constants.ts +126 -12
  88. package/src/chains/solana/ephemeral-keys.ts +543 -0
  89. package/src/chains/solana/index.ts +276 -1
  90. package/src/chains/solana/key-derivation.ts +418 -0
  91. package/src/chains/solana/kit-compat.ts +334 -0
  92. package/src/chains/solana/optimizations.ts +560 -0
  93. package/src/chains/solana/privacy-adapter.ts +605 -0
  94. package/src/chains/solana/providers/generic.ts +201 -0
  95. package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
  96. package/src/chains/solana/providers/helius-enhanced.ts +623 -0
  97. package/src/chains/solana/providers/helius.ts +402 -0
  98. package/src/chains/solana/providers/index.ts +85 -0
  99. package/src/chains/solana/providers/interface.ts +221 -0
  100. package/src/chains/solana/providers/quicknode.ts +409 -0
  101. package/src/chains/solana/providers/triton.ts +426 -0
  102. package/src/chains/solana/providers/webhook.ts +790 -0
  103. package/src/chains/solana/rpc-client.ts +1150 -0
  104. package/src/chains/solana/scan.ts +170 -73
  105. package/src/chains/solana/sol-transfer.ts +732 -0
  106. package/src/chains/solana/spl-transfer.ts +886 -0
  107. package/src/chains/solana/stealth-scanner.ts +703 -0
  108. package/src/chains/solana/sunspot-verifier.ts +453 -0
  109. package/src/chains/solana/transaction-builder.ts +755 -0
  110. package/src/chains/solana/transfer.ts +74 -5
  111. package/src/chains/solana/types.ts +77 -7
  112. package/src/chains/solana/utils.ts +110 -0
  113. package/src/chains/solana/viewing-key.ts +807 -0
  114. package/src/compliance/fireblocks.ts +921 -0
  115. package/src/compliance/index.ts +37 -0
  116. package/src/compliance/range-sas.ts +956 -0
  117. package/src/config/endpoints.ts +100 -0
  118. package/src/crypto.ts +11 -8
  119. package/src/errors.ts +82 -0
  120. package/src/evm/erc4337-relayer.ts +830 -0
  121. package/src/evm/index.ts +47 -0
  122. package/src/fees/calculator.ts +396 -0
  123. package/src/fees/index.ts +87 -0
  124. package/src/fees/near-contract.ts +429 -0
  125. package/src/fees/types.ts +268 -0
  126. package/src/index.ts +785 -1
  127. package/src/intent.ts +6 -3
  128. package/src/logger.ts +324 -0
  129. package/src/network/index.ts +80 -0
  130. package/src/network/proxy.ts +691 -0
  131. package/src/optimizations/index.ts +541 -0
  132. package/src/oracle/types.ts +1 -0
  133. package/src/privacy-backends/arcium-types.ts +727 -0
  134. package/src/privacy-backends/arcium.ts +719 -0
  135. package/src/privacy-backends/combined-privacy.ts +866 -0
  136. package/src/privacy-backends/cspl-token.ts +595 -0
  137. package/src/privacy-backends/cspl-types.ts +512 -0
  138. package/src/privacy-backends/cspl.ts +907 -0
  139. package/src/privacy-backends/health.ts +488 -0
  140. package/src/privacy-backends/inco-types.ts +323 -0
  141. package/src/privacy-backends/inco.ts +616 -0
  142. package/src/privacy-backends/index.ts +336 -0
  143. package/src/privacy-backends/interface.ts +906 -0
  144. package/src/privacy-backends/lru-cache.ts +343 -0
  145. package/src/privacy-backends/magicblock.ts +458 -0
  146. package/src/privacy-backends/mock.ts +258 -0
  147. package/src/privacy-backends/privacycash-types.ts +278 -0
  148. package/src/privacy-backends/privacycash.ts +456 -0
  149. package/src/privacy-backends/private-swap.ts +570 -0
  150. package/src/privacy-backends/rate-limiter.ts +683 -0
  151. package/src/privacy-backends/registry.ts +690 -0
  152. package/src/privacy-backends/router.ts +626 -0
  153. package/src/privacy-backends/shadowwire.ts +449 -0
  154. package/src/privacy-backends/sip-native.ts +256 -0
  155. package/src/privacy-logger.ts +191 -0
  156. package/src/production-safety.ts +373 -0
  157. package/src/proofs/aggregator.ts +1029 -0
  158. package/src/proofs/browser-composer.ts +1150 -0
  159. package/src/proofs/browser.ts +113 -25
  160. package/src/proofs/cache/index.ts +127 -0
  161. package/src/proofs/cache/interface.ts +545 -0
  162. package/src/proofs/cache/key-generator.ts +188 -0
  163. package/src/proofs/cache/lru-cache.ts +481 -0
  164. package/src/proofs/cache/multi-tier-cache.ts +575 -0
  165. package/src/proofs/cache/persistent-cache.ts +788 -0
  166. package/src/proofs/compliance-proof.ts +872 -0
  167. package/src/proofs/composer/base.ts +923 -0
  168. package/src/proofs/composer/index.ts +25 -0
  169. package/src/proofs/composer/interface.ts +518 -0
  170. package/src/proofs/composer/types.ts +383 -0
  171. package/src/proofs/converters/halo2.ts +452 -0
  172. package/src/proofs/converters/index.ts +208 -0
  173. package/src/proofs/converters/interface.ts +363 -0
  174. package/src/proofs/converters/kimchi.ts +462 -0
  175. package/src/proofs/converters/noir.ts +451 -0
  176. package/src/proofs/fallback.ts +888 -0
  177. package/src/proofs/halo2.ts +42 -0
  178. package/src/proofs/index.ts +471 -0
  179. package/src/proofs/interface.ts +13 -0
  180. package/src/proofs/kimchi.ts +42 -0
  181. package/src/proofs/lazy.ts +1004 -0
  182. package/src/proofs/mock.ts +25 -1
  183. package/src/proofs/noir.ts +111 -30
  184. package/src/proofs/orchestrator.ts +960 -0
  185. package/src/proofs/parallel/concurrency.ts +297 -0
  186. package/src/proofs/parallel/dependency-graph.ts +602 -0
  187. package/src/proofs/parallel/executor.ts +420 -0
  188. package/src/proofs/parallel/index.ts +131 -0
  189. package/src/proofs/parallel/interface.ts +685 -0
  190. package/src/proofs/parallel/worker-pool.ts +644 -0
  191. package/src/proofs/providers/halo2.ts +560 -0
  192. package/src/proofs/providers/index.ts +34 -0
  193. package/src/proofs/providers/kimchi.ts +641 -0
  194. package/src/proofs/validator.ts +881 -0
  195. package/src/proofs/verifier.ts +867 -0
  196. package/src/quantum/index.ts +112 -0
  197. package/src/quantum/winternitz-vault.ts +639 -0
  198. package/src/quantum/wots.ts +611 -0
  199. package/src/settlement/backends/direct-chain.ts +1 -0
  200. package/src/settlement/index.ts +9 -0
  201. package/src/settlement/router.ts +732 -46
  202. package/src/solana/index.ts +72 -0
  203. package/src/solana/jito-relayer.ts +687 -0
  204. package/src/solana/noir-verifier-types.ts +430 -0
  205. package/src/solana/noir-verifier.ts +816 -0
  206. package/src/stealth/address-derivation.ts +193 -0
  207. package/src/stealth/ed25519.ts +431 -0
  208. package/src/stealth/index.ts +233 -0
  209. package/src/stealth/meta-address.ts +221 -0
  210. package/src/stealth/secp256k1.ts +368 -0
  211. package/src/stealth/utils.ts +194 -0
  212. package/src/stealth.ts +50 -1504
  213. package/src/surveillance/algorithms/address-reuse.ts +143 -0
  214. package/src/surveillance/algorithms/cluster.ts +247 -0
  215. package/src/surveillance/algorithms/exchange.ts +295 -0
  216. package/src/surveillance/algorithms/temporal.ts +337 -0
  217. package/src/surveillance/analyzer.ts +442 -0
  218. package/src/surveillance/index.ts +64 -0
  219. package/src/surveillance/scoring.ts +372 -0
  220. package/src/surveillance/types.ts +264 -0
  221. package/src/sync/index.ts +106 -0
  222. package/src/sync/manager.ts +504 -0
  223. package/src/sync/mock-provider.ts +318 -0
  224. package/src/sync/oblivious.ts +625 -0
  225. package/src/tokens/index.ts +15 -0
  226. package/src/tokens/registry.ts +301 -0
  227. package/src/utils/deprecation.ts +94 -0
  228. package/src/utils/index.ts +9 -0
  229. package/src/wallet/ethereum/index.ts +68 -0
  230. package/src/wallet/ethereum/metamask-privacy.ts +420 -0
  231. package/src/wallet/ethereum/multi-wallet.ts +646 -0
  232. package/src/wallet/ethereum/privacy-adapter.ts +700 -0
  233. package/src/wallet/ethereum/types.ts +3 -1
  234. package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
  235. package/src/wallet/hardware/index.ts +10 -0
  236. package/src/wallet/hardware/ledger-privacy.ts +414 -0
  237. package/src/wallet/index.ts +71 -0
  238. package/src/wallet/near/adapter.ts +626 -0
  239. package/src/wallet/near/index.ts +86 -0
  240. package/src/wallet/near/meteor-wallet.ts +1153 -0
  241. package/src/wallet/near/my-near-wallet.ts +790 -0
  242. package/src/wallet/near/wallet-selector.ts +702 -0
  243. package/src/wallet/solana/adapter.ts +6 -4
  244. package/src/wallet/solana/index.ts +13 -0
  245. package/src/wallet/solana/privacy-adapter.ts +567 -0
  246. package/src/wallet/sui/types.ts +6 -4
  247. package/src/zcash/rpc-client.ts +13 -6
  248. package/dist/chunk-3INS3PR5.mjs +0 -884
  249. package/dist/chunk-3OVABDRH.mjs +0 -17096
  250. package/dist/chunk-DLDWZFYC.mjs +0 -1495
  251. package/dist/chunk-E6SZWREQ.mjs +0 -57
  252. package/dist/chunk-G33LB27A.mjs +0 -16166
  253. package/dist/chunk-HGU6HZRC.mjs +0 -231
  254. package/dist/chunk-L2K34JCU.mjs +0 -1496
  255. package/dist/chunk-SN4ZDTVW.mjs +0 -16166
  256. package/dist/constants-VOI7BSLK.mjs +0 -27
  257. package/dist/index-BYZbDjal.d.ts +0 -11390
  258. package/dist/index-CHB3KuOB.d.mts +0 -11859
  259. package/dist/index-CzWPI6Le.d.ts +0 -11859
  260. package/dist/index-xbWjohNq.d.mts +0 -11390
  261. package/dist/solana-5EMCTPTS.mjs +0 -46
  262. package/dist/solana-Q4NAVBTS.mjs +0 -46
@@ -0,0 +1,888 @@
1
+ /**
2
+ * Fallback Proof Strategies
3
+ *
4
+ * Implements fallback strategies for when primary proof providers fail or are unavailable.
5
+ * Ensures proof composition remains reliable even when individual ZK systems have issues.
6
+ *
7
+ * Key features:
8
+ * - Provider failover logic
9
+ * - Graceful degradation (simpler proofs when complex fails)
10
+ * - Circuit breaker pattern for failing providers
11
+ * - Mock/stub fallback for development
12
+ * - Custom fallback configuration
13
+ * - Fallback logging and alerting
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+
18
+ import type {
19
+ ProofSystem,
20
+ SingleProof,
21
+ HexString,
22
+ } from '@sip-protocol/types'
23
+
24
+ import type { ComposableProofProvider } from './composer/interface'
25
+ import type {
26
+ ProofGenerationRequest,
27
+ ProofGenerationResult,
28
+ FallbackConfig,
29
+ } from './composer/types'
30
+
31
+ // ─── Types ───────────────────────────────────────────────────────────────────
32
+
33
+ /**
34
+ * Fallback strategy interface
35
+ */
36
+ export interface FallbackStrategy {
37
+ /** Strategy name */
38
+ readonly name: string
39
+
40
+ /** Get next provider in fallback chain */
41
+ getNextProvider(
42
+ currentProvider: ProofSystem | null,
43
+ failedProviders: Set<ProofSystem>,
44
+ ): ProofSystem | null
45
+
46
+ /** Check if fallback should be attempted */
47
+ shouldAttemptFallback(
48
+ error: Error,
49
+ attemptCount: number,
50
+ maxAttempts: number,
51
+ ): boolean
52
+
53
+ /** Get fallback delay (for retry backoff) */
54
+ getRetryDelay(attemptCount: number): number
55
+ }
56
+
57
+ /**
58
+ * Circuit breaker state
59
+ */
60
+ export interface CircuitBreakerState {
61
+ /** Current state */
62
+ state: 'closed' | 'open' | 'half-open'
63
+ /** Number of consecutive failures */
64
+ failureCount: number
65
+ /** Last failure timestamp */
66
+ lastFailureAt: number
67
+ /** Time when circuit opened */
68
+ openedAt?: number
69
+ /** Success count in half-open state */
70
+ halfOpenSuccessCount: number
71
+ }
72
+
73
+ /**
74
+ * Circuit breaker configuration
75
+ */
76
+ export interface CircuitBreakerConfig {
77
+ /** Failures before opening circuit */
78
+ failureThreshold: number
79
+ /** Time to wait before half-open (ms) */
80
+ resetTimeoutMs: number
81
+ /** Successes needed in half-open to close */
82
+ halfOpenSuccessThreshold: number
83
+ }
84
+
85
+ /**
86
+ * Provider health status
87
+ */
88
+ export interface ProviderHealth {
89
+ /** Provider system */
90
+ system: ProofSystem
91
+ /** Whether provider is healthy */
92
+ isHealthy: boolean
93
+ /** Circuit breaker state */
94
+ circuitBreaker: CircuitBreakerState
95
+ /** Success rate (0-1) */
96
+ successRate: number
97
+ /** Average response time (ms) */
98
+ avgResponseTimeMs: number
99
+ /** Last successful operation timestamp */
100
+ lastSuccessAt?: number
101
+ /** Last error message */
102
+ lastError?: string
103
+ }
104
+
105
+ /**
106
+ * Fallback event types
107
+ */
108
+ export type FallbackEventType =
109
+ | 'fallback:started'
110
+ | 'fallback:provider_failed'
111
+ | 'fallback:provider_switched'
112
+ | 'fallback:success'
113
+ | 'fallback:exhausted'
114
+ | 'circuit:opened'
115
+ | 'circuit:closed'
116
+ | 'circuit:half_open'
117
+
118
+ /**
119
+ * Fallback event
120
+ */
121
+ export interface FallbackEvent {
122
+ type: FallbackEventType
123
+ timestamp: number
124
+ system?: ProofSystem
125
+ error?: string
126
+ attemptCount?: number
127
+ details?: Record<string, unknown>
128
+ /** Previous state (for circuit breaker transitions) */
129
+ previousState?: 'closed' | 'open' | 'half-open'
130
+ }
131
+
132
+ /**
133
+ * Fallback event listener
134
+ */
135
+ export type FallbackEventListener = (event: FallbackEvent) => void
136
+
137
+ /**
138
+ * Fallback executor options
139
+ */
140
+ export interface FallbackExecutorConfig {
141
+ /** Fallback configuration */
142
+ fallbackConfig: FallbackConfig
143
+ /** Circuit breaker config */
144
+ circuitBreakerConfig?: CircuitBreakerConfig
145
+ /** Enable mock fallback in development */
146
+ enableMockFallback?: boolean
147
+ /** Log all fallback events */
148
+ enableLogging?: boolean
149
+ }
150
+
151
+ // ─── Default Configurations ──────────────────────────────────────────────────
152
+
153
+ export const DEFAULT_CIRCUIT_BREAKER_CONFIG: CircuitBreakerConfig = {
154
+ failureThreshold: 5,
155
+ resetTimeoutMs: 30000, // 30 seconds
156
+ halfOpenSuccessThreshold: 3,
157
+ }
158
+
159
+ export const DEFAULT_FALLBACK_CONFIG: FallbackConfig = {
160
+ primary: 'noir',
161
+ fallbackChain: ['halo2', 'kimchi'],
162
+ retryOnFailure: true,
163
+ maxRetries: 3,
164
+ retryDelayMs: 1000,
165
+ exponentialBackoff: true,
166
+ }
167
+
168
+ // ─── Fallback Strategies ─────────────────────────────────────────────────────
169
+
170
+ /**
171
+ * Simple sequential fallback strategy
172
+ */
173
+ export class SequentialFallbackStrategy implements FallbackStrategy {
174
+ readonly name = 'sequential'
175
+
176
+ private _fallbackChain: ProofSystem[]
177
+
178
+ constructor(fallbackChain: ProofSystem[]) {
179
+ this._fallbackChain = fallbackChain
180
+ }
181
+
182
+ getNextProvider(
183
+ currentProvider: ProofSystem | null,
184
+ failedProviders: Set<ProofSystem>,
185
+ ): ProofSystem | null {
186
+ // Find first available provider in chain that hasn't failed
187
+ for (const system of this._fallbackChain) {
188
+ if (!failedProviders.has(system) && system !== currentProvider) {
189
+ return system
190
+ }
191
+ }
192
+ return null
193
+ }
194
+
195
+ shouldAttemptFallback(
196
+ _error: Error,
197
+ attemptCount: number,
198
+ maxAttempts: number,
199
+ ): boolean {
200
+ return attemptCount < maxAttempts
201
+ }
202
+
203
+ getRetryDelay(attemptCount: number): number {
204
+ // Linear backoff
205
+ return 1000 * attemptCount
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Exponential backoff fallback strategy
211
+ */
212
+ export class ExponentialBackoffStrategy implements FallbackStrategy {
213
+ readonly name = 'exponential-backoff'
214
+
215
+ private _fallbackChain: ProofSystem[]
216
+ private _baseDelayMs: number
217
+ private _maxDelayMs: number
218
+
219
+ constructor(
220
+ fallbackChain: ProofSystem[],
221
+ baseDelayMs: number = 1000,
222
+ maxDelayMs: number = 30000,
223
+ ) {
224
+ this._fallbackChain = fallbackChain
225
+ this._baseDelayMs = baseDelayMs
226
+ this._maxDelayMs = maxDelayMs
227
+ }
228
+
229
+ getNextProvider(
230
+ currentProvider: ProofSystem | null,
231
+ failedProviders: Set<ProofSystem>,
232
+ ): ProofSystem | null {
233
+ for (const system of this._fallbackChain) {
234
+ if (!failedProviders.has(system) && system !== currentProvider) {
235
+ return system
236
+ }
237
+ }
238
+ return null
239
+ }
240
+
241
+ shouldAttemptFallback(
242
+ _error: Error,
243
+ attemptCount: number,
244
+ maxAttempts: number,
245
+ ): boolean {
246
+ return attemptCount < maxAttempts
247
+ }
248
+
249
+ getRetryDelay(attemptCount: number): number {
250
+ const exponentialDelay = this._baseDelayMs * Math.pow(2, attemptCount)
251
+ const jitter = Math.random() * 0.3 * exponentialDelay
252
+ return Math.min(exponentialDelay + jitter, this._maxDelayMs)
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Priority-based fallback strategy (health-aware)
258
+ */
259
+ export class PriorityFallbackStrategy implements FallbackStrategy {
260
+ readonly name = 'priority'
261
+
262
+ private _priorities: Map<ProofSystem, number>
263
+ private _healthProvider: () => Map<ProofSystem, ProviderHealth>
264
+
265
+ constructor(
266
+ priorities: Map<ProofSystem, number>,
267
+ healthProvider: () => Map<ProofSystem, ProviderHealth>,
268
+ ) {
269
+ this._priorities = priorities
270
+ this._healthProvider = healthProvider
271
+ }
272
+
273
+ getNextProvider(
274
+ _currentProvider: ProofSystem | null,
275
+ failedProviders: Set<ProofSystem>,
276
+ ): ProofSystem | null {
277
+ const health = this._healthProvider()
278
+
279
+ // Sort by priority * health score
280
+ const candidates = Array.from(this._priorities.entries())
281
+ .filter(([system]) => !failedProviders.has(system))
282
+ .map(([system, priority]) => {
283
+ const providerHealth = health.get(system)
284
+ const healthScore = providerHealth?.isHealthy ? providerHealth.successRate : 0
285
+ return { system, score: priority * healthScore }
286
+ })
287
+ .sort((a, b) => b.score - a.score)
288
+
289
+ // Return null if no candidates or all have score 0 (all unhealthy)
290
+ if (candidates.length === 0 || candidates[0].score === 0) {
291
+ return null
292
+ }
293
+
294
+ return candidates[0].system
295
+ }
296
+
297
+ shouldAttemptFallback(
298
+ _error: Error,
299
+ attemptCount: number,
300
+ maxAttempts: number,
301
+ ): boolean {
302
+ return attemptCount < maxAttempts
303
+ }
304
+
305
+ getRetryDelay(attemptCount: number): number {
306
+ return 1000 * Math.pow(1.5, attemptCount)
307
+ }
308
+ }
309
+
310
+ // ─── Circuit Breaker ─────────────────────────────────────────────────────────
311
+
312
+ /**
313
+ * Circuit breaker for provider health management
314
+ */
315
+ export class CircuitBreaker {
316
+ private _states: Map<ProofSystem, CircuitBreakerState> = new Map()
317
+ private _config: CircuitBreakerConfig
318
+ private _eventListeners: Set<FallbackEventListener> = new Set()
319
+
320
+ constructor(config: CircuitBreakerConfig = DEFAULT_CIRCUIT_BREAKER_CONFIG) {
321
+ this._config = config
322
+ }
323
+
324
+ /**
325
+ * Get or create circuit breaker state for a provider
326
+ */
327
+ getState(system: ProofSystem): CircuitBreakerState {
328
+ let state = this._states.get(system)
329
+ if (!state) {
330
+ state = {
331
+ state: 'closed',
332
+ failureCount: 0,
333
+ lastFailureAt: 0,
334
+ halfOpenSuccessCount: 0,
335
+ }
336
+ this._states.set(system, state)
337
+ }
338
+ return state
339
+ }
340
+
341
+ /**
342
+ * Check if requests to a provider are allowed
343
+ */
344
+ isAllowed(system: ProofSystem): boolean {
345
+ const state = this.getState(system)
346
+
347
+ switch (state.state) {
348
+ case 'closed':
349
+ return true
350
+
351
+ case 'open':
352
+ // Check if reset timeout has passed
353
+ if (Date.now() - (state.openedAt || 0) > this._config.resetTimeoutMs) {
354
+ this._transitionTo(system, 'half-open')
355
+ return true
356
+ }
357
+ return false
358
+
359
+ case 'half-open':
360
+ // Allow limited requests in half-open state
361
+ return true
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Record a successful operation
367
+ */
368
+ recordSuccess(system: ProofSystem): void {
369
+ const state = this.getState(system)
370
+
371
+ if (state.state === 'half-open') {
372
+ state.halfOpenSuccessCount++
373
+ if (state.halfOpenSuccessCount >= this._config.halfOpenSuccessThreshold) {
374
+ this._transitionTo(system, 'closed')
375
+ }
376
+ } else if (state.state === 'closed') {
377
+ // Reset failure count on success
378
+ state.failureCount = Math.max(0, state.failureCount - 1)
379
+ }
380
+ }
381
+
382
+ /**
383
+ * Record a failed operation
384
+ */
385
+ recordFailure(system: ProofSystem, error?: string): void {
386
+ const state = this.getState(system)
387
+
388
+ state.failureCount++
389
+ state.lastFailureAt = Date.now()
390
+
391
+ if (state.state === 'half-open') {
392
+ // Immediately open circuit on failure in half-open state
393
+ this._transitionTo(system, 'open')
394
+ } else if (state.state === 'closed') {
395
+ if (state.failureCount >= this._config.failureThreshold) {
396
+ this._transitionTo(system, 'open')
397
+ }
398
+ }
399
+
400
+ this._emit({
401
+ type: 'fallback:provider_failed',
402
+ timestamp: Date.now(),
403
+ system,
404
+ error,
405
+ details: { failureCount: state.failureCount },
406
+ })
407
+ }
408
+
409
+ /**
410
+ * Reset circuit breaker for a provider
411
+ */
412
+ reset(system: ProofSystem): void {
413
+ this._states.set(system, {
414
+ state: 'closed',
415
+ failureCount: 0,
416
+ lastFailureAt: 0,
417
+ halfOpenSuccessCount: 0,
418
+ })
419
+ }
420
+
421
+ /**
422
+ * Reset all circuit breakers
423
+ */
424
+ resetAll(): void {
425
+ this._states.clear()
426
+ }
427
+
428
+ /**
429
+ * Add event listener
430
+ */
431
+ addEventListener(listener: FallbackEventListener): () => void {
432
+ this._eventListeners.add(listener)
433
+ return () => this._eventListeners.delete(listener)
434
+ }
435
+
436
+ private _transitionTo(
437
+ system: ProofSystem,
438
+ newState: 'closed' | 'open' | 'half-open',
439
+ ): void {
440
+ const state = this.getState(system)
441
+ const previousState = state.state
442
+
443
+ // Only transition if state actually changes
444
+ if (previousState === newState) return
445
+
446
+ state.state = newState
447
+
448
+ if (newState === 'open') {
449
+ state.openedAt = Date.now()
450
+ this._emit({ type: 'circuit:opened', timestamp: Date.now(), system, previousState })
451
+ } else if (newState === 'closed') {
452
+ state.failureCount = 0
453
+ state.halfOpenSuccessCount = 0
454
+ this._emit({ type: 'circuit:closed', timestamp: Date.now(), system, previousState })
455
+ } else if (newState === 'half-open') {
456
+ state.halfOpenSuccessCount = 0
457
+ this._emit({ type: 'circuit:half_open', timestamp: Date.now(), system, previousState })
458
+ }
459
+ }
460
+
461
+ private _emit(event: FallbackEvent): void {
462
+ for (const listener of this._eventListeners) {
463
+ try {
464
+ listener(event)
465
+ } catch {
466
+ // Ignore listener errors
467
+ }
468
+ }
469
+ }
470
+ }
471
+
472
+ // ─── Fallback Executor ───────────────────────────────────────────────────────
473
+
474
+ /**
475
+ * Executes proof generation with fallback support
476
+ */
477
+ export class FallbackExecutor {
478
+ private _config: FallbackExecutorConfig
479
+ private _strategy: FallbackStrategy
480
+ private _circuitBreaker: CircuitBreaker
481
+ private _providers: Map<ProofSystem, ComposableProofProvider> = new Map()
482
+ private _health: Map<ProofSystem, ProviderHealth> = new Map()
483
+ private _eventListeners: Set<FallbackEventListener> = new Set()
484
+ private _mockProvider?: ComposableProofProvider
485
+
486
+ constructor(config: FallbackExecutorConfig, customStrategy?: FallbackStrategy) {
487
+ this._config = config
488
+
489
+ // Use custom strategy if provided, otherwise create based on config
490
+ if (customStrategy) {
491
+ this._strategy = customStrategy
492
+ } else if (config.fallbackConfig.exponentialBackoff) {
493
+ this._strategy = new ExponentialBackoffStrategy(
494
+ [config.fallbackConfig.primary, ...config.fallbackConfig.fallbackChain],
495
+ config.fallbackConfig.retryDelayMs,
496
+ )
497
+ } else {
498
+ this._strategy = new SequentialFallbackStrategy(
499
+ [config.fallbackConfig.primary, ...config.fallbackConfig.fallbackChain],
500
+ )
501
+ }
502
+
503
+ this._circuitBreaker = new CircuitBreaker(
504
+ config.circuitBreakerConfig || DEFAULT_CIRCUIT_BREAKER_CONFIG,
505
+ )
506
+
507
+ // Forward circuit breaker events
508
+ this._circuitBreaker.addEventListener(event => this._emit(event))
509
+ }
510
+
511
+ /**
512
+ * Register a provider
513
+ */
514
+ registerProvider(provider: ComposableProofProvider): void {
515
+ this._providers.set(provider.system, provider)
516
+ this._health.set(provider.system, this._createInitialHealth(provider.system))
517
+ }
518
+
519
+ /**
520
+ * Set mock provider for development fallback
521
+ */
522
+ setMockProvider(provider: ComposableProofProvider): void {
523
+ this._mockProvider = provider
524
+ }
525
+
526
+ /**
527
+ * Execute proof generation with fallback
528
+ */
529
+ async execute(request: ProofGenerationRequest): Promise<ProofGenerationResult> {
530
+ const startTime = Date.now()
531
+ const failedProviders = new Set<ProofSystem>()
532
+ let currentProvider = request.system || this._config.fallbackConfig.primary
533
+ let attemptCount = 0
534
+ const maxAttempts = this._config.fallbackConfig.maxRetries + 1
535
+
536
+ this._emit({
537
+ type: 'fallback:started',
538
+ timestamp: startTime,
539
+ system: currentProvider,
540
+ details: { request: { circuitId: request.circuitId } },
541
+ })
542
+
543
+ while (attemptCount < maxAttempts) {
544
+ // Check circuit breaker
545
+ if (!this._circuitBreaker.isAllowed(currentProvider)) {
546
+ this._log(`Circuit open for ${currentProvider}, finding alternative`)
547
+ failedProviders.add(currentProvider)
548
+ const nextProvider = this._strategy.getNextProvider(currentProvider, failedProviders)
549
+
550
+ if (!nextProvider) {
551
+ break
552
+ }
553
+
554
+ this._emit({
555
+ type: 'fallback:provider_switched',
556
+ timestamp: Date.now(),
557
+ system: nextProvider,
558
+ details: { from: currentProvider, reason: 'circuit_open' },
559
+ })
560
+
561
+ currentProvider = nextProvider
562
+ continue
563
+ }
564
+
565
+ // Get provider
566
+ const provider = this._providers.get(currentProvider)
567
+ if (!provider) {
568
+ this._log(`Provider ${currentProvider} not found`)
569
+ failedProviders.add(currentProvider)
570
+ const nextProvider = this._strategy.getNextProvider(currentProvider, failedProviders)
571
+
572
+ if (!nextProvider) {
573
+ break
574
+ }
575
+
576
+ currentProvider = nextProvider
577
+ continue
578
+ }
579
+
580
+ // Attempt proof generation
581
+ try {
582
+ const result = await provider.generateProof({
583
+ ...request,
584
+ system: currentProvider,
585
+ })
586
+
587
+ if (result.success) {
588
+ this._circuitBreaker.recordSuccess(currentProvider)
589
+ this._updateHealth(currentProvider, true, Date.now() - startTime)
590
+
591
+ this._emit({
592
+ type: 'fallback:success',
593
+ timestamp: Date.now(),
594
+ system: currentProvider,
595
+ attemptCount,
596
+ })
597
+
598
+ return result
599
+ }
600
+
601
+ // Generation returned failure
602
+ throw new Error(result.error || 'Proof generation failed')
603
+ } catch (error) {
604
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
605
+ this._log(`Provider ${currentProvider} failed: ${errorMessage}`)
606
+
607
+ this._circuitBreaker.recordFailure(currentProvider, errorMessage)
608
+ this._updateHealth(currentProvider, false, Date.now() - startTime, errorMessage)
609
+ failedProviders.add(currentProvider)
610
+
611
+ attemptCount++
612
+
613
+ // Check if we should retry
614
+ if (!this._strategy.shouldAttemptFallback(
615
+ error instanceof Error ? error : new Error(errorMessage),
616
+ attemptCount,
617
+ maxAttempts,
618
+ )) {
619
+ break
620
+ }
621
+
622
+ // Find next provider
623
+ const nextProvider = this._strategy.getNextProvider(currentProvider, failedProviders)
624
+
625
+ if (nextProvider) {
626
+ this._emit({
627
+ type: 'fallback:provider_switched',
628
+ timestamp: Date.now(),
629
+ system: nextProvider,
630
+ details: { from: currentProvider, reason: 'failure' },
631
+ })
632
+
633
+ currentProvider = nextProvider
634
+
635
+ // Apply retry delay
636
+ const delay = this._strategy.getRetryDelay(attemptCount)
637
+ await this._delay(delay)
638
+ } else {
639
+ break
640
+ }
641
+ }
642
+ }
643
+
644
+ // All providers exhausted - try mock fallback if enabled
645
+ if (this._config.enableMockFallback && this._mockProvider) {
646
+ this._log('Using mock fallback provider')
647
+
648
+ try {
649
+ const result = await this._mockProvider.generateProof(request)
650
+ if (result.success) {
651
+ return result
652
+ }
653
+ } catch {
654
+ // Mock also failed
655
+ }
656
+ }
657
+
658
+ this._emit({
659
+ type: 'fallback:exhausted',
660
+ timestamp: Date.now(),
661
+ attemptCount,
662
+ details: { failedProviders: Array.from(failedProviders) },
663
+ })
664
+
665
+ return {
666
+ success: false,
667
+ error: `All providers exhausted after ${attemptCount} attempts`,
668
+ timeMs: Date.now() - startTime,
669
+ providerId: 'fallback',
670
+ }
671
+ }
672
+
673
+ /**
674
+ * Get health status for all providers
675
+ */
676
+ getHealth(): Map<ProofSystem, ProviderHealth> {
677
+ return new Map(this._health)
678
+ }
679
+
680
+ /**
681
+ * Get health status for a specific provider
682
+ */
683
+ getProviderHealth(system: ProofSystem): ProviderHealth | undefined {
684
+ return this._health.get(system)
685
+ }
686
+
687
+ /**
688
+ * Reset circuit breaker for a provider
689
+ */
690
+ resetCircuitBreaker(system: ProofSystem): void {
691
+ this._circuitBreaker.reset(system)
692
+ const health = this._health.get(system)
693
+ if (health) {
694
+ health.circuitBreaker = this._circuitBreaker.getState(system)
695
+ }
696
+ }
697
+
698
+ /**
699
+ * Add event listener
700
+ */
701
+ addEventListener(listener: FallbackEventListener): () => void {
702
+ this._eventListeners.add(listener)
703
+ return () => this._eventListeners.delete(listener)
704
+ }
705
+
706
+ /**
707
+ * Get current fallback strategy
708
+ */
709
+ get strategy(): FallbackStrategy {
710
+ return this._strategy
711
+ }
712
+
713
+ /**
714
+ * Set fallback strategy
715
+ */
716
+ setStrategy(strategy: FallbackStrategy): void {
717
+ this._strategy = strategy
718
+ }
719
+
720
+ private _createInitialHealth(system: ProofSystem): ProviderHealth {
721
+ return {
722
+ system,
723
+ isHealthy: true,
724
+ circuitBreaker: this._circuitBreaker.getState(system),
725
+ successRate: 1.0,
726
+ avgResponseTimeMs: 0,
727
+ }
728
+ }
729
+
730
+ private _updateHealth(
731
+ system: ProofSystem,
732
+ success: boolean,
733
+ responseTimeMs: number,
734
+ error?: string,
735
+ ): void {
736
+ const health = this._health.get(system)
737
+ if (!health) return
738
+
739
+ // Update circuit breaker state
740
+ health.circuitBreaker = this._circuitBreaker.getState(system)
741
+ health.isHealthy = health.circuitBreaker.state === 'closed'
742
+
743
+ // Update metrics (exponential moving average)
744
+ const alpha = 0.2
745
+ health.avgResponseTimeMs = alpha * responseTimeMs + (1 - alpha) * health.avgResponseTimeMs
746
+
747
+ if (success) {
748
+ health.lastSuccessAt = Date.now()
749
+ health.successRate = alpha * 1 + (1 - alpha) * health.successRate
750
+ } else {
751
+ health.lastError = error
752
+ health.successRate = alpha * 0 + (1 - alpha) * health.successRate
753
+ }
754
+ }
755
+
756
+ private _emit(event: FallbackEvent): void {
757
+ if (this._config.enableLogging) {
758
+ this._log(`[${event.type}] ${event.system || ''} ${JSON.stringify(event.details || {})}`)
759
+ }
760
+
761
+ for (const listener of this._eventListeners) {
762
+ try {
763
+ listener(event)
764
+ } catch {
765
+ // Ignore listener errors
766
+ }
767
+ }
768
+ }
769
+
770
+ private _log(message: string): void {
771
+ if (this._config.enableLogging) {
772
+ console.log(`[FallbackExecutor] ${message}`)
773
+ }
774
+ }
775
+
776
+ private _delay(ms: number): Promise<void> {
777
+ return new Promise(resolve => setTimeout(resolve, ms))
778
+ }
779
+ }
780
+
781
+ // ─── Mock Fallback Provider ──────────────────────────────────────────────────
782
+
783
+ /**
784
+ * Create a mock provider for development fallback
785
+ */
786
+ export function createMockFallbackProvider(): ComposableProofProvider {
787
+ let proofCounter = 0
788
+
789
+ return {
790
+ system: 'noir' as ProofSystem,
791
+ capabilities: {
792
+ system: 'noir',
793
+ supportsRecursion: false,
794
+ supportsBatchVerification: false,
795
+ supportsBrowser: true,
796
+ supportsNode: true,
797
+ maxProofSize: 65536,
798
+ supportedStrategies: [],
799
+ availableCircuits: ['*'], // Accepts any circuit
800
+ },
801
+ status: {
802
+ isReady: true,
803
+ isBusy: false,
804
+ queueLength: 0,
805
+ metrics: {
806
+ proofsGenerated: 0,
807
+ proofsVerified: 0,
808
+ avgGenerationTimeMs: 10,
809
+ avgVerificationTimeMs: 5,
810
+ successRate: 1.0,
811
+ memoryUsageBytes: 0,
812
+ },
813
+ },
814
+
815
+ async initialize() {},
816
+ async waitUntilReady() {},
817
+
818
+ async generateProof(request) {
819
+ proofCounter++
820
+ const proof: SingleProof = {
821
+ id: `mock-proof-${proofCounter}`,
822
+ proof: '0xmock_proof_data_for_development' as HexString,
823
+ publicInputs: [] as HexString[],
824
+ metadata: {
825
+ system: 'noir',
826
+ systemVersion: 'mock-1.0.0',
827
+ circuitId: request.circuitId,
828
+ circuitVersion: 'mock',
829
+ generatedAt: Date.now(),
830
+ proofSizeBytes: 32,
831
+ },
832
+ }
833
+
834
+ return {
835
+ success: true,
836
+ proof,
837
+ timeMs: 10,
838
+ providerId: 'mock-fallback',
839
+ }
840
+ },
841
+
842
+ async verifyProof() {
843
+ return true
844
+ },
845
+
846
+ async verifyBatch(proofs) {
847
+ return proofs.map(() => true)
848
+ },
849
+
850
+ getAvailableCircuits() {
851
+ return ['*']
852
+ },
853
+
854
+ hasCircuit() {
855
+ return true // Accepts any circuit
856
+ },
857
+
858
+ async dispose() {},
859
+ }
860
+ }
861
+
862
+ // ─── Factory Functions ───────────────────────────────────────────────────────
863
+
864
+ /**
865
+ * Create a fallback executor with default configuration
866
+ */
867
+ export function createFallbackExecutor(
868
+ config?: Partial<FallbackExecutorConfig>,
869
+ ): FallbackExecutor {
870
+ return new FallbackExecutor({
871
+ fallbackConfig: config?.fallbackConfig || DEFAULT_FALLBACK_CONFIG,
872
+ circuitBreakerConfig: config?.circuitBreakerConfig,
873
+ enableMockFallback: config?.enableMockFallback ?? false,
874
+ enableLogging: config?.enableLogging ?? false,
875
+ })
876
+ }
877
+
878
+ /**
879
+ * Create a circuit breaker with custom configuration
880
+ */
881
+ export function createCircuitBreaker(
882
+ config?: Partial<CircuitBreakerConfig>,
883
+ ): CircuitBreaker {
884
+ return new CircuitBreaker({
885
+ ...DEFAULT_CIRCUIT_BREAKER_CONFIG,
886
+ ...config,
887
+ })
888
+ }