@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,626 @@
1
+ /**
2
+ * SmartRouter - Privacy Backend Selection
3
+ *
4
+ * Automatically selects the optimal privacy backend based on:
5
+ * - User preferences (privacy, speed, cost, compliance)
6
+ * - Backend capabilities and availability
7
+ * - Transfer parameters
8
+ * - Backend health status (circuit breaker)
9
+ *
10
+ * ## Features
11
+ *
12
+ * - **Health-aware selection**: Skips backends with open circuit breakers
13
+ * - **Automatic fallback**: Tries alternatives when primary backend fails
14
+ * - **Metrics tracking**: Records success/failure for health monitoring
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { SmartRouter, PrivacyBackendRegistry, SIPNativeBackend } from '@sip-protocol/sdk'
19
+ *
20
+ * const registry = new PrivacyBackendRegistry()
21
+ * registry.register(new SIPNativeBackend())
22
+ *
23
+ * const router = new SmartRouter(registry)
24
+ *
25
+ * // Auto-select best backend with fallback
26
+ * const result = await router.execute(params, {
27
+ * prioritize: 'compliance',
28
+ * requireViewingKeys: true,
29
+ * enableFallback: true,
30
+ * })
31
+ *
32
+ * // Or just select without executing
33
+ * const selection = await router.selectBackend(params, config)
34
+ * console.log(`Selected: ${selection.backend.name}`)
35
+ * ```
36
+ */
37
+
38
+ import type {
39
+ PrivacyBackend,
40
+ TransferParams,
41
+ TransactionResult,
42
+ ComputationParams,
43
+ ComputationResult,
44
+ SmartRouterConfig,
45
+ BackendSelectionResult,
46
+ AvailabilityResult,
47
+ } from './interface'
48
+ import { AllBackendsFailedError } from './interface'
49
+ import { PrivacyBackendRegistry } from './registry'
50
+
51
+ /**
52
+ * Default router configuration
53
+ */
54
+ const DEFAULT_CONFIG: SmartRouterConfig = {
55
+ prioritize: 'privacy',
56
+ requireViewingKeys: false,
57
+ allowComputePrivacy: true,
58
+ enableFallback: true,
59
+ includeUnhealthy: false,
60
+ maxFallbackAttempts: 3,
61
+ }
62
+
63
+ /**
64
+ * Scoring weights for different priorities
65
+ */
66
+ const PRIORITY_WEIGHTS = {
67
+ privacy: {
68
+ hiddenAmount: 25,
69
+ hiddenSender: 25,
70
+ hiddenRecipient: 25,
71
+ hiddenCompute: 10,
72
+ anonymitySet: 15,
73
+ },
74
+ speed: {
75
+ fast: 40,
76
+ medium: 25,
77
+ slow: 10,
78
+ setupRequired: -20,
79
+ },
80
+ cost: {
81
+ baseCost: 50,
82
+ estimatedCost: 50,
83
+ },
84
+ compliance: {
85
+ complianceSupport: 60,
86
+ hiddenAmount: 15,
87
+ hiddenSender: 15,
88
+ hiddenRecipient: 10,
89
+ },
90
+ }
91
+
92
+ /**
93
+ * SmartRouter for automatic backend selection
94
+ *
95
+ * Analyzes available backends and selects the optimal one
96
+ * based on user preferences and transfer requirements.
97
+ */
98
+ export class SmartRouter {
99
+ private registry: PrivacyBackendRegistry
100
+
101
+ /**
102
+ * Create a new SmartRouter
103
+ *
104
+ * @param registry - Backend registry to use for selection
105
+ */
106
+ constructor(registry: PrivacyBackendRegistry) {
107
+ this.registry = registry
108
+ }
109
+
110
+ /**
111
+ * Select the best backend for a transfer
112
+ *
113
+ * @param params - Transfer parameters
114
+ * @param config - Router configuration
115
+ * @returns Selection result with backend and reasoning
116
+ * @throws Error if no suitable backend is found
117
+ */
118
+ async selectBackend(
119
+ params: TransferParams,
120
+ config: Partial<SmartRouterConfig> = {}
121
+ ): Promise<BackendSelectionResult> {
122
+ const fullConfig = { ...DEFAULT_CONFIG, ...config }
123
+
124
+ // Get backends for the chain
125
+ const chainBackends = this.registry.getByChain(params.chain)
126
+
127
+ if (chainBackends.length === 0) {
128
+ throw new Error(
129
+ `No backends available for chain '${params.chain}'. ` +
130
+ `Register a backend that supports this chain.`
131
+ )
132
+ }
133
+
134
+ // Filter and score backends
135
+ const scoredBackends: Array<{
136
+ backend: PrivacyBackend
137
+ availability: AvailabilityResult
138
+ score: number
139
+ reason: string
140
+ }> = []
141
+
142
+ for (const backend of chainBackends) {
143
+ // Check exclusions
144
+ if (fullConfig.excludeBackends?.includes(backend.name)) {
145
+ continue
146
+ }
147
+
148
+ // Check health status (circuit breaker)
149
+ if (!fullConfig.includeUnhealthy && !this.registry.isHealthy(backend.name)) {
150
+ continue
151
+ }
152
+
153
+ // Check availability
154
+ const availability = await backend.checkAvailability(params)
155
+ if (!availability.available) {
156
+ continue
157
+ }
158
+
159
+ // Check hard requirements
160
+ const capabilities = backend.getCapabilities()
161
+
162
+ // Viewing key requirement
163
+ if (fullConfig.requireViewingKeys && !capabilities.complianceSupport) {
164
+ continue
165
+ }
166
+
167
+ // Anonymity set requirement
168
+ if (
169
+ fullConfig.minAnonymitySet &&
170
+ capabilities.anonymitySet !== undefined &&
171
+ capabilities.anonymitySet < fullConfig.minAnonymitySet
172
+ ) {
173
+ continue
174
+ }
175
+
176
+ // Compute privacy filter
177
+ if (!fullConfig.allowComputePrivacy && backend.type === 'compute') {
178
+ continue
179
+ }
180
+
181
+ // Cost limit
182
+ if (fullConfig.maxCost && availability.estimatedCost) {
183
+ if (availability.estimatedCost > fullConfig.maxCost) {
184
+ continue
185
+ }
186
+ }
187
+
188
+ // Latency limit
189
+ if (fullConfig.maxLatency && availability.estimatedTime) {
190
+ if (availability.estimatedTime > fullConfig.maxLatency) {
191
+ continue
192
+ }
193
+ }
194
+
195
+ // Score this backend
196
+ const { score, reason } = this.scoreBackend(
197
+ backend,
198
+ availability,
199
+ fullConfig
200
+ )
201
+
202
+ scoredBackends.push({
203
+ backend,
204
+ availability,
205
+ score,
206
+ reason,
207
+ })
208
+ }
209
+
210
+ if (scoredBackends.length === 0) {
211
+ throw new Error(
212
+ `No backends meet the requirements for this transfer. ` +
213
+ `Check your router configuration and registered backends.`
214
+ )
215
+ }
216
+
217
+ // Sort by score (descending)
218
+ scoredBackends.sort((a, b) => b.score - a.score)
219
+
220
+ // Preferred backend bonus
221
+ if (fullConfig.preferredBackend) {
222
+ const preferredIndex = scoredBackends.findIndex(
223
+ s => s.backend.name === fullConfig.preferredBackend
224
+ )
225
+ if (preferredIndex > 0) {
226
+ // Move preferred to top if within 10 points of leader
227
+ const preferred = scoredBackends[preferredIndex]
228
+ const leader = scoredBackends[0]
229
+ if (leader.score - preferred.score <= 10) {
230
+ scoredBackends.splice(preferredIndex, 1)
231
+ scoredBackends.unshift(preferred)
232
+ preferred.reason = `Preferred backend (within 10pts of optimal)`
233
+ }
234
+ }
235
+ }
236
+
237
+ const selected = scoredBackends[0]
238
+ const alternatives = scoredBackends.slice(1).map(s => ({
239
+ backend: s.backend,
240
+ score: s.score,
241
+ reason: s.reason,
242
+ }))
243
+
244
+ return {
245
+ backend: selected.backend,
246
+ reason: selected.reason,
247
+ alternatives,
248
+ score: selected.score,
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Execute a transfer using the best available backend
254
+ *
255
+ * Includes automatic fallback to alternatives if the primary backend fails
256
+ * (when enableFallback is true). Records success/failure for health tracking.
257
+ *
258
+ * @param params - Transfer parameters
259
+ * @param config - Router configuration
260
+ * @returns Transaction result
261
+ * @throws AllBackendsFailedError if all backends fail
262
+ */
263
+ async execute(
264
+ params: TransferParams,
265
+ config: Partial<SmartRouterConfig> = {}
266
+ ): Promise<TransactionResult> {
267
+ const fullConfig = {
268
+ ...DEFAULT_CONFIG,
269
+ ...config,
270
+ allowComputePrivacy: false, // Only transaction backends for execute()
271
+ }
272
+ const selection = await this.selectBackend(params, fullConfig)
273
+
274
+ // Try primary backend
275
+ const result = await this.executeOnBackend(selection.backend, params)
276
+
277
+ if (result.success) {
278
+ return result
279
+ }
280
+
281
+ // Primary failed, try fallback if enabled
282
+ if (!fullConfig.enableFallback || selection.alternatives.length === 0) {
283
+ return result
284
+ }
285
+
286
+ // Try alternatives
287
+ const attemptedBackends = [selection.backend.name]
288
+ const errors = new Map<string, string>()
289
+ errors.set(selection.backend.name, result.error || 'Unknown error')
290
+
291
+ const maxFallbackAttempts = fullConfig.maxFallbackAttempts ?? 3
292
+
293
+ // Iterate over all alternatives, but limit actual attempts
294
+ // Skipped backends (unhealthy/already attempted) don't count against the limit
295
+ let actualAttempts = 0
296
+ for (
297
+ let i = 0;
298
+ i < selection.alternatives.length && actualAttempts < maxFallbackAttempts;
299
+ i++
300
+ ) {
301
+ const alternative = selection.alternatives[i]
302
+
303
+ // Skip if already attempted (defensive - shouldn't happen with unique names)
304
+ if (attemptedBackends.includes(alternative.backend.name)) {
305
+ continue
306
+ }
307
+
308
+ // Skip unhealthy backends unless explicitly included
309
+ if (!fullConfig.includeUnhealthy && !this.registry.isHealthy(alternative.backend.name)) {
310
+ continue
311
+ }
312
+
313
+ // This counts as an actual attempt
314
+ actualAttempts++
315
+ attemptedBackends.push(alternative.backend.name)
316
+ const fallbackResult = await this.executeOnBackend(alternative.backend, params)
317
+
318
+ if (fallbackResult.success) {
319
+ // Add metadata about fallback
320
+ return {
321
+ ...fallbackResult,
322
+ metadata: {
323
+ ...fallbackResult.metadata,
324
+ fallbackFrom: selection.backend.name,
325
+ attemptedBackends,
326
+ },
327
+ }
328
+ }
329
+
330
+ errors.set(alternative.backend.name, fallbackResult.error || 'Unknown error')
331
+ }
332
+
333
+ // All attempts failed
334
+ throw new AllBackendsFailedError(attemptedBackends, errors, params)
335
+ }
336
+
337
+ /**
338
+ * Execute on a specific backend with health tracking
339
+ *
340
+ * @param backend - Backend to execute on
341
+ * @param params - Transfer parameters
342
+ * @returns Transaction result (never throws, returns error in result)
343
+ */
344
+ private async executeOnBackend(
345
+ backend: PrivacyBackend,
346
+ params: TransferParams
347
+ ): Promise<TransactionResult> {
348
+ const startTime = Date.now()
349
+
350
+ try {
351
+ const result = await backend.execute(params)
352
+ const latency = Date.now() - startTime
353
+
354
+ if (result.success) {
355
+ this.registry.recordSuccess(backend.name, latency)
356
+ } else {
357
+ this.registry.recordFailure(backend.name, result.error || 'Execution returned failure')
358
+ }
359
+
360
+ return result
361
+ } catch (error) {
362
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
363
+ this.registry.recordFailure(backend.name, errorMessage)
364
+
365
+ return {
366
+ success: false,
367
+ error: errorMessage,
368
+ backend: backend.name,
369
+ }
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Execute a computation using the best available compute backend
375
+ *
376
+ * Selects from compute-type backends (Arcium, Inco) and executes
377
+ * the computation via MPC/FHE.
378
+ *
379
+ * @param params - Computation parameters
380
+ * @param config - Router configuration
381
+ * @returns Computation result
382
+ * @throws Error if no compute backend is available or supports the computation
383
+ *
384
+ * @example
385
+ * ```typescript
386
+ * const result = await router.executeComputation({
387
+ * chain: 'solana',
388
+ * circuitId: 'private-swap',
389
+ * encryptedInputs: [encryptedAmount, encryptedPrice],
390
+ * })
391
+ * ```
392
+ */
393
+ async executeComputation(
394
+ params: ComputationParams,
395
+ config: Partial<SmartRouterConfig> = {}
396
+ ): Promise<ComputationResult> {
397
+ const selection = await this.selectComputeBackend(params, config)
398
+
399
+ if (!selection.backend.executeComputation) {
400
+ throw new Error(
401
+ `Backend '${selection.backend.name}' does not support compute operations. ` +
402
+ `This should not happen - please report this bug.`
403
+ )
404
+ }
405
+
406
+ return selection.backend.executeComputation(params)
407
+ }
408
+
409
+ /**
410
+ * Select the best compute backend for a computation
411
+ *
412
+ * @param params - Computation parameters
413
+ * @param config - Router configuration
414
+ * @returns Selection result with backend and reasoning
415
+ * @throws Error if no suitable compute backend is found
416
+ */
417
+ async selectComputeBackend(
418
+ params: ComputationParams,
419
+ config: Partial<SmartRouterConfig> = {}
420
+ ): Promise<BackendSelectionResult> {
421
+ const fullConfig = { ...DEFAULT_CONFIG, ...config }
422
+
423
+ // Get all backends for the chain
424
+ const chainBackends = this.registry.getByChain(params.chain)
425
+
426
+ // Filter to compute backends only
427
+ const computeBackends = chainBackends.filter(
428
+ b => b.type === 'compute' || b.type === 'both'
429
+ )
430
+
431
+ if (computeBackends.length === 0) {
432
+ throw new Error(
433
+ `No compute backends available for chain '${params.chain}'. ` +
434
+ `Register a compute backend (e.g., ArciumBackend) that supports this chain.`
435
+ )
436
+ }
437
+
438
+ // Filter and score backends
439
+ const scoredBackends: Array<{
440
+ backend: PrivacyBackend
441
+ availability: AvailabilityResult
442
+ score: number
443
+ reason: string
444
+ }> = []
445
+
446
+ for (const backend of computeBackends) {
447
+ // Check exclusions
448
+ if (fullConfig.excludeBackends?.includes(backend.name)) {
449
+ continue
450
+ }
451
+
452
+ // Check availability
453
+ const availability = await backend.checkAvailability(params)
454
+ if (!availability.available) {
455
+ continue
456
+ }
457
+
458
+ // Check cost limit
459
+ if (fullConfig.maxCost && availability.estimatedCost) {
460
+ if (availability.estimatedCost > fullConfig.maxCost) {
461
+ continue
462
+ }
463
+ }
464
+
465
+ // Check latency limit
466
+ if (fullConfig.maxLatency && availability.estimatedTime) {
467
+ if (availability.estimatedTime > fullConfig.maxLatency) {
468
+ continue
469
+ }
470
+ }
471
+
472
+ // Score this backend
473
+ const { score, reason } = this.scoreBackend(
474
+ backend,
475
+ availability,
476
+ fullConfig
477
+ )
478
+
479
+ scoredBackends.push({
480
+ backend,
481
+ availability,
482
+ score,
483
+ reason,
484
+ })
485
+ }
486
+
487
+ if (scoredBackends.length === 0) {
488
+ throw new Error(
489
+ `No compute backends meet the requirements for this computation. ` +
490
+ `Check that the circuit exists and the cluster is available.`
491
+ )
492
+ }
493
+
494
+ // Sort by score (descending)
495
+ scoredBackends.sort((a, b) => b.score - a.score)
496
+
497
+ // Preferred backend bonus
498
+ if (fullConfig.preferredBackend) {
499
+ const preferredIndex = scoredBackends.findIndex(
500
+ s => s.backend.name === fullConfig.preferredBackend
501
+ )
502
+ if (preferredIndex > 0) {
503
+ const preferred = scoredBackends[preferredIndex]
504
+ const leader = scoredBackends[0]
505
+ if (leader.score - preferred.score <= 10) {
506
+ scoredBackends.splice(preferredIndex, 1)
507
+ scoredBackends.unshift(preferred)
508
+ preferred.reason = `Preferred backend (within 10pts of optimal)`
509
+ }
510
+ }
511
+ }
512
+
513
+ const selected = scoredBackends[0]
514
+ const alternatives = scoredBackends.slice(1).map(s => ({
515
+ backend: s.backend,
516
+ score: s.score,
517
+ reason: s.reason,
518
+ }))
519
+
520
+ return {
521
+ backend: selected.backend,
522
+ reason: selected.reason,
523
+ alternatives,
524
+ score: selected.score,
525
+ }
526
+ }
527
+
528
+ /**
529
+ * Get available backends for a transfer (without selecting)
530
+ *
531
+ * @param params - Transfer parameters
532
+ * @returns Array of available backends with scores
533
+ */
534
+ async getAvailableBackends(
535
+ params: TransferParams
536
+ ): Promise<Array<{ backend: PrivacyBackend; availability: AvailabilityResult }>> {
537
+ return this.registry.findAvailable(params)
538
+ }
539
+
540
+ /**
541
+ * Score a backend based on configuration priority
542
+ */
543
+ private scoreBackend(
544
+ backend: PrivacyBackend,
545
+ availability: AvailabilityResult,
546
+ config: SmartRouterConfig
547
+ ): { score: number; reason: string } {
548
+ const capabilities = backend.getCapabilities()
549
+ let score = 0
550
+ const reasons: string[] = []
551
+
552
+ switch (config.prioritize) {
553
+ case 'privacy':
554
+ if (capabilities.hiddenAmount) {
555
+ score += PRIORITY_WEIGHTS.privacy.hiddenAmount
556
+ reasons.push('hidden amounts')
557
+ }
558
+ if (capabilities.hiddenSender) {
559
+ score += PRIORITY_WEIGHTS.privacy.hiddenSender
560
+ reasons.push('hidden sender')
561
+ }
562
+ if (capabilities.hiddenRecipient) {
563
+ score += PRIORITY_WEIGHTS.privacy.hiddenRecipient
564
+ reasons.push('hidden recipient')
565
+ }
566
+ if (capabilities.hiddenCompute) {
567
+ score += PRIORITY_WEIGHTS.privacy.hiddenCompute
568
+ reasons.push('private compute')
569
+ }
570
+ if (capabilities.anonymitySet && capabilities.anonymitySet >= 100) {
571
+ score += PRIORITY_WEIGHTS.privacy.anonymitySet
572
+ reasons.push(`anonymity set: ${capabilities.anonymitySet}`)
573
+ }
574
+ break
575
+
576
+ case 'speed':
577
+ score += PRIORITY_WEIGHTS.speed[capabilities.latencyEstimate]
578
+ reasons.push(`${capabilities.latencyEstimate} latency`)
579
+ if (capabilities.setupRequired) {
580
+ score += PRIORITY_WEIGHTS.speed.setupRequired
581
+ reasons.push('setup required')
582
+ }
583
+ break
584
+
585
+ case 'cost':
586
+ // Lower cost = higher score (invert with log scale)
587
+ if (availability.estimatedCost !== undefined) {
588
+ // Use log scale to handle wide range of costs
589
+ // log10(100) ≈ 2, log10(100000) ≈ 5, log10(1000000) ≈ 6
590
+ const logCost = availability.estimatedCost > BigInt(0)
591
+ ? Math.log10(Number(availability.estimatedCost))
592
+ : 0
593
+ // Max cost assumed around 10^14 (log = 14), gives score 0
594
+ // Min cost around 10^2 (log = 2), gives score ~60
595
+ const costScore = Math.max(0, 70 - logCost * 5)
596
+ score += costScore
597
+ reasons.push(`low cost`)
598
+ }
599
+ break
600
+
601
+ case 'compliance':
602
+ if (capabilities.complianceSupport) {
603
+ score += PRIORITY_WEIGHTS.compliance.complianceSupport
604
+ reasons.push('viewing key support')
605
+ }
606
+ if (capabilities.hiddenAmount) {
607
+ score += PRIORITY_WEIGHTS.compliance.hiddenAmount
608
+ }
609
+ if (capabilities.hiddenSender) {
610
+ score += PRIORITY_WEIGHTS.compliance.hiddenSender
611
+ }
612
+ if (capabilities.hiddenRecipient) {
613
+ score += PRIORITY_WEIGHTS.compliance.hiddenRecipient
614
+ }
615
+ break
616
+ }
617
+
618
+ // Normalize score to 0-100
619
+ score = Math.min(100, Math.max(0, score))
620
+
621
+ return {
622
+ score,
623
+ reason: reasons.length > 0 ? reasons.join(', ') : 'default selection',
624
+ }
625
+ }
626
+ }