sol-trade-sdk 0.1.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 (87) hide show
  1. package/README.md +390 -0
  2. package/dist/chunk-MMQAMIKR.mjs +3735 -0
  3. package/dist/chunk-NEZDFAYA.mjs +7744 -0
  4. package/dist/clients-VITWK7B6.mjs +1370 -0
  5. package/dist/index-1BK_FXsW.d.mts +2327 -0
  6. package/dist/index-1BK_FXsW.d.ts +2327 -0
  7. package/dist/index.d.mts +2659 -0
  8. package/dist/index.d.ts +2659 -0
  9. package/dist/index.js +13265 -0
  10. package/dist/index.mjs +562 -0
  11. package/dist/perf/index.d.mts +2 -0
  12. package/dist/perf/index.d.ts +2 -0
  13. package/dist/perf/index.js +3742 -0
  14. package/dist/perf/index.mjs +214 -0
  15. package/package.json +101 -0
  16. package/src/__tests__/complete_sdk.test.ts +354 -0
  17. package/src/__tests__/hotpath.test.ts +486 -0
  18. package/src/__tests__/nonce.test.ts +45 -0
  19. package/src/__tests__/sdk.test.ts +425 -0
  20. package/src/address-lookup/index.ts +197 -0
  21. package/src/cache/cache.ts +308 -0
  22. package/src/calc/index.ts +1058 -0
  23. package/src/calc/pumpfun.ts +124 -0
  24. package/src/common/bonding_curve.ts +272 -0
  25. package/src/common/compute-budget.ts +148 -0
  26. package/src/common/confirm-any-signature.ts +184 -0
  27. package/src/common/fast-timing.ts +481 -0
  28. package/src/common/fast_fn.ts +150 -0
  29. package/src/common/gas-fee-strategy.ts +253 -0
  30. package/src/common/map-pool.ts +23 -0
  31. package/src/common/nonce.ts +40 -0
  32. package/src/common/sdk-log.ts +460 -0
  33. package/src/common/seed.ts +381 -0
  34. package/src/common/spl-token.ts +578 -0
  35. package/src/common/subscription-handle.ts +644 -0
  36. package/src/common/trading-utils.ts +239 -0
  37. package/src/common/wsol-manager.ts +325 -0
  38. package/src/compute/compute_budget_manager.ts +187 -0
  39. package/src/compute/index.ts +21 -0
  40. package/src/constants/index.ts +96 -0
  41. package/src/execution/execution.ts +532 -0
  42. package/src/execution/index.ts +42 -0
  43. package/src/hotpath/executor.ts +464 -0
  44. package/src/hotpath/index.ts +64 -0
  45. package/src/hotpath/state.ts +435 -0
  46. package/src/index.ts +2117 -0
  47. package/src/instruction/bonk_builder.ts +730 -0
  48. package/src/instruction/index.ts +24 -0
  49. package/src/instruction/meteora_damm_v2_builder.ts +509 -0
  50. package/src/instruction/pumpfun_builder.ts +1183 -0
  51. package/src/instruction/pumpswap.ts +1123 -0
  52. package/src/instruction/raydium_amm_v4_builder.ts +692 -0
  53. package/src/instruction/raydium_cpmm_builder.ts +795 -0
  54. package/src/middleware/traits.ts +407 -0
  55. package/src/params/index.ts +483 -0
  56. package/src/perf/compiler-optimization.ts +529 -0
  57. package/src/perf/hardware.ts +631 -0
  58. package/src/perf/index.ts +9 -0
  59. package/src/perf/kernel-bypass.ts +656 -0
  60. package/src/perf/protocol.ts +682 -0
  61. package/src/perf/realtime.ts +592 -0
  62. package/src/perf/simd.ts +668 -0
  63. package/src/perf/syscall-bypass.ts +331 -0
  64. package/src/perf/ultra-low-latency.ts +505 -0
  65. package/src/perf/zero-copy.ts +589 -0
  66. package/src/pool/pool.ts +294 -0
  67. package/src/rpc/client.ts +345 -0
  68. package/src/sdk-errors.ts +13 -0
  69. package/src/security/index.ts +26 -0
  70. package/src/security/secure-key.ts +303 -0
  71. package/src/security/validators.ts +281 -0
  72. package/src/seed/pda.ts +262 -0
  73. package/src/serialization/index.ts +28 -0
  74. package/src/serialization/serialization.ts +288 -0
  75. package/src/swqos/clients.ts +1754 -0
  76. package/src/swqos/index.ts +50 -0
  77. package/src/swqos/providers.ts +1707 -0
  78. package/src/trading/core/async-executor.ts +702 -0
  79. package/src/trading/core/confirmation-monitor.ts +711 -0
  80. package/src/trading/core/index.ts +82 -0
  81. package/src/trading/core/retry-handler.ts +683 -0
  82. package/src/trading/core/transaction-pool.ts +780 -0
  83. package/src/trading/executor.ts +385 -0
  84. package/src/trading/factory.ts +282 -0
  85. package/src/trading/index.ts +30 -0
  86. package/src/types.ts +8 -0
  87. package/src/utils/index.ts +155 -0
@@ -0,0 +1,1707 @@
1
+ /**
2
+ * SWQOS Providers for Sol Trade SDK
3
+ * Implements all 19 SWQOS (Solana Write Queue Operating System) providers.
4
+ * Based on the Rust/Python SDK implementations.
5
+ */
6
+
7
+ import { TradeError } from '../index';
8
+
9
+ // ===== Enums =====
10
+
11
+ /**
12
+ * SWQOS service provider types
13
+ */
14
+ export enum SwqosType {
15
+ Jito = 'Jito',
16
+ NextBlock = 'NextBlock',
17
+ ZeroSlot = 'ZeroSlot',
18
+ Temporal = 'Temporal',
19
+ Bloxroute = 'Bloxroute',
20
+ Node1 = 'Node1',
21
+ FlashBlock = 'FlashBlock',
22
+ BlockRazor = 'BlockRazor',
23
+ Astralane = 'Astralane',
24
+ Stellium = 'Stellium',
25
+ Lightspeed = 'Lightspeed',
26
+ Soyas = 'Soyas',
27
+ Speedlanding = 'Speedlanding',
28
+ Helius = 'Helius',
29
+ Triton = 'Triton',
30
+ QuickNode = 'QuickNode',
31
+ Syndica = 'Syndica',
32
+ Figment = 'Figment',
33
+ Alchemy = 'Alchemy',
34
+ Default = 'Default',
35
+ }
36
+
37
+ /**
38
+ * SWQOS service regions
39
+ */
40
+ export enum SwqosRegion {
41
+ NewYork = 'NewYork',
42
+ Frankfurt = 'Frankfurt',
43
+ Amsterdam = 'Amsterdam',
44
+ SLC = 'SLC',
45
+ Tokyo = 'Tokyo',
46
+ London = 'London',
47
+ LosAngeles = 'LosAngeles',
48
+ Singapore = 'Singapore',
49
+ Default = 'Default',
50
+ }
51
+
52
+ /**
53
+ * MEV protection levels
54
+ */
55
+ export enum MevProtectionLevel {
56
+ None = 'none',
57
+ Basic = 'basic',
58
+ Enhanced = 'enhanced',
59
+ Maximum = 'maximum',
60
+ }
61
+
62
+ // ===== Types =====
63
+
64
+ /**
65
+ * Transaction submission result
66
+ */
67
+ export interface TransactionResult {
68
+ success: boolean;
69
+ signature?: string;
70
+ provider: string;
71
+ latencyMs: number;
72
+ slot?: number;
73
+ error?: string;
74
+ bundleId?: string;
75
+ confirmationStatus?: string;
76
+ }
77
+
78
+ /**
79
+ * SWQOS configuration
80
+ */
81
+ export interface SwqosConfig {
82
+ swqosType: SwqosType;
83
+ apiKey?: string;
84
+ region?: SwqosRegion;
85
+ url?: string;
86
+ timeoutMs?: number;
87
+ maxRetries?: number;
88
+ enabled?: boolean;
89
+ priorityFeeMultiplier?: number;
90
+ mevProtection?: MevProtectionLevel;
91
+ customHeaders?: Record<string, string>;
92
+ rateLimitRps?: number;
93
+ }
94
+
95
+ /**
96
+ * Client statistics
97
+ */
98
+ export interface ClientStats {
99
+ requests: number;
100
+ successes: number;
101
+ failures: number;
102
+ avgLatencyMs: number;
103
+ lastError?: string;
104
+ }
105
+
106
+ // ===== Base Client =====
107
+
108
+ /**
109
+ * Base SWQOS client class
110
+ */
111
+ export abstract class SwqosClient {
112
+ protected _stats: ClientStats = {
113
+ requests: 0,
114
+ successes: 0,
115
+ failures: 0,
116
+ avgLatencyMs: 0,
117
+ };
118
+ protected _lastRequestTime = 0;
119
+ protected _rateLimitDelay: number;
120
+
121
+ constructor(public readonly config: SwqosConfig) {
122
+ const rateLimitRps = config.rateLimitRps ?? 100;
123
+ this._rateLimitDelay = rateLimitRps > 0 ? 1000 / rateLimitRps : 0;
124
+ }
125
+
126
+ /**
127
+ * Submit transaction to SWQOS provider
128
+ */
129
+ abstract submitTransaction(transaction: Buffer, tip?: number): Promise<TransactionResult>;
130
+
131
+ /**
132
+ * Submit transaction bundle
133
+ */
134
+ async submitBundle(transactions: Buffer[], tip?: number): Promise<TransactionResult> {
135
+ // Default: submit first transaction only
136
+ if (transactions.length > 0) {
137
+ return this.submitTransaction(transactions[0]!, tip);
138
+ }
139
+ return {
140
+ success: false,
141
+ provider: this.config.swqosType,
142
+ latencyMs: 0,
143
+ error: 'Empty bundle',
144
+ };
145
+ }
146
+
147
+ /**
148
+ * Get recommended tip amount in lamports
149
+ */
150
+ async getTipRecommendation(): Promise<number> {
151
+ return 10000; // Default 0.00001 SOL
152
+ }
153
+
154
+ /**
155
+ * Get client statistics
156
+ */
157
+ getStats(): ClientStats {
158
+ return { ...this._stats };
159
+ }
160
+
161
+ /**
162
+ * Update client statistics
163
+ */
164
+ protected updateStats(success: boolean, latencyMs: number, error?: string): void {
165
+ this._stats.requests++;
166
+ if (success) {
167
+ this._stats.successes++;
168
+ } else {
169
+ this._stats.failures++;
170
+ this._stats.lastError = error;
171
+ }
172
+
173
+ // Update average latency
174
+ const n = this._stats.requests;
175
+ this._stats.avgLatencyMs = Math.floor(
176
+ (this._stats.avgLatencyMs * (n - 1) + latencyMs) / n
177
+ );
178
+ }
179
+
180
+ /**
181
+ * Check and enforce rate limiting
182
+ */
183
+ protected async rateLimitCheck(): Promise<void> {
184
+ if (this._rateLimitDelay <= 0) {
185
+ return;
186
+ }
187
+
188
+ const elapsed = Date.now() - this._lastRequestTime;
189
+ if (elapsed < this._rateLimitDelay) {
190
+ await this.sleep(this._rateLimitDelay - elapsed);
191
+ }
192
+
193
+ this._lastRequestTime = Date.now();
194
+ }
195
+
196
+ /**
197
+ * Sleep helper
198
+ */
199
+ protected sleep(ms: number): Promise<void> {
200
+ return new Promise(resolve => setTimeout(resolve, ms));
201
+ }
202
+
203
+ /**
204
+ * Make HTTP POST request
205
+ */
206
+ protected async post(url: string, payload: unknown, headers: Record<string, string> = {}): Promise<unknown> {
207
+ const response = await fetch(url, {
208
+ method: 'POST',
209
+ headers: {
210
+ 'Content-Type': 'application/json',
211
+ ...headers,
212
+ },
213
+ body: JSON.stringify(payload),
214
+ });
215
+
216
+ if (!response.ok) {
217
+ throw new TradeError(response.status, `HTTP error: ${response.statusText}`);
218
+ }
219
+
220
+ return response.json();
221
+ }
222
+
223
+ /**
224
+ * Get provider type
225
+ */
226
+ abstract getProviderType(): SwqosType;
227
+
228
+ /**
229
+ * Check if provider is enabled
230
+ */
231
+ isEnabled(): boolean {
232
+ return this.config.enabled ?? true;
233
+ }
234
+ }
235
+
236
+ // ===== Provider Implementations =====
237
+
238
+ /**
239
+ * Jito SWQOS client - MEV protection and bundle submission
240
+ */
241
+ export class JitoClient extends SwqosClient {
242
+ private bundleUrl: string;
243
+ private authToken?: string;
244
+
245
+ private static readonly DEFAULT_ENDPOINTS: Record<SwqosRegion, string> = {
246
+ [SwqosRegion.NewYork]: 'https://mainnet.block-engine.jito.wtf',
247
+ [SwqosRegion.Frankfurt]: 'https://frankfurt.mainnet.block-engine.jito.wtf',
248
+ [SwqosRegion.Amsterdam]: 'https://amsterdam.mainnet.block-engine.jito.wtf',
249
+ [SwqosRegion.Tokyo]: 'https://tokyo.mainnet.block-engine.jito.wtf',
250
+ [SwqosRegion.SLC]: 'https://slc.mainnet.block-engine.jito.wtf',
251
+ [SwqosRegion.London]: 'https://mainnet.block-engine.jito.wtf',
252
+ [SwqosRegion.LosAngeles]: 'https://mainnet.block-engine.jito.wtf',
253
+ [SwqosRegion.Singapore]: 'https://mainnet.block-engine.jito.wtf',
254
+ [SwqosRegion.Default]: 'https://mainnet.block-engine.jito.wtf',
255
+ };
256
+
257
+ constructor(config: SwqosConfig) {
258
+ super(config);
259
+ this.bundleUrl = config.url || this.getEndpointForRegion(config.region || SwqosRegion.Default);
260
+ this.authToken = config.apiKey;
261
+ }
262
+
263
+ private getEndpointForRegion(region: SwqosRegion): string {
264
+ return JitoClient.DEFAULT_ENDPOINTS[region] || JitoClient.DEFAULT_ENDPOINTS[SwqosRegion.Default];
265
+ }
266
+
267
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
268
+ await this.rateLimitCheck();
269
+ const startTime = Date.now();
270
+
271
+ try {
272
+ const encoded = transaction.toString('base64');
273
+ const payload = {
274
+ jsonrpc: '2.0',
275
+ id: 1,
276
+ method: 'sendTransaction',
277
+ params: [encoded, { encoding: 'base64' }],
278
+ };
279
+
280
+ const headers: Record<string, string> = {};
281
+ if (this.authToken) {
282
+ headers['X-Jito-Auth-Token'] = this.authToken;
283
+ }
284
+
285
+ const result = (await this.post(`${this.bundleUrl}/api/v1/bundles`, payload, headers)) as any;
286
+
287
+ if (result.error) {
288
+ throw new TradeError(result.error.code || 500, result.error.message);
289
+ }
290
+
291
+ const latencyMs = Date.now() - startTime;
292
+ this.updateStats(true, latencyMs);
293
+
294
+ return {
295
+ success: true,
296
+ signature: result.result,
297
+ provider: 'Jito',
298
+ latencyMs,
299
+ bundleId: `bundle_${Date.now()}`,
300
+ };
301
+ } catch (error) {
302
+ const latencyMs = Date.now() - startTime;
303
+ const errorMsg = error instanceof Error ? error.message : String(error);
304
+ this.updateStats(false, latencyMs, errorMsg);
305
+
306
+ return {
307
+ success: false,
308
+ provider: 'Jito',
309
+ latencyMs,
310
+ error: errorMsg,
311
+ };
312
+ }
313
+ }
314
+
315
+ async submitBundle(transactions: Buffer[], tip = 0): Promise<TransactionResult> {
316
+ await this.rateLimitCheck();
317
+ const startTime = Date.now();
318
+
319
+ try {
320
+ const encodedTxs = transactions.map(tx => tx.toString('base64'));
321
+ const payload = {
322
+ jsonrpc: '2.0',
323
+ id: 1,
324
+ method: 'sendBundle',
325
+ params: [encodedTxs],
326
+ };
327
+
328
+ const headers: Record<string, string> = {};
329
+ if (this.authToken) {
330
+ headers['X-Jito-Auth-Token'] = this.authToken;
331
+ }
332
+
333
+ const result = (await this.post(`${this.bundleUrl}/api/v1/bundles`, payload, headers)) as any;
334
+
335
+ const latencyMs = Date.now() - startTime;
336
+ this.updateStats(true, latencyMs);
337
+
338
+ return {
339
+ success: true,
340
+ signature: result.result,
341
+ provider: 'Jito',
342
+ latencyMs,
343
+ bundleId: `bundle_${Date.now()}`,
344
+ };
345
+ } catch (error) {
346
+ const latencyMs = Date.now() - startTime;
347
+ const errorMsg = error instanceof Error ? error.message : String(error);
348
+ this.updateStats(false, latencyMs, errorMsg);
349
+
350
+ return {
351
+ success: false,
352
+ provider: 'Jito',
353
+ latencyMs,
354
+ error: errorMsg,
355
+ };
356
+ }
357
+ }
358
+
359
+ async getTipRecommendation(): Promise<number> {
360
+ // Jito typically recommends 10000-100000 lamports
361
+ return 50000;
362
+ }
363
+
364
+ getProviderType(): SwqosType {
365
+ return SwqosType.Jito;
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Bloxroute SWQOS client - High-speed transaction relay
371
+ */
372
+ export class BloxrouteClient extends SwqosClient {
373
+ private gatewayUrl: string;
374
+ private wsUrl: string;
375
+
376
+ private static readonly DEFAULT_ENDPOINTS: Record<SwqosRegion, string> = {
377
+ [SwqosRegion.NewYork]: 'https://solana.dex.blxrbdn.com',
378
+ [SwqosRegion.Frankfurt]: 'https://solana.dex.blxrbdn.com',
379
+ [SwqosRegion.Amsterdam]: 'https://solana.dex.blxrbdn.com',
380
+ [SwqosRegion.Tokyo]: 'https://solana.dex.blxrbdn.com',
381
+ [SwqosRegion.SLC]: 'https://solana.dex.blxrbdn.com',
382
+ [SwqosRegion.London]: 'https://solana.dex.blxrbdn.com',
383
+ [SwqosRegion.LosAngeles]: 'https://solana.dex.blxrbdn.com',
384
+ [SwqosRegion.Singapore]: 'https://solana.dex.blxrbdn.com',
385
+ [SwqosRegion.Default]: 'https://solana.dex.blxrbdn.com',
386
+ };
387
+
388
+ constructor(config: SwqosConfig) {
389
+ super(config);
390
+ this.gatewayUrl = config.url || BloxrouteClient.DEFAULT_ENDPOINTS[config.region || SwqosRegion.Default];
391
+ this.wsUrl = this.gatewayUrl.replace('https://', 'wss://');
392
+ }
393
+
394
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
395
+ await this.rateLimitCheck();
396
+ const startTime = Date.now();
397
+
398
+ try {
399
+ const encoded = transaction.toString('base64');
400
+ const payload = {
401
+ jsonrpc: '2.0',
402
+ id: 1,
403
+ method: 'sendTransaction',
404
+ params: [encoded],
405
+ };
406
+
407
+ const headers: Record<string, string> = {};
408
+ if (this.config.apiKey) {
409
+ headers['Authorization'] = this.config.apiKey;
410
+ }
411
+
412
+ const result = (await this.post(`${this.gatewayUrl}/api/v2/submit`, payload, headers)) as any;
413
+
414
+ if (result.reason) {
415
+ throw new TradeError(500, result.reason);
416
+ }
417
+
418
+ const latencyMs = Date.now() - startTime;
419
+ this.updateStats(true, latencyMs);
420
+
421
+ return {
422
+ success: true,
423
+ signature: result.signature,
424
+ provider: 'Bloxroute',
425
+ latencyMs,
426
+ };
427
+ } catch (error) {
428
+ const latencyMs = Date.now() - startTime;
429
+ const errorMsg = error instanceof Error ? error.message : String(error);
430
+ this.updateStats(false, latencyMs, errorMsg);
431
+
432
+ return {
433
+ success: false,
434
+ provider: 'Bloxroute',
435
+ latencyMs,
436
+ error: errorMsg,
437
+ };
438
+ }
439
+ }
440
+
441
+ getProviderType(): SwqosType {
442
+ return SwqosType.Bloxroute;
443
+ }
444
+ }
445
+
446
+ /**
447
+ * ZeroSlot SWQOS client - Zero-slot latency
448
+ */
449
+ export class ZeroSlotClient extends SwqosClient {
450
+ private apiUrl: string;
451
+
452
+ constructor(config: SwqosConfig) {
453
+ super(config);
454
+ this.apiUrl = config.url || 'https://api.zeroslot.io';
455
+ }
456
+
457
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
458
+ await this.rateLimitCheck();
459
+ const startTime = Date.now();
460
+
461
+ try {
462
+ const encoded = transaction.toString('base64');
463
+ const payload = { transaction: encoded, tip };
464
+
465
+ const headers: Record<string, string> = {};
466
+ if (this.config.apiKey) {
467
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
468
+ }
469
+
470
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
471
+
472
+ if (result.error) {
473
+ throw new TradeError(500, result.error);
474
+ }
475
+
476
+ const latencyMs = Date.now() - startTime;
477
+ this.updateStats(true, latencyMs);
478
+
479
+ return {
480
+ success: true,
481
+ signature: result.signature,
482
+ provider: 'ZeroSlot',
483
+ latencyMs,
484
+ slot: result.slot,
485
+ };
486
+ } catch (error) {
487
+ const latencyMs = Date.now() - startTime;
488
+ const errorMsg = error instanceof Error ? error.message : String(error);
489
+ this.updateStats(false, latencyMs, errorMsg);
490
+
491
+ return {
492
+ success: false,
493
+ provider: 'ZeroSlot',
494
+ latencyMs,
495
+ error: errorMsg,
496
+ };
497
+ }
498
+ }
499
+
500
+ getProviderType(): SwqosType {
501
+ return SwqosType.ZeroSlot;
502
+ }
503
+ }
504
+
505
+ /**
506
+ * NextBlock SWQOS client - Next block inclusion guarantee
507
+ */
508
+ export class NextBlockClient extends SwqosClient {
509
+ private apiUrl: string;
510
+
511
+ constructor(config: SwqosConfig) {
512
+ super(config);
513
+ this.apiUrl = config.url || 'https://api.nextblock.io';
514
+ }
515
+
516
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
517
+ await this.rateLimitCheck();
518
+ const startTime = Date.now();
519
+
520
+ try {
521
+ const encoded = transaction.toString('base64');
522
+ const payload = { transaction: encoded, tip };
523
+
524
+ const headers: Record<string, string> = {};
525
+ if (this.config.apiKey) {
526
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
527
+ }
528
+
529
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
530
+
531
+ const latencyMs = Date.now() - startTime;
532
+ this.updateStats(true, latencyMs);
533
+
534
+ return {
535
+ success: true,
536
+ signature: result.signature,
537
+ provider: 'NextBlock',
538
+ latencyMs,
539
+ };
540
+ } catch (error) {
541
+ const latencyMs = Date.now() - startTime;
542
+ const errorMsg = error instanceof Error ? error.message : String(error);
543
+ this.updateStats(false, latencyMs, errorMsg);
544
+
545
+ return {
546
+ success: false,
547
+ provider: 'NextBlock',
548
+ latencyMs,
549
+ error: errorMsg,
550
+ };
551
+ }
552
+ }
553
+
554
+ getProviderType(): SwqosType {
555
+ return SwqosType.NextBlock;
556
+ }
557
+ }
558
+
559
+ /**
560
+ * Temporal SWQOS client - Time-based execution
561
+ */
562
+ export class TemporalClient extends SwqosClient {
563
+ private apiUrl: string;
564
+
565
+ constructor(config: SwqosConfig) {
566
+ super(config);
567
+ this.apiUrl = config.url || 'https://api.temporal.trade';
568
+ }
569
+
570
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
571
+ await this.rateLimitCheck();
572
+ const startTime = Date.now();
573
+
574
+ try {
575
+ const encoded = transaction.toString('base64');
576
+ const payload = { transaction: encoded, tip };
577
+
578
+ const headers: Record<string, string> = {};
579
+ if (this.config.apiKey) {
580
+ headers['Authorization'] = this.config.apiKey;
581
+ }
582
+
583
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
584
+
585
+ if (result.error) {
586
+ throw new TradeError(500, result.error);
587
+ }
588
+
589
+ const latencyMs = Date.now() - startTime;
590
+ this.updateStats(true, latencyMs);
591
+
592
+ return {
593
+ success: true,
594
+ signature: result.signature,
595
+ provider: 'Temporal',
596
+ latencyMs,
597
+ };
598
+ } catch (error) {
599
+ const latencyMs = Date.now() - startTime;
600
+ const errorMsg = error instanceof Error ? error.message : String(error);
601
+ this.updateStats(false, latencyMs, errorMsg);
602
+
603
+ return {
604
+ success: false,
605
+ provider: 'Temporal',
606
+ latencyMs,
607
+ error: errorMsg,
608
+ };
609
+ }
610
+ }
611
+
612
+ getProviderType(): SwqosType {
613
+ return SwqosType.Temporal;
614
+ }
615
+ }
616
+
617
+ /**
618
+ * Node1 SWQOS client - Premium node access
619
+ */
620
+ export class Node1Client extends SwqosClient {
621
+ private apiUrl: string;
622
+
623
+ constructor(config: SwqosConfig) {
624
+ super(config);
625
+ this.apiUrl = config.url || 'https://api.node1.io';
626
+ }
627
+
628
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
629
+ await this.rateLimitCheck();
630
+ const startTime = Date.now();
631
+
632
+ try {
633
+ const encoded = transaction.toString('base64');
634
+ const payload = { transaction: encoded, tip };
635
+
636
+ const headers: Record<string, string> = {};
637
+ if (this.config.apiKey) {
638
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
639
+ }
640
+
641
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
642
+
643
+ if (result.error) {
644
+ throw new TradeError(500, result.error);
645
+ }
646
+
647
+ const latencyMs = Date.now() - startTime;
648
+ this.updateStats(true, latencyMs);
649
+
650
+ return {
651
+ success: true,
652
+ signature: result.signature,
653
+ provider: 'Node1',
654
+ latencyMs,
655
+ };
656
+ } catch (error) {
657
+ const latencyMs = Date.now() - startTime;
658
+ const errorMsg = error instanceof Error ? error.message : String(error);
659
+ this.updateStats(false, latencyMs, errorMsg);
660
+
661
+ return {
662
+ success: false,
663
+ provider: 'Node1',
664
+ latencyMs,
665
+ error: errorMsg,
666
+ };
667
+ }
668
+ }
669
+
670
+ getProviderType(): SwqosType {
671
+ return SwqosType.Node1;
672
+ }
673
+ }
674
+
675
+ /**
676
+ * FlashBlock SWQOS client - Flash block inclusion
677
+ */
678
+ export class FlashBlockClient extends SwqosClient {
679
+ private apiUrl: string;
680
+
681
+ constructor(config: SwqosConfig) {
682
+ super(config);
683
+ this.apiUrl = config.url || 'https://api.flashblock.io';
684
+ }
685
+
686
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
687
+ await this.rateLimitCheck();
688
+ const startTime = Date.now();
689
+
690
+ try {
691
+ const encoded = transaction.toString('base64');
692
+ const payload = { transaction: encoded, tip };
693
+
694
+ const headers: Record<string, string> = {};
695
+ if (this.config.apiKey) {
696
+ headers['X-API-Key'] = this.config.apiKey;
697
+ }
698
+
699
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
700
+
701
+ if (result.error) {
702
+ throw new TradeError(500, result.error);
703
+ }
704
+
705
+ const latencyMs = Date.now() - startTime;
706
+ this.updateStats(true, latencyMs);
707
+
708
+ return {
709
+ success: true,
710
+ signature: result.signature,
711
+ provider: 'FlashBlock',
712
+ latencyMs,
713
+ };
714
+ } catch (error) {
715
+ const latencyMs = Date.now() - startTime;
716
+ const errorMsg = error instanceof Error ? error.message : String(error);
717
+ this.updateStats(false, latencyMs, errorMsg);
718
+
719
+ return {
720
+ success: false,
721
+ provider: 'FlashBlock',
722
+ latencyMs,
723
+ error: errorMsg,
724
+ };
725
+ }
726
+ }
727
+
728
+ getProviderType(): SwqosType {
729
+ return SwqosType.FlashBlock;
730
+ }
731
+ }
732
+
733
+ /**
734
+ * BlockRazor SWQOS client - Block optimization
735
+ */
736
+ export class BlockRazorClient extends SwqosClient {
737
+ private apiUrl: string;
738
+
739
+ constructor(config: SwqosConfig) {
740
+ super(config);
741
+ this.apiUrl = config.url || 'https://api.blockrazor.io';
742
+ }
743
+
744
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
745
+ await this.rateLimitCheck();
746
+ const startTime = Date.now();
747
+
748
+ try {
749
+ const encoded = transaction.toString('base64');
750
+ const payload = { transaction: encoded, tip };
751
+
752
+ const headers: Record<string, string> = {};
753
+ if (this.config.apiKey) {
754
+ headers['X-API-Key'] = this.config.apiKey;
755
+ }
756
+
757
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
758
+
759
+ if (result.error) {
760
+ throw new TradeError(500, result.error);
761
+ }
762
+
763
+ const latencyMs = Date.now() - startTime;
764
+ this.updateStats(true, latencyMs);
765
+
766
+ return {
767
+ success: true,
768
+ signature: result.signature,
769
+ provider: 'BlockRazor',
770
+ latencyMs,
771
+ };
772
+ } catch (error) {
773
+ const latencyMs = Date.now() - startTime;
774
+ const errorMsg = error instanceof Error ? error.message : String(error);
775
+ this.updateStats(false, latencyMs, errorMsg);
776
+
777
+ return {
778
+ success: false,
779
+ provider: 'BlockRazor',
780
+ latencyMs,
781
+ error: errorMsg,
782
+ };
783
+ }
784
+ }
785
+
786
+ getProviderType(): SwqosType {
787
+ return SwqosType.BlockRazor;
788
+ }
789
+ }
790
+
791
+ /**
792
+ * Astralane SWQOS client - High-speed relay
793
+ */
794
+ export class AstralaneClient extends SwqosClient {
795
+ private apiUrl: string;
796
+
797
+ constructor(config: SwqosConfig) {
798
+ super(config);
799
+ this.apiUrl = config.url || 'https://api.astralane.io';
800
+ }
801
+
802
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
803
+ await this.rateLimitCheck();
804
+ const startTime = Date.now();
805
+
806
+ try {
807
+ const encoded = transaction.toString('base64');
808
+ const payload = { transaction: encoded, tip };
809
+
810
+ const headers: Record<string, string> = {};
811
+ if (this.config.apiKey) {
812
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
813
+ }
814
+
815
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
816
+
817
+ if (result.error) {
818
+ throw new TradeError(500, result.error);
819
+ }
820
+
821
+ const latencyMs = Date.now() - startTime;
822
+ this.updateStats(true, latencyMs);
823
+
824
+ return {
825
+ success: true,
826
+ signature: result.signature,
827
+ provider: 'Astralane',
828
+ latencyMs,
829
+ };
830
+ } catch (error) {
831
+ const latencyMs = Date.now() - startTime;
832
+ const errorMsg = error instanceof Error ? error.message : String(error);
833
+ this.updateStats(false, latencyMs, errorMsg);
834
+
835
+ return {
836
+ success: false,
837
+ provider: 'Astralane',
838
+ latencyMs,
839
+ error: errorMsg,
840
+ };
841
+ }
842
+ }
843
+
844
+ getProviderType(): SwqosType {
845
+ return SwqosType.Astralane;
846
+ }
847
+ }
848
+
849
+ /**
850
+ * Stellium SWQOS client - Premium infrastructure
851
+ */
852
+ export class StelliumClient extends SwqosClient {
853
+ private apiUrl: string;
854
+
855
+ constructor(config: SwqosConfig) {
856
+ super(config);
857
+ this.apiUrl = config.url || 'https://api.stellium.io';
858
+ }
859
+
860
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
861
+ await this.rateLimitCheck();
862
+ const startTime = Date.now();
863
+
864
+ try {
865
+ const encoded = transaction.toString('base64');
866
+ const payload = { transaction: encoded, tip };
867
+
868
+ const headers: Record<string, string> = {};
869
+ if (this.config.apiKey) {
870
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
871
+ }
872
+
873
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
874
+
875
+ const latencyMs = Date.now() - startTime;
876
+ this.updateStats(true, latencyMs);
877
+
878
+ return {
879
+ success: true,
880
+ signature: result.signature,
881
+ provider: 'Stellium',
882
+ latencyMs,
883
+ };
884
+ } catch (error) {
885
+ const latencyMs = Date.now() - startTime;
886
+ const errorMsg = error instanceof Error ? error.message : String(error);
887
+ this.updateStats(false, latencyMs, errorMsg);
888
+
889
+ return {
890
+ success: false,
891
+ provider: 'Stellium',
892
+ latencyMs,
893
+ error: errorMsg,
894
+ };
895
+ }
896
+ }
897
+
898
+ getProviderType(): SwqosType {
899
+ return SwqosType.Stellium;
900
+ }
901
+ }
902
+
903
+ /**
904
+ * Lightspeed SWQOS client - Ultra-low latency
905
+ */
906
+ export class LightspeedClient extends SwqosClient {
907
+ private apiUrl: string;
908
+
909
+ constructor(config: SwqosConfig) {
910
+ super(config);
911
+ this.apiUrl = config.url || 'https://api.lightspeed.trade';
912
+ }
913
+
914
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
915
+ await this.rateLimitCheck();
916
+ const startTime = Date.now();
917
+
918
+ try {
919
+ const encoded = transaction.toString('base64');
920
+ const payload = { transaction: encoded, tip };
921
+
922
+ const headers: Record<string, string> = {};
923
+ if (this.config.apiKey) {
924
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
925
+ }
926
+
927
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
928
+
929
+ const latencyMs = Date.now() - startTime;
930
+ this.updateStats(true, latencyMs);
931
+
932
+ return {
933
+ success: true,
934
+ signature: result.signature,
935
+ provider: 'Lightspeed',
936
+ latencyMs,
937
+ };
938
+ } catch (error) {
939
+ const latencyMs = Date.now() - startTime;
940
+ const errorMsg = error instanceof Error ? error.message : String(error);
941
+ this.updateStats(false, latencyMs, errorMsg);
942
+
943
+ return {
944
+ success: false,
945
+ provider: 'Lightspeed',
946
+ latencyMs,
947
+ error: errorMsg,
948
+ };
949
+ }
950
+ }
951
+
952
+ getProviderType(): SwqosType {
953
+ return SwqosType.Lightspeed;
954
+ }
955
+ }
956
+
957
+ /**
958
+ * Soyas SWQOS client - MEV protection
959
+ */
960
+ export class SoyasClient extends SwqosClient {
961
+ private apiUrl: string;
962
+
963
+ constructor(config: SwqosConfig) {
964
+ super(config);
965
+ this.apiUrl = config.url || 'https://api.soyas.io';
966
+ }
967
+
968
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
969
+ await this.rateLimitCheck();
970
+ const startTime = Date.now();
971
+
972
+ try {
973
+ const encoded = transaction.toString('base64');
974
+ const payload = { transaction: encoded, tip };
975
+
976
+ const headers: Record<string, string> = {};
977
+ if (this.config.apiKey) {
978
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
979
+ }
980
+
981
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
982
+
983
+ const latencyMs = Date.now() - startTime;
984
+ this.updateStats(true, latencyMs);
985
+
986
+ return {
987
+ success: true,
988
+ signature: result.signature,
989
+ provider: 'Soyas',
990
+ latencyMs,
991
+ };
992
+ } catch (error) {
993
+ const latencyMs = Date.now() - startTime;
994
+ const errorMsg = error instanceof Error ? error.message : String(error);
995
+ this.updateStats(false, latencyMs, errorMsg);
996
+
997
+ return {
998
+ success: false,
999
+ provider: 'Soyas',
1000
+ latencyMs,
1001
+ error: errorMsg,
1002
+ };
1003
+ }
1004
+ }
1005
+
1006
+ getProviderType(): SwqosType {
1007
+ return SwqosType.Soyas;
1008
+ }
1009
+ }
1010
+
1011
+ /**
1012
+ * Speedlanding SWQOS client - Fast inclusion
1013
+ */
1014
+ export class SpeedlandingClient extends SwqosClient {
1015
+ private apiUrl: string;
1016
+
1017
+ constructor(config: SwqosConfig) {
1018
+ super(config);
1019
+ this.apiUrl = config.url || 'https://api.speedlanding.io';
1020
+ }
1021
+
1022
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1023
+ await this.rateLimitCheck();
1024
+ const startTime = Date.now();
1025
+
1026
+ try {
1027
+ const encoded = transaction.toString('base64');
1028
+ const payload = { transaction: encoded, tip };
1029
+
1030
+ const headers: Record<string, string> = {};
1031
+ if (this.config.apiKey) {
1032
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
1033
+ }
1034
+
1035
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
1036
+
1037
+ const latencyMs = Date.now() - startTime;
1038
+ this.updateStats(true, latencyMs);
1039
+
1040
+ return {
1041
+ success: true,
1042
+ signature: result.signature,
1043
+ provider: 'Speedlanding',
1044
+ latencyMs,
1045
+ };
1046
+ } catch (error) {
1047
+ const latencyMs = Date.now() - startTime;
1048
+ const errorMsg = error instanceof Error ? error.message : String(error);
1049
+ this.updateStats(false, latencyMs, errorMsg);
1050
+
1051
+ return {
1052
+ success: false,
1053
+ provider: 'Speedlanding',
1054
+ latencyMs,
1055
+ error: errorMsg,
1056
+ };
1057
+ }
1058
+ }
1059
+
1060
+ getProviderType(): SwqosType {
1061
+ return SwqosType.Speedlanding;
1062
+ }
1063
+ }
1064
+
1065
+ /**
1066
+ * Helius SWQOS client - Enhanced RPC
1067
+ */
1068
+ export class HeliusClient extends SwqosClient {
1069
+ private apiUrl: string;
1070
+
1071
+ private static readonly DEFAULT_ENDPOINTS: Record<SwqosRegion, string> = {
1072
+ [SwqosRegion.NewYork]: 'https://api.helius-rpc.com',
1073
+ [SwqosRegion.Frankfurt]: 'https://api.helius-rpc.com',
1074
+ [SwqosRegion.Amsterdam]: 'https://api.helius-rpc.com',
1075
+ [SwqosRegion.Tokyo]: 'https://api.helius-rpc.com',
1076
+ [SwqosRegion.SLC]: 'https://api.helius-rpc.com',
1077
+ [SwqosRegion.London]: 'https://api.helius-rpc.com',
1078
+ [SwqosRegion.LosAngeles]: 'https://api.helius-rpc.com',
1079
+ [SwqosRegion.Singapore]: 'https://api.helius-rpc.com',
1080
+ [SwqosRegion.Default]: 'https://api.helius-rpc.com',
1081
+ };
1082
+
1083
+ constructor(config: SwqosConfig) {
1084
+ super(config);
1085
+ this.apiUrl = config.url || HeliusClient.DEFAULT_ENDPOINTS[config.region || SwqosRegion.Default];
1086
+ }
1087
+
1088
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1089
+ await this.rateLimitCheck();
1090
+ const startTime = Date.now();
1091
+
1092
+ try {
1093
+ const encoded = transaction.toString('base64');
1094
+ const payload = {
1095
+ jsonrpc: '2.0',
1096
+ id: 1,
1097
+ method: 'sendTransaction',
1098
+ params: [encoded, { encoding: 'base64' }],
1099
+ };
1100
+
1101
+ const headers: Record<string, string> = {};
1102
+ if (this.config.apiKey) {
1103
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
1104
+ }
1105
+
1106
+ const result = (await this.post(this.apiUrl, payload, headers)) as any;
1107
+
1108
+ if (result.error) {
1109
+ throw new TradeError(result.error.code || 500, result.error.message);
1110
+ }
1111
+
1112
+ const latencyMs = Date.now() - startTime;
1113
+ this.updateStats(true, latencyMs);
1114
+
1115
+ return {
1116
+ success: true,
1117
+ signature: result.result,
1118
+ provider: 'Helius',
1119
+ latencyMs,
1120
+ };
1121
+ } catch (error) {
1122
+ const latencyMs = Date.now() - startTime;
1123
+ const errorMsg = error instanceof Error ? error.message : String(error);
1124
+ this.updateStats(false, latencyMs, errorMsg);
1125
+
1126
+ return {
1127
+ success: false,
1128
+ provider: 'Helius',
1129
+ latencyMs,
1130
+ error: errorMsg,
1131
+ };
1132
+ }
1133
+ }
1134
+
1135
+ getProviderType(): SwqosType {
1136
+ return SwqosType.Helius;
1137
+ }
1138
+ }
1139
+
1140
+ /**
1141
+ * Triton SWQOS client - High-performance RPC
1142
+ */
1143
+ export class TritonClient extends SwqosClient {
1144
+ private apiUrl: string;
1145
+
1146
+ constructor(config: SwqosConfig) {
1147
+ super(config);
1148
+ this.apiUrl = config.url || 'https://api.triton.one';
1149
+ }
1150
+
1151
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1152
+ await this.rateLimitCheck();
1153
+ const startTime = Date.now();
1154
+
1155
+ try {
1156
+ const encoded = transaction.toString('base64');
1157
+ const payload = { transaction: encoded, tip };
1158
+
1159
+ const headers: Record<string, string> = {};
1160
+ if (this.config.apiKey) {
1161
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
1162
+ }
1163
+
1164
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
1165
+
1166
+ const latencyMs = Date.now() - startTime;
1167
+ this.updateStats(true, latencyMs);
1168
+
1169
+ return {
1170
+ success: true,
1171
+ signature: result.signature,
1172
+ provider: 'Triton',
1173
+ latencyMs,
1174
+ };
1175
+ } catch (error) {
1176
+ const latencyMs = Date.now() - startTime;
1177
+ const errorMsg = error instanceof Error ? error.message : String(error);
1178
+ this.updateStats(false, latencyMs, errorMsg);
1179
+
1180
+ return {
1181
+ success: false,
1182
+ provider: 'Triton',
1183
+ latencyMs,
1184
+ error: errorMsg,
1185
+ };
1186
+ }
1187
+ }
1188
+
1189
+ getProviderType(): SwqosType {
1190
+ return SwqosType.Triton;
1191
+ }
1192
+ }
1193
+
1194
+ /**
1195
+ * QuickNode SWQOS client - Enterprise RPC
1196
+ */
1197
+ export class QuickNodeClient extends SwqosClient {
1198
+ private apiUrl: string;
1199
+
1200
+ constructor(config: SwqosConfig) {
1201
+ super(config);
1202
+ this.apiUrl = config.url || 'https://api.quicknode.com';
1203
+ }
1204
+
1205
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1206
+ await this.rateLimitCheck();
1207
+ const startTime = Date.now();
1208
+
1209
+ try {
1210
+ const encoded = transaction.toString('base64');
1211
+ const payload = { transaction: encoded, tip };
1212
+
1213
+ const headers: Record<string, string> = {};
1214
+ if (this.config.apiKey) {
1215
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
1216
+ }
1217
+
1218
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
1219
+
1220
+ const latencyMs = Date.now() - startTime;
1221
+ this.updateStats(true, latencyMs);
1222
+
1223
+ return {
1224
+ success: true,
1225
+ signature: result.signature,
1226
+ provider: 'QuickNode',
1227
+ latencyMs,
1228
+ };
1229
+ } catch (error) {
1230
+ const latencyMs = Date.now() - startTime;
1231
+ const errorMsg = error instanceof Error ? error.message : String(error);
1232
+ this.updateStats(false, latencyMs, errorMsg);
1233
+
1234
+ return {
1235
+ success: false,
1236
+ provider: 'QuickNode',
1237
+ latencyMs,
1238
+ error: errorMsg,
1239
+ };
1240
+ }
1241
+ }
1242
+
1243
+ getProviderType(): SwqosType {
1244
+ return SwqosType.QuickNode;
1245
+ }
1246
+ }
1247
+
1248
+ /**
1249
+ * Syndica SWQOS client - Premium infrastructure
1250
+ */
1251
+ export class SyndicaClient extends SwqosClient {
1252
+ private apiUrl: string;
1253
+
1254
+ constructor(config: SwqosConfig) {
1255
+ super(config);
1256
+ this.apiUrl = config.url || 'https://api.syndica.io';
1257
+ }
1258
+
1259
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1260
+ await this.rateLimitCheck();
1261
+ const startTime = Date.now();
1262
+
1263
+ try {
1264
+ const encoded = transaction.toString('base64');
1265
+ const payload = { transaction: encoded, tip };
1266
+
1267
+ const headers: Record<string, string> = {};
1268
+ if (this.config.apiKey) {
1269
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
1270
+ }
1271
+
1272
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
1273
+
1274
+ const latencyMs = Date.now() - startTime;
1275
+ this.updateStats(true, latencyMs);
1276
+
1277
+ return {
1278
+ success: true,
1279
+ signature: result.signature,
1280
+ provider: 'Syndica',
1281
+ latencyMs,
1282
+ };
1283
+ } catch (error) {
1284
+ const latencyMs = Date.now() - startTime;
1285
+ const errorMsg = error instanceof Error ? error.message : String(error);
1286
+ this.updateStats(false, latencyMs, errorMsg);
1287
+
1288
+ return {
1289
+ success: false,
1290
+ provider: 'Syndica',
1291
+ latencyMs,
1292
+ error: errorMsg,
1293
+ };
1294
+ }
1295
+ }
1296
+
1297
+ getProviderType(): SwqosType {
1298
+ return SwqosType.Syndica;
1299
+ }
1300
+ }
1301
+
1302
+ /**
1303
+ * Figment SWQOS client - Enterprise staking RPC
1304
+ */
1305
+ export class FigmentClient extends SwqosClient {
1306
+ private apiUrl: string;
1307
+
1308
+ constructor(config: SwqosConfig) {
1309
+ super(config);
1310
+ this.apiUrl = config.url || 'https://api.figment.io';
1311
+ }
1312
+
1313
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1314
+ await this.rateLimitCheck();
1315
+ const startTime = Date.now();
1316
+
1317
+ try {
1318
+ const encoded = transaction.toString('base64');
1319
+ const payload = { transaction: encoded, tip };
1320
+
1321
+ const headers: Record<string, string> = {};
1322
+ if (this.config.apiKey) {
1323
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
1324
+ }
1325
+
1326
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
1327
+
1328
+ const latencyMs = Date.now() - startTime;
1329
+ this.updateStats(true, latencyMs);
1330
+
1331
+ return {
1332
+ success: true,
1333
+ signature: result.signature,
1334
+ provider: 'Figment',
1335
+ latencyMs,
1336
+ };
1337
+ } catch (error) {
1338
+ const latencyMs = Date.now() - startTime;
1339
+ const errorMsg = error instanceof Error ? error.message : String(error);
1340
+ this.updateStats(false, latencyMs, errorMsg);
1341
+
1342
+ return {
1343
+ success: false,
1344
+ provider: 'Figment',
1345
+ latencyMs,
1346
+ error: errorMsg,
1347
+ };
1348
+ }
1349
+ }
1350
+
1351
+ getProviderType(): SwqosType {
1352
+ return SwqosType.Figment;
1353
+ }
1354
+ }
1355
+
1356
+ /**
1357
+ * Alchemy SWQOS client - Web3 infrastructure
1358
+ */
1359
+ export class AlchemyClient extends SwqosClient {
1360
+ private apiUrl: string;
1361
+
1362
+ constructor(config: SwqosConfig) {
1363
+ super(config);
1364
+ this.apiUrl = config.url || 'https://api.alchemy.com';
1365
+ }
1366
+
1367
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1368
+ await this.rateLimitCheck();
1369
+ const startTime = Date.now();
1370
+
1371
+ try {
1372
+ const encoded = transaction.toString('base64');
1373
+ const payload = { transaction: encoded, tip };
1374
+
1375
+ const headers: Record<string, string> = {};
1376
+ if (this.config.apiKey) {
1377
+ headers['Authorization'] = `Bearer ${this.config.apiKey}`;
1378
+ }
1379
+
1380
+ const result = (await this.post(`${this.apiUrl}/api/v1/submit`, payload, headers)) as any;
1381
+
1382
+ const latencyMs = Date.now() - startTime;
1383
+ this.updateStats(true, latencyMs);
1384
+
1385
+ return {
1386
+ success: true,
1387
+ signature: result.signature,
1388
+ provider: 'Alchemy',
1389
+ latencyMs,
1390
+ };
1391
+ } catch (error) {
1392
+ const latencyMs = Date.now() - startTime;
1393
+ const errorMsg = error instanceof Error ? error.message : String(error);
1394
+ this.updateStats(false, latencyMs, errorMsg);
1395
+
1396
+ return {
1397
+ success: false,
1398
+ provider: 'Alchemy',
1399
+ latencyMs,
1400
+ error: errorMsg,
1401
+ };
1402
+ }
1403
+ }
1404
+
1405
+ getProviderType(): SwqosType {
1406
+ return SwqosType.Alchemy;
1407
+ }
1408
+ }
1409
+
1410
+ /**
1411
+ * Default SWQOS client - Standard RPC fallback
1412
+ */
1413
+ export class DefaultClient extends SwqosClient {
1414
+ private rpcUrl: string;
1415
+
1416
+ constructor(config: SwqosConfig, rpcUrl: string) {
1417
+ super(config);
1418
+ this.rpcUrl = rpcUrl;
1419
+ }
1420
+
1421
+ async submitTransaction(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1422
+ await this.rateLimitCheck();
1423
+ const startTime = Date.now();
1424
+
1425
+ try {
1426
+ const encoded = transaction.toString('base64');
1427
+ const payload = {
1428
+ jsonrpc: '2.0',
1429
+ id: 1,
1430
+ method: 'sendTransaction',
1431
+ params: [encoded, { encoding: 'base64' }],
1432
+ };
1433
+
1434
+ const result = (await this.post(this.rpcUrl, payload)) as any;
1435
+
1436
+ if (result.error) {
1437
+ throw new TradeError(result.error.code || 500, result.error.message);
1438
+ }
1439
+
1440
+ const latencyMs = Date.now() - startTime;
1441
+ this.updateStats(true, latencyMs);
1442
+
1443
+ return {
1444
+ success: true,
1445
+ signature: result.result,
1446
+ provider: 'Default',
1447
+ latencyMs,
1448
+ };
1449
+ } catch (error) {
1450
+ const latencyMs = Date.now() - startTime;
1451
+ const errorMsg = error instanceof Error ? error.message : String(error);
1452
+ this.updateStats(false, latencyMs, errorMsg);
1453
+
1454
+ return {
1455
+ success: false,
1456
+ provider: 'Default',
1457
+ latencyMs,
1458
+ error: errorMsg,
1459
+ };
1460
+ }
1461
+ }
1462
+
1463
+ getProviderType(): SwqosType {
1464
+ return SwqosType.Default;
1465
+ }
1466
+ }
1467
+
1468
+ // ===== Factory =====
1469
+
1470
+ /**
1471
+ * Factory for creating SWQOS clients
1472
+ */
1473
+ export class SwqosClientFactory {
1474
+ private static readonly CLIENT_MAP: Record<SwqosType, new (config: SwqosConfig) => SwqosClient> = {
1475
+ [SwqosType.Jito]: JitoClient,
1476
+ [SwqosType.Bloxroute]: BloxrouteClient,
1477
+ [SwqosType.ZeroSlot]: ZeroSlotClient,
1478
+ [SwqosType.NextBlock]: NextBlockClient,
1479
+ [SwqosType.Temporal]: TemporalClient,
1480
+ [SwqosType.Node1]: Node1Client,
1481
+ [SwqosType.FlashBlock]: FlashBlockClient,
1482
+ [SwqosType.BlockRazor]: BlockRazorClient,
1483
+ [SwqosType.Astralane]: AstralaneClient,
1484
+ [SwqosType.Stellium]: StelliumClient,
1485
+ [SwqosType.Lightspeed]: LightspeedClient,
1486
+ [SwqosType.Soyas]: SoyasClient,
1487
+ [SwqosType.Speedlanding]: SpeedlandingClient,
1488
+ [SwqosType.Helius]: HeliusClient,
1489
+ [SwqosType.Triton]: TritonClient,
1490
+ [SwqosType.QuickNode]: QuickNodeClient,
1491
+ [SwqosType.Syndica]: SyndicaClient,
1492
+ [SwqosType.Figment]: FigmentClient,
1493
+ [SwqosType.Alchemy]: AlchemyClient,
1494
+ [SwqosType.Default]: DefaultClient as any,
1495
+ };
1496
+
1497
+ /**
1498
+ * Create SWQOS client based on config type
1499
+ */
1500
+ static createClient(config: SwqosConfig): SwqosClient {
1501
+ const ClientClass = this.CLIENT_MAP[config.swqosType];
1502
+ if (!ClientClass) {
1503
+ throw new TradeError(400, `Unknown SWQOS type: ${config.swqosType}`);
1504
+ }
1505
+ return new ClientClass(config);
1506
+ }
1507
+
1508
+ /**
1509
+ * Get list of supported provider types
1510
+ */
1511
+ static getSupportedTypes(): SwqosType[] {
1512
+ return Object.keys(this.CLIENT_MAP) as SwqosType[];
1513
+ }
1514
+ }
1515
+
1516
+ // ===== Manager =====
1517
+
1518
+ /**
1519
+ * Manager for multiple SWQOS clients
1520
+ */
1521
+ export class SwqosManager {
1522
+ private clients: Map<SwqosType, SwqosClient> = new Map();
1523
+ private fallbackOrder: SwqosType[] = [];
1524
+
1525
+ /**
1526
+ * Add a SWQOS client
1527
+ */
1528
+ addClient(client: SwqosClient): this {
1529
+ this.clients.set(client.config.swqosType, client);
1530
+ if (!this.fallbackOrder.includes(client.config.swqosType)) {
1531
+ this.fallbackOrder.push(client.config.swqosType);
1532
+ }
1533
+ return this;
1534
+ }
1535
+
1536
+ /**
1537
+ * Remove a SWQOS client
1538
+ */
1539
+ removeClient(swqosType: SwqosType): this {
1540
+ this.clients.delete(swqosType);
1541
+ const index = this.fallbackOrder.indexOf(swqosType);
1542
+ if (index > -1) {
1543
+ this.fallbackOrder.splice(index, 1);
1544
+ }
1545
+ return this;
1546
+ }
1547
+
1548
+ /**
1549
+ * Get SWQOS client by type
1550
+ */
1551
+ getClient(swqosType: SwqosType): SwqosClient | undefined {
1552
+ return this.clients.get(swqosType);
1553
+ }
1554
+
1555
+ /**
1556
+ * Get all enabled clients
1557
+ */
1558
+ getAllClients(): SwqosClient[] {
1559
+ return Array.from(this.clients.values()).filter(c => c.isEnabled());
1560
+ }
1561
+
1562
+ /**
1563
+ * Get client with best performance stats
1564
+ */
1565
+ getBestClient(): SwqosClient | undefined {
1566
+ const enabled = this.getAllClients();
1567
+ if (enabled.length === 0) {
1568
+ return undefined;
1569
+ }
1570
+
1571
+ // Sort by success rate and latency
1572
+ const score = (client: SwqosClient): number => {
1573
+ const stats = client.getStats();
1574
+ if (stats.requests === 0) {
1575
+ return 0;
1576
+ }
1577
+ const successRate = stats.successes / stats.requests;
1578
+ // Higher success rate and lower latency = better score
1579
+ return (successRate * 1000) / (stats.avgLatencyMs + 1);
1580
+ };
1581
+
1582
+ return enabled.reduce((best, current) =>
1583
+ score(current) > score(best) ? current : best
1584
+ );
1585
+ }
1586
+
1587
+ /**
1588
+ * Set fallback order for providers
1589
+ */
1590
+ setFallbackOrder(order: SwqosType[]): void {
1591
+ this.fallbackOrder = order.filter(t => this.clients.has(t));
1592
+ }
1593
+
1594
+ /**
1595
+ * Submit with automatic fallback
1596
+ */
1597
+ async submitWithFallback(transaction: Buffer, tip = 0): Promise<TransactionResult> {
1598
+ for (const swqosType of this.fallbackOrder) {
1599
+ const client = this.clients.get(swqosType);
1600
+ if (!client || !client.isEnabled()) {
1601
+ continue;
1602
+ }
1603
+
1604
+ const result = await client.submitTransaction(transaction, tip);
1605
+ if (result.success) {
1606
+ return result;
1607
+ }
1608
+ }
1609
+
1610
+ return {
1611
+ success: false,
1612
+ provider: 'fallback',
1613
+ latencyMs: 0,
1614
+ error: 'All providers failed',
1615
+ };
1616
+ }
1617
+
1618
+ /**
1619
+ * Submit transaction to all enabled providers
1620
+ */
1621
+ async submitToAll(transaction: Buffer, tip = 0): Promise<{
1622
+ results: TransactionResult[];
1623
+ total: number;
1624
+ successful: number;
1625
+ }> {
1626
+ const clients = this.getAllClients();
1627
+ const promises = clients.map(client => client.submitTransaction(transaction, tip));
1628
+
1629
+ const results = await Promise.all(promises);
1630
+
1631
+ return {
1632
+ results,
1633
+ total: promises.length,
1634
+ successful: results.filter(r => r.success).length,
1635
+ };
1636
+ }
1637
+
1638
+ /**
1639
+ * Submit bundle to all providers that support it
1640
+ */
1641
+ async submitBundleToAll(
1642
+ transactions: Buffer[],
1643
+ tip = 0
1644
+ ): Promise<{
1645
+ results: TransactionResult[];
1646
+ total: number;
1647
+ successful: number;
1648
+ }> {
1649
+ const clients = this.getAllClients();
1650
+ const promises = clients.map(client => client.submitBundle(transactions, tip));
1651
+
1652
+ const results = await Promise.all(promises);
1653
+
1654
+ return {
1655
+ results,
1656
+ total: promises.length,
1657
+ successful: results.filter(r => r.success).length,
1658
+ };
1659
+ }
1660
+
1661
+ /**
1662
+ * Get stats for all clients
1663
+ */
1664
+ getAllStats(): Map<SwqosType, ClientStats> {
1665
+ const stats = new Map<SwqosType, ClientStats>();
1666
+ for (const [type, client] of this.clients) {
1667
+ stats.set(type, client.getStats());
1668
+ }
1669
+ return stats;
1670
+ }
1671
+
1672
+ /**
1673
+ * Get aggregated stats across all clients
1674
+ */
1675
+ getAggregatedStats(): {
1676
+ totalRequests: number;
1677
+ totalSuccesses: number;
1678
+ totalFailures: number;
1679
+ successRate: number;
1680
+ avgLatencyMs: number;
1681
+ activeProviders: number;
1682
+ } {
1683
+ let totalRequests = 0;
1684
+ let totalSuccesses = 0;
1685
+ let totalFailures = 0;
1686
+ let totalLatency = 0;
1687
+
1688
+ for (const client of this.clients.values()) {
1689
+ const stats = client.getStats();
1690
+ totalRequests += stats.requests;
1691
+ totalSuccesses += stats.successes;
1692
+ totalFailures += stats.failures;
1693
+ totalLatency += stats.avgLatencyMs;
1694
+ }
1695
+
1696
+ const clientCount = this.clients.size;
1697
+
1698
+ return {
1699
+ totalRequests,
1700
+ totalSuccesses,
1701
+ totalFailures,
1702
+ successRate: totalRequests > 0 ? totalSuccesses / totalRequests : 0,
1703
+ avgLatencyMs: clientCount > 0 ? totalLatency / clientCount : 0,
1704
+ activeProviders: this.getAllClients().length,
1705
+ };
1706
+ }
1707
+ }