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,702 @@
1
+ /**
2
+ * Async Trade Executor for Sol Trade SDK
3
+ * Implements asynchronous trade execution with configurable submission modes.
4
+ */
5
+
6
+ import { Connection, Transaction, Commitment } from '@solana/web3.js';
7
+ import { TradeError, SwqosType, TradeType } from '../../index';
8
+ import { SwqosClient } from '../../swqos/clients';
9
+
10
+ // ===== Types =====
11
+
12
+ /**
13
+ * Submission mode for transaction execution
14
+ */
15
+ export enum SubmitMode {
16
+ /** Submit to single fastest provider */
17
+ Single = 'Single',
18
+ /** Submit to multiple providers in parallel */
19
+ Parallel = 'Parallel',
20
+ /** Submit with fallback providers */
21
+ Fallback = 'Fallback',
22
+ /** Submit with redundancy for high availability */
23
+ Redundant = 'Redundant',
24
+ }
25
+
26
+ /**
27
+ * Execution status for tracking transaction state
28
+ */
29
+ export enum ExecutionStatus {
30
+ /** Initial pending state */
31
+ Pending = 'Pending',
32
+ /** Transaction submitted to provider */
33
+ Submitted = 'Submitted',
34
+ /** Transaction confirmed on chain */
35
+ Confirmed = 'Confirmed',
36
+ /** Transaction finalized */
37
+ Finalized = 'Finalized',
38
+ /** Transaction failed */
39
+ Failed = 'Failed',
40
+ /** Transaction timed out */
41
+ TimedOut = 'TimedOut',
42
+ /** Transaction cancelled */
43
+ Cancelled = 'Cancelled',
44
+ }
45
+
46
+ /**
47
+ * Configuration for async trade execution
48
+ */
49
+ export interface ExecutionConfig {
50
+ /** Submission mode */
51
+ submitMode: SubmitMode;
52
+ /** Whether to wait for confirmation */
53
+ waitConfirmation: boolean;
54
+ /**
55
+ * Commitment level for confirmation polling.
56
+ * `finalized` waits for finalized only; any other value follows Rust
57
+ * `poll_any_transaction_confirmation` (confirmed or finalized, not processed-only).
58
+ */
59
+ commitment: Commitment;
60
+ /** Maximum number of retries */
61
+ maxRetries: number;
62
+ /** Delay between retries in milliseconds */
63
+ retryDelayMs: number;
64
+ /** Timeout for execution in milliseconds */
65
+ timeoutMs: number;
66
+ /** Whether to abort on first success */
67
+ abortOnSuccess: boolean;
68
+ /** Priority providers to use (empty = all) */
69
+ priorityProviders: SwqosType[];
70
+ /** Callback for status updates */
71
+ onStatusUpdate?: (status: ExecutionStatus, result?: ExecutionResult) => void;
72
+ /** Callback for progress updates */
73
+ onProgress?: (progress: ExecutionProgress) => void;
74
+ }
75
+
76
+ /**
77
+ * Execution progress information
78
+ */
79
+ export interface ExecutionProgress {
80
+ /** Current attempt number */
81
+ attempt: number;
82
+ /** Total attempts allowed */
83
+ totalAttempts: number;
84
+ /** Current provider being used */
85
+ currentProvider?: SwqosType;
86
+ /** Number of providers tried */
87
+ providersTried: number;
88
+ /** Elapsed time in milliseconds */
89
+ elapsedMs: number;
90
+ /** Estimated time remaining in milliseconds */
91
+ estimatedRemainingMs?: number;
92
+ }
93
+
94
+ /**
95
+ * Result of trade execution
96
+ */
97
+ export interface ExecutionResult {
98
+ /** Transaction signature */
99
+ signature: string;
100
+ /** Execution success status */
101
+ success: boolean;
102
+ /** Final execution status */
103
+ status: ExecutionStatus;
104
+ /** Error message if failed */
105
+ error?: string;
106
+ /** Provider that succeeded (if any) */
107
+ provider?: SwqosType;
108
+ /** Number of attempts made */
109
+ attempts: number;
110
+ /** Total execution time in milliseconds */
111
+ executionTimeMs: number;
112
+ /** Time to confirmation in milliseconds */
113
+ confirmationTimeMs?: number;
114
+ /** Slot when transaction was confirmed */
115
+ slot?: number;
116
+ /** Blockhash used for transaction */
117
+ blockhash?: string;
118
+ /** Additional metadata */
119
+ metadata?: Record<string, unknown>;
120
+ }
121
+
122
+ /**
123
+ * Internal execution state
124
+ */
125
+ interface ExecutionState {
126
+ id: string;
127
+ startTime: number;
128
+ attempts: number;
129
+ providersTried: Set<SwqosType>;
130
+ currentStatus: ExecutionStatus;
131
+ abortController: AbortController;
132
+ }
133
+
134
+ // ===== Default Configurations =====
135
+
136
+ /**
137
+ * Get default execution configuration
138
+ */
139
+ export function defaultExecutionConfig(): ExecutionConfig {
140
+ return {
141
+ submitMode: SubmitMode.Parallel,
142
+ waitConfirmation: true,
143
+ commitment: 'confirmed',
144
+ maxRetries: 3,
145
+ retryDelayMs: 100,
146
+ timeoutMs: 60000,
147
+ abortOnSuccess: true,
148
+ priorityProviders: [],
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Get execution config for high-frequency trading
154
+ */
155
+ export function hftExecutionConfig(): ExecutionConfig {
156
+ return {
157
+ submitMode: SubmitMode.Parallel,
158
+ waitConfirmation: false,
159
+ commitment: 'processed',
160
+ maxRetries: 1,
161
+ retryDelayMs: 50,
162
+ timeoutMs: 10000,
163
+ abortOnSuccess: true,
164
+ priorityProviders: [SwqosType.Jito, SwqosType.Bloxroute],
165
+ };
166
+ }
167
+
168
+ /**
169
+ * Get execution config for reliable execution
170
+ */
171
+ export function reliableExecutionConfig(): ExecutionConfig {
172
+ return {
173
+ submitMode: SubmitMode.Fallback,
174
+ waitConfirmation: true,
175
+ commitment: 'finalized',
176
+ maxRetries: 5,
177
+ retryDelayMs: 500,
178
+ timeoutMs: 120000,
179
+ abortOnSuccess: true,
180
+ priorityProviders: [],
181
+ };
182
+ }
183
+
184
+ // ===== Async Trade Executor =====
185
+
186
+ /**
187
+ * Async trade executor with multiple submission modes
188
+ */
189
+ export class AsyncTradeExecutor {
190
+ private clients: Map<SwqosType, SwqosClient> = new Map();
191
+ private connection: Connection;
192
+ private activeExecutions: Map<string, ExecutionState> = new Map();
193
+
194
+ constructor(
195
+ private rpcUrl: string,
196
+ clients: SwqosClient[] = []
197
+ ) {
198
+ this.connection = new Connection(rpcUrl, 'confirmed');
199
+ for (const client of clients) {
200
+ this.clients.set(client.getSwqosType(), client);
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Add a SWQOS client
206
+ */
207
+ addClient(client: SwqosClient): void {
208
+ this.clients.set(client.getSwqosType(), client);
209
+ }
210
+
211
+ /**
212
+ * Remove a SWQOS client
213
+ */
214
+ removeClient(type: SwqosType): void {
215
+ this.clients.delete(type);
216
+ }
217
+
218
+ /**
219
+ * Get all registered clients
220
+ */
221
+ getClients(): Map<SwqosType, SwqosClient> {
222
+ return new Map(this.clients);
223
+ }
224
+
225
+ /**
226
+ * Execute a trade asynchronously
227
+ */
228
+ async execute(
229
+ tradeType: TradeType,
230
+ transaction: Buffer,
231
+ config: Partial<ExecutionConfig> = {}
232
+ ): Promise<ExecutionResult> {
233
+ const fullConfig = { ...defaultExecutionConfig(), ...config };
234
+ const executionId = this.generateExecutionId();
235
+
236
+ const state: ExecutionState = {
237
+ id: executionId,
238
+ startTime: Date.now(),
239
+ attempts: 0,
240
+ providersTried: new Set(),
241
+ currentStatus: ExecutionStatus.Pending,
242
+ abortController: new AbortController(),
243
+ };
244
+
245
+ this.activeExecutions.set(executionId, state);
246
+
247
+ try {
248
+ this.updateStatus(state, ExecutionStatus.Pending, fullConfig);
249
+
250
+ const result = await this.executeWithTimeout(
251
+ tradeType,
252
+ transaction,
253
+ fullConfig,
254
+ state
255
+ );
256
+
257
+ return result;
258
+ } finally {
259
+ this.activeExecutions.delete(executionId);
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Cancel an active execution
265
+ */
266
+ cancel(executionId: string): boolean {
267
+ const state = this.activeExecutions.get(executionId);
268
+ if (state) {
269
+ state.abortController.abort();
270
+ this.updateStatus(state, ExecutionStatus.Cancelled);
271
+ return true;
272
+ }
273
+ return false;
274
+ }
275
+
276
+ /**
277
+ * Cancel all active executions
278
+ */
279
+ cancelAll(): number {
280
+ let count = 0;
281
+ for (const [id, state] of this.activeExecutions) {
282
+ state.abortController.abort();
283
+ this.updateStatus(state, ExecutionStatus.Cancelled);
284
+ count++;
285
+ }
286
+ return count;
287
+ }
288
+
289
+ /**
290
+ * Get active execution count
291
+ */
292
+ getActiveExecutionCount(): number {
293
+ return this.activeExecutions.size;
294
+ }
295
+
296
+ private async executeWithTimeout(
297
+ tradeType: TradeType,
298
+ transaction: Buffer,
299
+ config: ExecutionConfig,
300
+ state: ExecutionState
301
+ ): Promise<ExecutionResult> {
302
+ return new Promise((resolve, reject) => {
303
+ const timeoutId = setTimeout(() => {
304
+ this.updateStatus(state, ExecutionStatus.TimedOut, config);
305
+ resolve(this.createTimeoutResult(state));
306
+ }, config.timeoutMs);
307
+
308
+ this.executeInternal(tradeType, transaction, config, state)
309
+ .then(result => {
310
+ clearTimeout(timeoutId);
311
+ resolve(result);
312
+ })
313
+ .catch(error => {
314
+ clearTimeout(timeoutId);
315
+ reject(error);
316
+ });
317
+ });
318
+ }
319
+
320
+ private async executeInternal(
321
+ tradeType: TradeType,
322
+ transaction: Buffer,
323
+ config: ExecutionConfig,
324
+ state: ExecutionState
325
+ ): Promise<ExecutionResult> {
326
+ switch (config.submitMode) {
327
+ case SubmitMode.Single:
328
+ return this.executeSingle(tradeType, transaction, config, state);
329
+ case SubmitMode.Parallel:
330
+ return this.executeParallel(tradeType, transaction, config, state);
331
+ case SubmitMode.Fallback:
332
+ return this.executeFallback(tradeType, transaction, config, state);
333
+ case SubmitMode.Redundant:
334
+ return this.executeRedundant(tradeType, transaction, config, state);
335
+ default:
336
+ throw new TradeError(400, `Unknown submit mode: ${config.submitMode}`);
337
+ }
338
+ }
339
+
340
+ private async executeSingle(
341
+ tradeType: TradeType,
342
+ transaction: Buffer,
343
+ config: ExecutionConfig,
344
+ state: ExecutionState
345
+ ): Promise<ExecutionResult> {
346
+ const providers = this.getOrderedProviders(config.priorityProviders);
347
+ const provider = providers[0];
348
+
349
+ if (!provider) {
350
+ return this.createErrorResult(state, 'No providers available');
351
+ }
352
+
353
+ return this.executeWithRetry(tradeType, transaction, config, state, provider);
354
+ }
355
+
356
+ private async executeParallel(
357
+ tradeType: TradeType,
358
+ transaction: Buffer,
359
+ config: ExecutionConfig,
360
+ state: ExecutionState
361
+ ): Promise<ExecutionResult> {
362
+ const providers = this.getOrderedProviders(config.priorityProviders);
363
+
364
+ if (providers.length === 0) {
365
+ return this.createErrorResult(state, 'No providers available');
366
+ }
367
+
368
+ const promises = providers.map(provider =>
369
+ this.executeWithProvider(tradeType, transaction, config, state, provider)
370
+ .catch(error => ({ success: false, error, provider: provider.getSwqosType() } as ExecutionResult))
371
+ );
372
+
373
+ const results = await Promise.allSettled(promises);
374
+
375
+ for (const result of results) {
376
+ if (result.status === 'fulfilled' && result.value.success) {
377
+ return result.value;
378
+ }
379
+ }
380
+
381
+ // All failed, return first error
382
+ const firstError = results.find(r => r.status === 'fulfilled');
383
+ if (firstError && firstError.status === 'fulfilled') {
384
+ return firstError.value;
385
+ }
386
+
387
+ return this.createErrorResult(state, 'All parallel submissions failed');
388
+ }
389
+
390
+ private async executeFallback(
391
+ tradeType: TradeType,
392
+ transaction: Buffer,
393
+ config: ExecutionConfig,
394
+ state: ExecutionState
395
+ ): Promise<ExecutionResult> {
396
+ const providers = this.getOrderedProviders(config.priorityProviders);
397
+
398
+ for (const provider of providers) {
399
+ const result = await this.executeWithProvider(
400
+ tradeType,
401
+ transaction,
402
+ config,
403
+ state,
404
+ provider
405
+ );
406
+
407
+ if (result.success) {
408
+ return result;
409
+ }
410
+
411
+ if (config.retryDelayMs > 0) {
412
+ await this.sleep(config.retryDelayMs);
413
+ }
414
+ }
415
+
416
+ return this.createErrorResult(state, 'All fallback providers failed');
417
+ }
418
+
419
+ private async executeRedundant(
420
+ tradeType: TradeType,
421
+ transaction: Buffer,
422
+ config: ExecutionConfig,
423
+ state: ExecutionState
424
+ ): Promise<ExecutionResult> {
425
+ // Similar to parallel but continues even after first success for redundancy
426
+ const providers = this.getOrderedProviders(config.priorityProviders);
427
+ const minSuccesses = Math.min(2, providers.length);
428
+
429
+ const promises = providers.map(provider =>
430
+ this.executeWithProvider(tradeType, transaction, config, state, provider)
431
+ );
432
+
433
+ const results = await Promise.allSettled(promises);
434
+ const successes = results.filter(
435
+ (r): r is PromiseFulfilledResult<ExecutionResult> => r.status === 'fulfilled' && r.value.success
436
+ );
437
+
438
+ if (successes.length >= minSuccesses) {
439
+ // Return the fastest successful result
440
+ const firstSuccess = successes[0]!;
441
+ if (firstSuccess.status === 'fulfilled') {
442
+ return {
443
+ ...firstSuccess.value,
444
+ metadata: {
445
+ ...firstSuccess.value.metadata,
446
+ redundantSubmissions: successes.length,
447
+ },
448
+ };
449
+ }
450
+ }
451
+
452
+ return this.createErrorResult(
453
+ state,
454
+ `Redundant execution failed: ${successes.length}/${minSuccesses} successes`
455
+ );
456
+ }
457
+
458
+ private async executeWithRetry(
459
+ tradeType: TradeType,
460
+ transaction: Buffer,
461
+ config: ExecutionConfig,
462
+ state: ExecutionState,
463
+ provider: SwqosClient
464
+ ): Promise<ExecutionResult> {
465
+ for (let attempt = 0; attempt < config.maxRetries; attempt++) {
466
+ state.attempts = attempt + 1;
467
+
468
+ this.reportProgress(state, config, provider.getSwqosType());
469
+
470
+ const result = await this.executeWithProvider(
471
+ tradeType,
472
+ transaction,
473
+ config,
474
+ state,
475
+ provider
476
+ );
477
+
478
+ if (result.success) {
479
+ return result;
480
+ }
481
+
482
+ if (attempt < config.maxRetries - 1 && config.retryDelayMs > 0) {
483
+ await this.sleep(config.retryDelayMs * Math.pow(2, attempt)); // Exponential backoff
484
+ }
485
+ }
486
+
487
+ return this.createErrorResult(
488
+ state,
489
+ `Failed after ${config.maxRetries} retries`
490
+ );
491
+ }
492
+
493
+ private async executeWithProvider(
494
+ tradeType: TradeType,
495
+ transaction: Buffer,
496
+ config: ExecutionConfig,
497
+ state: ExecutionState,
498
+ provider: SwqosClient
499
+ ): Promise<ExecutionResult> {
500
+ const providerType = provider.getSwqosType();
501
+ state.providersTried.add(providerType);
502
+
503
+ try {
504
+ this.updateStatus(state, ExecutionStatus.Submitted, config);
505
+
506
+ const signature = await provider.sendTransaction(
507
+ tradeType,
508
+ transaction,
509
+ false
510
+ );
511
+
512
+ let confirmationTimeMs: number | undefined;
513
+
514
+ if (config.waitConfirmation) {
515
+ this.updateStatus(state, ExecutionStatus.Confirmed, config);
516
+ const confirmed = await this.waitForConfirmation(
517
+ signature,
518
+ config.commitment
519
+ );
520
+ confirmationTimeMs = Date.now() - state.startTime;
521
+
522
+ if (!confirmed) {
523
+ return this.createErrorResult(state, 'Transaction failed to confirm', providerType);
524
+ }
525
+
526
+ this.updateStatus(state, ExecutionStatus.Finalized, config);
527
+ }
528
+
529
+ return {
530
+ signature,
531
+ success: true,
532
+ status: config.waitConfirmation ? ExecutionStatus.Finalized : ExecutionStatus.Submitted,
533
+ provider: providerType,
534
+ attempts: state.attempts,
535
+ executionTimeMs: Date.now() - state.startTime,
536
+ confirmationTimeMs,
537
+ };
538
+ } catch (error) {
539
+ return this.createErrorResult(
540
+ state,
541
+ error instanceof Error ? error.message : 'Unknown error',
542
+ providerType
543
+ );
544
+ }
545
+ }
546
+
547
+ private async waitForConfirmation(
548
+ signature: string,
549
+ commitment: Commitment
550
+ ): Promise<boolean> {
551
+ const timeoutMs = 30000;
552
+ const startTime = Date.now();
553
+
554
+ while (Date.now() - startTime < timeoutMs) {
555
+ try {
556
+ const status = await this.connection.getSignatureStatus(signature);
557
+ if (status.value) {
558
+ if (status.value.err) {
559
+ return false;
560
+ }
561
+ const cs = status.value.confirmationStatus;
562
+ if (commitment === 'finalized') {
563
+ if (cs === 'finalized') return true;
564
+ } else {
565
+ // Rust `poll_any_transaction_confirmation`: Confirmed | Finalized only
566
+ if (cs === 'confirmed' || cs === 'finalized') return true;
567
+ }
568
+ }
569
+ } catch {
570
+ // Continue polling
571
+ }
572
+ await this.sleep(500);
573
+ }
574
+
575
+ return false;
576
+ }
577
+
578
+ private getOrderedProviders(priorityProviders: SwqosType[]): SwqosClient[] {
579
+ const providers: SwqosClient[] = [];
580
+
581
+ // Add priority providers first
582
+ for (const type of priorityProviders) {
583
+ const client = this.clients.get(type);
584
+ if (client) {
585
+ providers.push(client);
586
+ }
587
+ }
588
+
589
+ // Add remaining providers
590
+ for (const [type, client] of this.clients) {
591
+ if (!priorityProviders.includes(type)) {
592
+ providers.push(client);
593
+ }
594
+ }
595
+
596
+ return providers;
597
+ }
598
+
599
+ private updateStatus(
600
+ state: ExecutionState,
601
+ status: ExecutionStatus,
602
+ config?: ExecutionConfig,
603
+ result?: ExecutionResult
604
+ ): void {
605
+ state.currentStatus = status;
606
+ if (config?.onStatusUpdate) {
607
+ config.onStatusUpdate(status, result);
608
+ }
609
+ }
610
+
611
+ private reportProgress(
612
+ state: ExecutionState,
613
+ config: ExecutionConfig,
614
+ currentProvider?: SwqosType
615
+ ): void {
616
+ if (config.onProgress) {
617
+ const elapsedMs = Date.now() - state.startTime;
618
+ const progress: ExecutionProgress = {
619
+ attempt: state.attempts,
620
+ totalAttempts: config.maxRetries,
621
+ currentProvider,
622
+ providersTried: state.providersTried.size,
623
+ elapsedMs,
624
+ estimatedRemainingMs: this.estimateRemainingTime(state, config),
625
+ };
626
+ config.onProgress(progress);
627
+ }
628
+ }
629
+
630
+ private estimateRemainingTime(state: ExecutionState, config: ExecutionConfig): number | undefined {
631
+ if (state.attempts === 0) {
632
+ return undefined;
633
+ }
634
+
635
+ const elapsedMs = Date.now() - state.startTime;
636
+ const avgTimePerAttempt = elapsedMs / state.attempts;
637
+ const remainingAttempts = config.maxRetries - state.attempts;
638
+
639
+ return Math.ceil(avgTimePerAttempt * remainingAttempts);
640
+ }
641
+
642
+ private createErrorResult(
643
+ state: ExecutionState,
644
+ error: string,
645
+ provider?: SwqosType
646
+ ): ExecutionResult {
647
+ return {
648
+ signature: '',
649
+ success: false,
650
+ status: ExecutionStatus.Failed,
651
+ error,
652
+ provider,
653
+ attempts: state.attempts,
654
+ executionTimeMs: Date.now() - state.startTime,
655
+ };
656
+ }
657
+
658
+ private createTimeoutResult(state: ExecutionState): ExecutionResult {
659
+ return {
660
+ signature: '',
661
+ success: false,
662
+ status: ExecutionStatus.TimedOut,
663
+ error: 'Execution timed out',
664
+ attempts: state.attempts,
665
+ executionTimeMs: Date.now() - state.startTime,
666
+ };
667
+ }
668
+
669
+ private generateExecutionId(): string {
670
+ return `exec_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
671
+ }
672
+
673
+ private sleep(ms: number): Promise<void> {
674
+ return new Promise(resolve => setTimeout(resolve, ms));
675
+ }
676
+ }
677
+
678
+ // ===== Convenience Functions =====
679
+
680
+ /**
681
+ * Create an async trade executor with default configuration
682
+ */
683
+ export function createAsyncExecutor(
684
+ rpcUrl: string,
685
+ clients: SwqosClient[] = []
686
+ ): AsyncTradeExecutor {
687
+ return new AsyncTradeExecutor(rpcUrl, clients);
688
+ }
689
+
690
+ /**
691
+ * Execute a single trade with minimal configuration
692
+ */
693
+ export async function executeTrade(
694
+ rpcUrl: string,
695
+ tradeType: TradeType,
696
+ transaction: Buffer,
697
+ clients: SwqosClient[],
698
+ config?: Partial<ExecutionConfig>
699
+ ): Promise<ExecutionResult> {
700
+ const executor = new AsyncTradeExecutor(rpcUrl, clients);
701
+ return executor.execute(tradeType, transaction, config);
702
+ }