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,711 @@
1
+ /**
2
+ * Confirmation Monitor for Sol Trade SDK
3
+ * Monitors transaction confirmations with configurable strategies.
4
+ */
5
+
6
+ import { Connection, Commitment, PublicKey } from '@solana/web3.js';
7
+ import { TradeError } from '../../index';
8
+
9
+ // ===== Types =====
10
+
11
+ /**
12
+ * Confirmation status levels
13
+ */
14
+ export enum ConfirmationStatus {
15
+ /** Transaction not found */
16
+ NotFound = 'NotFound',
17
+ /** Transaction processed but not confirmed */
18
+ Processed = 'Processed',
19
+ /** Transaction confirmed by cluster */
20
+ Confirmed = 'Confirmed',
21
+ /** Transaction finalized (rooted) */
22
+ Finalized = 'Finalized',
23
+ /** Transaction failed with error */
24
+ Failed = 'Failed',
25
+ /** Confirmation timed out */
26
+ TimedOut = 'TimedOut',
27
+ }
28
+
29
+ /**
30
+ * Configuration for confirmation monitoring
31
+ */
32
+ export interface ConfirmationConfig {
33
+ /** Target commitment level */
34
+ commitment: Commitment;
35
+ /** Polling interval in milliseconds */
36
+ pollIntervalMs: number;
37
+ /** Maximum time to wait for confirmation */
38
+ timeoutMs: number;
39
+ /** Maximum retry attempts */
40
+ maxRetries: number;
41
+ /** Whether to use WebSocket subscription */
42
+ useWebSocket: boolean;
43
+ /** Whether to enable signature caching */
44
+ enableCache: boolean;
45
+ /** Cache TTL in milliseconds */
46
+ cacheTtlMs: number;
47
+ /** Callback for status updates */
48
+ onStatusUpdate?: (signature: string, status: ConfirmationStatus, result?: ConfirmationResult) => void;
49
+ /** Callback for progress updates */
50
+ onProgress?: (signature: string, progress: ConfirmationProgress) => void;
51
+ }
52
+
53
+ /**
54
+ * Confirmation progress information
55
+ */
56
+ export interface ConfirmationProgress {
57
+ /** Current status */
58
+ status: ConfirmationStatus;
59
+ /** Number of confirmations received */
60
+ confirmations: number;
61
+ /** Slot when transaction was processed */
62
+ slot?: number;
63
+ /** Current slot */
64
+ currentSlot?: number;
65
+ /** Elapsed time in milliseconds */
66
+ elapsedMs: number;
67
+ /** Estimated time remaining in milliseconds */
68
+ estimatedRemainingMs?: number;
69
+ /** Retry attempt number */
70
+ retryAttempt: number;
71
+ }
72
+
73
+ /**
74
+ * Result of confirmation monitoring
75
+ */
76
+ export interface ConfirmationResult {
77
+ /** Transaction signature */
78
+ signature: string;
79
+ /** Final confirmation status */
80
+ status: ConfirmationStatus;
81
+ /** Slot when transaction was processed */
82
+ slot?: number;
83
+ /** Blockhash of the block containing the transaction */
84
+ blockhash?: string;
85
+ /** Error information if transaction failed */
86
+ error?: TransactionError;
87
+ /** Total time to confirm in milliseconds */
88
+ confirmationTimeMs: number;
89
+ /** Number of retry attempts made */
90
+ retryAttempts: number;
91
+ /** Timestamp when monitoring started */
92
+ startedAt: number;
93
+ /** Timestamp when monitoring completed */
94
+ completedAt: number;
95
+ /** Additional metadata */
96
+ metadata?: Record<string, unknown>;
97
+ }
98
+
99
+ /**
100
+ * Transaction error information
101
+ */
102
+ export interface TransactionError {
103
+ /** Error code */
104
+ code: number;
105
+ /** Error message */
106
+ message: string;
107
+ /** Program that caused the error (if applicable) */
108
+ programId?: string;
109
+ /** Error logs */
110
+ logs?: string[];
111
+ }
112
+
113
+ /**
114
+ * Monitored signature information
115
+ */
116
+ interface MonitoredSignature {
117
+ signature: string;
118
+ startTime: number;
119
+ config: ConfirmationConfig;
120
+ status: ConfirmationStatus;
121
+ slot?: number;
122
+ blockhash?: string;
123
+ error?: TransactionError;
124
+ retryAttempts: number;
125
+ lastPollTime: number;
126
+ abortController: AbortController;
127
+ callbacks: Set<(result: ConfirmationResult) => void>;
128
+ }
129
+
130
+ // ===== Default Configurations =====
131
+
132
+ /**
133
+ * Get default confirmation configuration
134
+ */
135
+ export function defaultConfirmationConfig(): ConfirmationConfig {
136
+ return {
137
+ commitment: 'confirmed',
138
+ pollIntervalMs: 500,
139
+ timeoutMs: 60000,
140
+ maxRetries: 3,
141
+ useWebSocket: false,
142
+ enableCache: true,
143
+ cacheTtlMs: 300000, // 5 minutes
144
+ };
145
+ }
146
+
147
+ /**
148
+ * Get fast confirmation configuration
149
+ */
150
+ export function fastConfirmationConfig(): ConfirmationConfig {
151
+ return {
152
+ commitment: 'processed',
153
+ pollIntervalMs: 200,
154
+ timeoutMs: 10000,
155
+ maxRetries: 1,
156
+ useWebSocket: true,
157
+ enableCache: false,
158
+ cacheTtlMs: 60000,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Get reliable confirmation configuration
164
+ */
165
+ export function reliableConfirmationConfig(): ConfirmationConfig {
166
+ return {
167
+ commitment: 'finalized',
168
+ pollIntervalMs: 1000,
169
+ timeoutMs: 120000,
170
+ maxRetries: 5,
171
+ useWebSocket: true,
172
+ enableCache: true,
173
+ cacheTtlMs: 600000, // 10 minutes
174
+ };
175
+ }
176
+
177
+ // ===== Confirmation Monitor =====
178
+
179
+ /**
180
+ * Monitors transaction confirmations with configurable strategies
181
+ */
182
+ export class ConfirmationMonitor {
183
+ private connection: Connection;
184
+ private monitored: Map<string, MonitoredSignature> = new Map();
185
+ private cache: Map<string, ConfirmationResult> = new Map();
186
+ private pollInterval?: NodeJS.Timeout;
187
+ private isRunning: boolean = false;
188
+ private wsSubscription?: number;
189
+
190
+ constructor(
191
+ rpcUrl: string,
192
+ private defaultConfig: ConfirmationConfig = defaultConfirmationConfig()
193
+ ) {
194
+ this.connection = new Connection(rpcUrl, defaultConfig.commitment);
195
+ }
196
+
197
+ /**
198
+ * Start the confirmation monitor
199
+ */
200
+ start(): void {
201
+ if (this.isRunning) return;
202
+
203
+ this.isRunning = true;
204
+ this.pollInterval = setInterval(() => {
205
+ this.pollAll();
206
+ }, this.defaultConfig.pollIntervalMs);
207
+
208
+ if (this.defaultConfig.useWebSocket) {
209
+ this.setupWebSocket();
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Stop the confirmation monitor
215
+ */
216
+ stop(): void {
217
+ this.isRunning = false;
218
+
219
+ if (this.pollInterval) {
220
+ clearInterval(this.pollInterval);
221
+ this.pollInterval = undefined;
222
+ }
223
+
224
+ if (this.wsSubscription !== undefined) {
225
+ this.connection.removeSignatureListener(this.wsSubscription);
226
+ this.wsSubscription = undefined;
227
+ }
228
+
229
+ // Abort all monitored signatures
230
+ for (const monitored of this.monitored.values()) {
231
+ monitored.abortController.abort();
232
+ }
233
+ this.monitored.clear();
234
+ }
235
+
236
+ /**
237
+ * Monitor a transaction signature for confirmation
238
+ */
239
+ async monitor(
240
+ signature: string,
241
+ config?: Partial<ConfirmationConfig>
242
+ ): Promise<ConfirmationResult> {
243
+ const fullConfig = { ...this.defaultConfig, ...config };
244
+
245
+ // Check cache first
246
+ if (fullConfig.enableCache) {
247
+ const cached = this.getCachedResult(signature);
248
+ if (cached) {
249
+ return cached;
250
+ }
251
+ }
252
+
253
+ // Check if already being monitored
254
+ const existing = this.monitored.get(signature);
255
+ if (existing) {
256
+ return this.waitForResult(existing);
257
+ }
258
+
259
+ // Start monitoring
260
+ const monitored: MonitoredSignature = {
261
+ signature,
262
+ startTime: Date.now(),
263
+ config: fullConfig,
264
+ status: ConfirmationStatus.NotFound,
265
+ retryAttempts: 0,
266
+ lastPollTime: 0,
267
+ abortController: new AbortController(),
268
+ callbacks: new Set(),
269
+ };
270
+
271
+ this.monitored.set(signature, monitored);
272
+
273
+ if (!this.isRunning) {
274
+ this.start();
275
+ }
276
+
277
+ // Set up timeout
278
+ this.setupTimeout(monitored);
279
+
280
+ return this.waitForResult(monitored);
281
+ }
282
+
283
+ /**
284
+ * Monitor multiple signatures
285
+ */
286
+ async monitorMultiple(
287
+ signatures: string[],
288
+ config?: Partial<ConfirmationConfig>
289
+ ): Promise<ConfirmationResult[]> {
290
+ return Promise.all(
291
+ signatures.map(sig => this.monitor(sig, config))
292
+ );
293
+ }
294
+
295
+ /**
296
+ * Cancel monitoring for a signature
297
+ */
298
+ cancel(signature: string): boolean {
299
+ const monitored = this.monitored.get(signature);
300
+ if (monitored) {
301
+ monitored.abortController.abort();
302
+ this.monitored.delete(signature);
303
+ return true;
304
+ }
305
+ return false;
306
+ }
307
+
308
+ /**
309
+ * Get the current status of a monitored signature
310
+ */
311
+ getStatus(signature: string): ConfirmationStatus | undefined {
312
+ const monitored = this.monitored.get(signature);
313
+ if (monitored) {
314
+ return monitored.status;
315
+ }
316
+
317
+ const cached = this.cache.get(signature);
318
+ if (cached) {
319
+ return cached.status;
320
+ }
321
+
322
+ return undefined;
323
+ }
324
+
325
+ /**
326
+ * Get cached result if available and not expired
327
+ */
328
+ getCachedResult(signature: string): ConfirmationResult | undefined {
329
+ const cached = this.cache.get(signature);
330
+ if (!cached) return undefined;
331
+
332
+ const age = Date.now() - cached.completedAt;
333
+ if (age > this.defaultConfig.cacheTtlMs) {
334
+ this.cache.delete(signature);
335
+ return undefined;
336
+ }
337
+
338
+ return cached;
339
+ }
340
+
341
+ /**
342
+ * Clear expired cache entries
343
+ */
344
+ clearExpiredCache(): number {
345
+ const now = Date.now();
346
+ let cleared = 0;
347
+
348
+ for (const [signature, result] of this.cache) {
349
+ if (now - result.completedAt > this.defaultConfig.cacheTtlMs) {
350
+ this.cache.delete(signature);
351
+ cleared++;
352
+ }
353
+ }
354
+
355
+ return cleared;
356
+ }
357
+
358
+ /**
359
+ * Get count of actively monitored signatures
360
+ */
361
+ getActiveCount(): number {
362
+ return this.monitored.size;
363
+ }
364
+
365
+ /**
366
+ * Get all actively monitored signatures
367
+ */
368
+ getActiveSignatures(): string[] {
369
+ return Array.from(this.monitored.keys());
370
+ }
371
+
372
+ private async waitForResult(monitored: MonitoredSignature): Promise<ConfirmationResult> {
373
+ return new Promise((resolve, reject) => {
374
+ // Add callback to be called when monitoring completes
375
+ const callback = (result: ConfirmationResult) => {
376
+ if (result.status === ConfirmationStatus.Failed ||
377
+ result.status === ConfirmationStatus.TimedOut) {
378
+ reject(new TradeError(500, result.error?.message || 'Confirmation failed'));
379
+ } else {
380
+ resolve(result);
381
+ }
382
+ };
383
+
384
+ monitored.callbacks.add(callback);
385
+
386
+ // Check if already completed
387
+ if (this.isTerminalStatus(monitored.status)) {
388
+ const result = this.createResult(monitored);
389
+ this.completeMonitoring(monitored, result);
390
+ }
391
+ });
392
+ }
393
+
394
+ private async pollAll(): Promise<void> {
395
+ const promises: Promise<void>[] = [];
396
+
397
+ for (const monitored of this.monitored.values()) {
398
+ // Skip if recently polled
399
+ const timeSinceLastPoll = Date.now() - monitored.lastPollTime;
400
+ if (timeSinceLastPoll < monitored.config.pollIntervalMs) {
401
+ continue;
402
+ }
403
+
404
+ promises.push(this.pollSignature(monitored));
405
+ }
406
+
407
+ await Promise.all(promises);
408
+
409
+ // Clean up completed monitors
410
+ this.cleanupCompleted();
411
+ }
412
+
413
+ private async pollSignature(monitored: MonitoredSignature): Promise<void> {
414
+ if (monitored.abortController.signal.aborted) {
415
+ return;
416
+ }
417
+
418
+ monitored.lastPollTime = Date.now();
419
+
420
+ try {
421
+ const status = await this.connection.getSignatureStatus(monitored.signature);
422
+
423
+ if (!status.value) {
424
+ // Transaction not found yet
425
+ this.updateStatus(monitored, ConfirmationStatus.NotFound);
426
+ return;
427
+ }
428
+
429
+ // Update slot information
430
+ if (status.value.slot) {
431
+ monitored.slot = status.value.slot;
432
+ }
433
+
434
+ // Check for errors
435
+ if (status.value.err) {
436
+ const error: TransactionError = {
437
+ code: -32002,
438
+ message: typeof status.value.err === 'string'
439
+ ? status.value.err
440
+ : JSON.stringify(status.value.err),
441
+ };
442
+ monitored.error = error;
443
+ this.updateStatus(monitored, ConfirmationStatus.Failed);
444
+
445
+ const result = this.createResult(monitored);
446
+ this.completeMonitoring(monitored, result);
447
+ return;
448
+ }
449
+
450
+ // Determine confirmation status
451
+ const confirmationStatus = status.value.confirmationStatus;
452
+ let newStatus = ConfirmationStatus.Processed;
453
+
454
+ if (confirmationStatus === 'finalized') {
455
+ newStatus = ConfirmationStatus.Finalized;
456
+ } else if (confirmationStatus === 'confirmed') {
457
+ newStatus = ConfirmationStatus.Confirmed;
458
+ } else if (confirmationStatus === 'processed') {
459
+ newStatus = ConfirmationStatus.Processed;
460
+ }
461
+
462
+ this.updateStatus(monitored, newStatus);
463
+
464
+ // Check if target commitment reached
465
+ if (this.isTargetReached(newStatus, monitored.config.commitment)) {
466
+ const result = this.createResult(monitored);
467
+ this.completeMonitoring(monitored, result);
468
+ }
469
+ } catch (error) {
470
+ // Retry on error
471
+ monitored.retryAttempts++;
472
+
473
+ if (monitored.retryAttempts >= monitored.config.maxRetries) {
474
+ monitored.error = {
475
+ code: -32003,
476
+ message: error instanceof Error ? error.message : 'Polling error',
477
+ };
478
+ this.updateStatus(monitored, ConfirmationStatus.Failed);
479
+
480
+ const result = this.createResult(monitored);
481
+ this.completeMonitoring(monitored, result);
482
+ }
483
+ }
484
+
485
+ this.reportProgress(monitored);
486
+ }
487
+
488
+ private setupWebSocket(): void {
489
+ // Note: Full WebSocket implementation would require signatureSubscribe
490
+ // This is a simplified version
491
+ try {
492
+ // WebSocket setup would go here
493
+ // this.wsSubscription = this.connection.onSignature(...);
494
+ } catch {
495
+ // Fall back to polling
496
+ }
497
+ }
498
+
499
+ private setupTimeout(monitored: MonitoredSignature): void {
500
+ setTimeout(() => {
501
+ if (this.monitored.has(monitored.signature) &&
502
+ !this.isTerminalStatus(monitored.status)) {
503
+ this.updateStatus(monitored, ConfirmationStatus.TimedOut);
504
+
505
+ const result = this.createResult(monitored);
506
+ this.completeMonitoring(monitored, result);
507
+ }
508
+ }, monitored.config.timeoutMs);
509
+ }
510
+
511
+ private updateStatus(monitored: MonitoredSignature, status: ConfirmationStatus): void {
512
+ monitored.status = status;
513
+
514
+ if (monitored.config.onStatusUpdate) {
515
+ const result = this.isTerminalStatus(status) ? this.createResult(monitored) : undefined;
516
+ monitored.config.onStatusUpdate(monitored.signature, status, result);
517
+ }
518
+ }
519
+
520
+ private reportProgress(monitored: MonitoredSignature): void {
521
+ if (monitored.config.onProgress) {
522
+ const elapsedMs = Date.now() - monitored.startTime;
523
+ const progress: ConfirmationProgress = {
524
+ status: monitored.status,
525
+ confirmations: this.getConfirmationsCount(monitored.status),
526
+ slot: monitored.slot,
527
+ elapsedMs,
528
+ estimatedRemainingMs: this.estimateRemainingTime(monitored),
529
+ retryAttempt: monitored.retryAttempts,
530
+ };
531
+ monitored.config.onProgress(monitored.signature, progress);
532
+ }
533
+ }
534
+
535
+ private getConfirmationsCount(status: ConfirmationStatus): number {
536
+ switch (status) {
537
+ case ConfirmationStatus.NotFound:
538
+ return 0;
539
+ case ConfirmationStatus.Processed:
540
+ return 1;
541
+ case ConfirmationStatus.Confirmed:
542
+ return 2;
543
+ case ConfirmationStatus.Finalized:
544
+ return 3;
545
+ default:
546
+ return 0;
547
+ }
548
+ }
549
+
550
+ private estimateRemainingTime(monitored: MonitoredSignature): number | undefined {
551
+ const targetConfirmations = this.getConfirmationsCount(
552
+ this.commitmentToStatus(monitored.config.commitment)
553
+ );
554
+ const currentConfirmations = this.getConfirmationsCount(monitored.status);
555
+
556
+ if (currentConfirmations >= targetConfirmations) {
557
+ return 0;
558
+ }
559
+
560
+ const elapsedMs = Date.now() - monitored.startTime;
561
+ const avgTimePerConfirmation = elapsedMs / Math.max(currentConfirmations, 1);
562
+ const remainingConfirmations = targetConfirmations - currentConfirmations;
563
+
564
+ return Math.round(avgTimePerConfirmation * remainingConfirmations);
565
+ }
566
+
567
+ private commitmentToStatus(commitment: Commitment): ConfirmationStatus {
568
+ switch (commitment) {
569
+ case 'processed':
570
+ return ConfirmationStatus.Processed;
571
+ case 'confirmed':
572
+ return ConfirmationStatus.Confirmed;
573
+ case 'finalized':
574
+ return ConfirmationStatus.Finalized;
575
+ default:
576
+ return ConfirmationStatus.Confirmed;
577
+ }
578
+ }
579
+
580
+ private isTargetReached(current: ConfirmationStatus, target: Commitment): boolean {
581
+ const levels = {
582
+ [ConfirmationStatus.NotFound]: 0,
583
+ [ConfirmationStatus.Processed]: 1,
584
+ [ConfirmationStatus.Confirmed]: 2,
585
+ [ConfirmationStatus.Finalized]: 3,
586
+ [ConfirmationStatus.Failed]: 4,
587
+ [ConfirmationStatus.TimedOut]: 4,
588
+ };
589
+
590
+ const currentLevel = levels[current];
591
+ const targetLevel = this.getConfirmationsCount(this.commitmentToStatus(target));
592
+
593
+ return currentLevel >= targetLevel;
594
+ }
595
+
596
+ private isTerminalStatus(status: ConfirmationStatus): boolean {
597
+ return [
598
+ ConfirmationStatus.Finalized,
599
+ ConfirmationStatus.Failed,
600
+ ConfirmationStatus.TimedOut,
601
+ ].includes(status);
602
+ }
603
+
604
+ private createResult(monitored: MonitoredSignature): ConfirmationResult {
605
+ const completedAt = Date.now();
606
+
607
+ return {
608
+ signature: monitored.signature,
609
+ status: monitored.status,
610
+ slot: monitored.slot,
611
+ blockhash: monitored.blockhash,
612
+ error: monitored.error,
613
+ confirmationTimeMs: completedAt - monitored.startTime,
614
+ retryAttempts: monitored.retryAttempts,
615
+ startedAt: monitored.startTime,
616
+ completedAt,
617
+ };
618
+ }
619
+
620
+ private completeMonitoring(monitored: MonitoredSignature, result: ConfirmationResult): void {
621
+ // Cache the result
622
+ if (monitored.config.enableCache) {
623
+ this.cache.set(monitored.signature, result);
624
+ }
625
+
626
+ // Notify callbacks
627
+ for (const callback of monitored.callbacks) {
628
+ try {
629
+ callback(result);
630
+ } catch {
631
+ // Ignore callback errors
632
+ }
633
+ }
634
+
635
+ // Clean up
636
+ monitored.callbacks.clear();
637
+ this.monitored.delete(monitored.signature);
638
+ }
639
+
640
+ private cleanupCompleted(): void {
641
+ const now = Date.now();
642
+ const maxAge = 300000; // 5 minutes
643
+
644
+ for (const [signature, monitored] of this.monitored) {
645
+ if (this.isTerminalStatus(monitored.status)) {
646
+ const age = now - monitored.startTime;
647
+ if (age > maxAge) {
648
+ this.monitored.delete(signature);
649
+ }
650
+ }
651
+ }
652
+ }
653
+ }
654
+
655
+ // ===== Convenience Functions =====
656
+
657
+ /**
658
+ * Create a new confirmation monitor
659
+ */
660
+ export function createConfirmationMonitor(
661
+ rpcUrl: string,
662
+ config?: Partial<ConfirmationConfig>
663
+ ): ConfirmationMonitor {
664
+ return new ConfirmationMonitor(rpcUrl, { ...defaultConfirmationConfig(), ...config });
665
+ }
666
+
667
+ /**
668
+ * Wait for a single transaction confirmation
669
+ */
670
+ export async function waitForConfirmation(
671
+ connection: Connection,
672
+ signature: string,
673
+ commitment: Commitment = 'confirmed',
674
+ timeoutMs: number = 60000
675
+ ): Promise<ConfirmationResult> {
676
+ const monitor = new ConfirmationMonitor(connection.rpcEndpoint, {
677
+ ...defaultConfirmationConfig(),
678
+ commitment,
679
+ timeoutMs,
680
+ });
681
+
682
+ monitor.start();
683
+
684
+ try {
685
+ return await monitor.monitor(signature);
686
+ } finally {
687
+ monitor.stop();
688
+ }
689
+ }
690
+
691
+ /**
692
+ * Check if a transaction is confirmed
693
+ */
694
+ export async function isConfirmed(
695
+ connection: Connection,
696
+ signature: string,
697
+ commitment: Commitment = 'confirmed'
698
+ ): Promise<boolean> {
699
+ try {
700
+ const status = await connection.getSignatureStatus(signature);
701
+ if (!status.value) return false;
702
+
703
+ const levels = ['processed', 'confirmed', 'finalized'];
704
+ const targetIndex = levels.indexOf(commitment);
705
+ const currentIndex = levels.indexOf(status.value.confirmationStatus || 'processed');
706
+
707
+ return currentIndex >= targetIndex && !status.value.err;
708
+ } catch {
709
+ return false;
710
+ }
711
+ }