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.
- package/README.md +390 -0
- package/dist/chunk-MMQAMIKR.mjs +3735 -0
- package/dist/chunk-NEZDFAYA.mjs +7744 -0
- package/dist/clients-VITWK7B6.mjs +1370 -0
- package/dist/index-1BK_FXsW.d.mts +2327 -0
- package/dist/index-1BK_FXsW.d.ts +2327 -0
- package/dist/index.d.mts +2659 -0
- package/dist/index.d.ts +2659 -0
- package/dist/index.js +13265 -0
- package/dist/index.mjs +562 -0
- package/dist/perf/index.d.mts +2 -0
- package/dist/perf/index.d.ts +2 -0
- package/dist/perf/index.js +3742 -0
- package/dist/perf/index.mjs +214 -0
- package/package.json +101 -0
- package/src/__tests__/complete_sdk.test.ts +354 -0
- package/src/__tests__/hotpath.test.ts +486 -0
- package/src/__tests__/nonce.test.ts +45 -0
- package/src/__tests__/sdk.test.ts +425 -0
- package/src/address-lookup/index.ts +197 -0
- package/src/cache/cache.ts +308 -0
- package/src/calc/index.ts +1058 -0
- package/src/calc/pumpfun.ts +124 -0
- package/src/common/bonding_curve.ts +272 -0
- package/src/common/compute-budget.ts +148 -0
- package/src/common/confirm-any-signature.ts +184 -0
- package/src/common/fast-timing.ts +481 -0
- package/src/common/fast_fn.ts +150 -0
- package/src/common/gas-fee-strategy.ts +253 -0
- package/src/common/map-pool.ts +23 -0
- package/src/common/nonce.ts +40 -0
- package/src/common/sdk-log.ts +460 -0
- package/src/common/seed.ts +381 -0
- package/src/common/spl-token.ts +578 -0
- package/src/common/subscription-handle.ts +644 -0
- package/src/common/trading-utils.ts +239 -0
- package/src/common/wsol-manager.ts +325 -0
- package/src/compute/compute_budget_manager.ts +187 -0
- package/src/compute/index.ts +21 -0
- package/src/constants/index.ts +96 -0
- package/src/execution/execution.ts +532 -0
- package/src/execution/index.ts +42 -0
- package/src/hotpath/executor.ts +464 -0
- package/src/hotpath/index.ts +64 -0
- package/src/hotpath/state.ts +435 -0
- package/src/index.ts +2117 -0
- package/src/instruction/bonk_builder.ts +730 -0
- package/src/instruction/index.ts +24 -0
- package/src/instruction/meteora_damm_v2_builder.ts +509 -0
- package/src/instruction/pumpfun_builder.ts +1183 -0
- package/src/instruction/pumpswap.ts +1123 -0
- package/src/instruction/raydium_amm_v4_builder.ts +692 -0
- package/src/instruction/raydium_cpmm_builder.ts +795 -0
- package/src/middleware/traits.ts +407 -0
- package/src/params/index.ts +483 -0
- package/src/perf/compiler-optimization.ts +529 -0
- package/src/perf/hardware.ts +631 -0
- package/src/perf/index.ts +9 -0
- package/src/perf/kernel-bypass.ts +656 -0
- package/src/perf/protocol.ts +682 -0
- package/src/perf/realtime.ts +592 -0
- package/src/perf/simd.ts +668 -0
- package/src/perf/syscall-bypass.ts +331 -0
- package/src/perf/ultra-low-latency.ts +505 -0
- package/src/perf/zero-copy.ts +589 -0
- package/src/pool/pool.ts +294 -0
- package/src/rpc/client.ts +345 -0
- package/src/sdk-errors.ts +13 -0
- package/src/security/index.ts +26 -0
- package/src/security/secure-key.ts +303 -0
- package/src/security/validators.ts +281 -0
- package/src/seed/pda.ts +262 -0
- package/src/serialization/index.ts +28 -0
- package/src/serialization/serialization.ts +288 -0
- package/src/swqos/clients.ts +1754 -0
- package/src/swqos/index.ts +50 -0
- package/src/swqos/providers.ts +1707 -0
- package/src/trading/core/async-executor.ts +702 -0
- package/src/trading/core/confirmation-monitor.ts +711 -0
- package/src/trading/core/index.ts +82 -0
- package/src/trading/core/retry-handler.ts +683 -0
- package/src/trading/core/transaction-pool.ts +780 -0
- package/src/trading/executor.ts +385 -0
- package/src/trading/factory.ts +282 -0
- package/src/trading/index.ts +30 -0
- package/src/types.ts +8 -0
- package/src/utils/index.ts +155 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hot Path Executor for Sol Trade SDK
|
|
3
|
+
*
|
|
4
|
+
* Executes trades with ZERO RPC calls in the hot path.
|
|
5
|
+
* All data must be prefetched before execution.
|
|
6
|
+
*
|
|
7
|
+
* Key principle: Prepare everything, then execute with minimal latency.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Connection, PublicKey, Transaction, TransactionInstruction } from '@solana/web3.js';
|
|
11
|
+
import {
|
|
12
|
+
HotPathState,
|
|
13
|
+
HotPathConfig,
|
|
14
|
+
TradingContext,
|
|
15
|
+
StaleBlockhashError,
|
|
16
|
+
defaultHotPathConfig,
|
|
17
|
+
} from './state';
|
|
18
|
+
import { SwqosClient } from '../swqos/clients';
|
|
19
|
+
import { SwqosType, TradeType } from '../index';
|
|
20
|
+
|
|
21
|
+
// ===== Types =====
|
|
22
|
+
|
|
23
|
+
export interface ExecuteOptions {
|
|
24
|
+
parallelSubmit: boolean;
|
|
25
|
+
timeoutMs: number;
|
|
26
|
+
skipBlockhashValidation: boolean;
|
|
27
|
+
maxRetries: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function defaultExecuteOptions(): ExecuteOptions {
|
|
31
|
+
return {
|
|
32
|
+
parallelSubmit: true,
|
|
33
|
+
timeoutMs: 10000,
|
|
34
|
+
skipBlockhashValidation: false,
|
|
35
|
+
maxRetries: 3,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ExecuteResult {
|
|
40
|
+
signature: string;
|
|
41
|
+
success: boolean;
|
|
42
|
+
error?: string;
|
|
43
|
+
latencyMs: number;
|
|
44
|
+
swqosType?: SwqosType;
|
|
45
|
+
blockhashUsed: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface GasFeeConfig {
|
|
49
|
+
computeUnitLimit: number;
|
|
50
|
+
computeUnitPrice: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ===== Metrics =====
|
|
54
|
+
|
|
55
|
+
export class HotPathMetrics {
|
|
56
|
+
private totalTrades = 0;
|
|
57
|
+
private successTrades = 0;
|
|
58
|
+
private failedTrades = 0;
|
|
59
|
+
private totalLatencyMs = 0;
|
|
60
|
+
|
|
61
|
+
record(success: boolean, latencyMs: number): void {
|
|
62
|
+
this.totalTrades++;
|
|
63
|
+
if (success) {
|
|
64
|
+
this.successTrades++;
|
|
65
|
+
} else {
|
|
66
|
+
this.failedTrades++;
|
|
67
|
+
}
|
|
68
|
+
this.totalLatencyMs += latencyMs;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getStats(): {
|
|
72
|
+
totalTrades: number;
|
|
73
|
+
successTrades: number;
|
|
74
|
+
failedTrades: number;
|
|
75
|
+
avgLatencyMs: number;
|
|
76
|
+
} {
|
|
77
|
+
return {
|
|
78
|
+
totalTrades: this.totalTrades,
|
|
79
|
+
successTrades: this.successTrades,
|
|
80
|
+
failedTrades: this.failedTrades,
|
|
81
|
+
avgLatencyMs: this.totalTrades > 0 ? this.totalLatencyMs / this.totalTrades : 0,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ===== Hot Path Executor =====
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Executes trades with ZERO RPC calls in the hot path.
|
|
90
|
+
*
|
|
91
|
+
* Usage:
|
|
92
|
+
* 1. Create executor with RPC connection
|
|
93
|
+
* 2. Call start() to begin background prefetching
|
|
94
|
+
* 3. Prefetch required accounts/pools BEFORE trading
|
|
95
|
+
* 4. Build transaction with prefetched blockhash
|
|
96
|
+
* 5. Execute - no RPC calls during this phase
|
|
97
|
+
*/
|
|
98
|
+
export class HotPathExecutor {
|
|
99
|
+
private state: HotPathState;
|
|
100
|
+
private config: HotPathConfig;
|
|
101
|
+
private connection: Connection;
|
|
102
|
+
|
|
103
|
+
// SWQoS clients for transaction submission
|
|
104
|
+
private swqosClients: Map<SwqosType, SwqosClient> = new Map();
|
|
105
|
+
|
|
106
|
+
// Metrics
|
|
107
|
+
private metrics = new HotPathMetrics();
|
|
108
|
+
|
|
109
|
+
constructor(connection: Connection, config?: Partial<HotPathConfig>) {
|
|
110
|
+
this.config = { ...defaultHotPathConfig(), ...config };
|
|
111
|
+
this.connection = connection;
|
|
112
|
+
this.state = new HotPathState(connection, config);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Add a SWQoS client for transaction submission
|
|
117
|
+
*/
|
|
118
|
+
addSwqosClient(client: SwqosClient): void {
|
|
119
|
+
this.swqosClients.set(client.getSwqosType(), client);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Remove a SWQoS client
|
|
124
|
+
*/
|
|
125
|
+
removeSwqosClient(swqosType: SwqosType): void {
|
|
126
|
+
this.swqosClients.delete(swqosType);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get SWQoS client by type
|
|
131
|
+
*/
|
|
132
|
+
getSwqosClient(swqosType: SwqosType): SwqosClient | undefined {
|
|
133
|
+
return this.swqosClients.get(swqosType);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Start background prefetching
|
|
138
|
+
*/
|
|
139
|
+
async start(): Promise<void> {
|
|
140
|
+
await this.state.start();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Stop background prefetching
|
|
145
|
+
*/
|
|
146
|
+
stop(): void {
|
|
147
|
+
this.state.stop();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get hot path state for external access
|
|
152
|
+
*/
|
|
153
|
+
getState(): HotPathState {
|
|
154
|
+
return this.state;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Check if executor is ready for hot path execution
|
|
159
|
+
*/
|
|
160
|
+
isReady(): boolean {
|
|
161
|
+
return this.state.isDataFresh() && this.swqosClients.size > 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Wait until executor is ready
|
|
166
|
+
*/
|
|
167
|
+
async waitForReady(
|
|
168
|
+
checkIntervalMs: number = 100,
|
|
169
|
+
timeoutMs: number = 30000
|
|
170
|
+
): Promise<boolean> {
|
|
171
|
+
const startTime = Date.now();
|
|
172
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
173
|
+
if (this.isReady()) {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
await this.sleep(checkIntervalMs);
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Prefetch accounts - call BEFORE hot path execution
|
|
183
|
+
*/
|
|
184
|
+
async prefetchAccounts(pubkeys: string[]): Promise<void> {
|
|
185
|
+
await this.state.prefetchAccounts(pubkeys);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Create trading context with prefetched data - NO RPC
|
|
190
|
+
*/
|
|
191
|
+
createTradingContext(payer: string): TradingContext {
|
|
192
|
+
return new TradingContext(this.state, payer);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Execute a pre-signed transaction - NO RPC CALLS
|
|
197
|
+
*
|
|
198
|
+
* Transaction must already be signed with valid blockhash.
|
|
199
|
+
* All state should be prefetched before calling this.
|
|
200
|
+
*/
|
|
201
|
+
async execute(
|
|
202
|
+
tradeType: TradeType,
|
|
203
|
+
transactionBytes: Buffer,
|
|
204
|
+
opts: ExecuteOptions = defaultExecuteOptions()
|
|
205
|
+
): Promise<ExecuteResult> {
|
|
206
|
+
const startTime = Date.now();
|
|
207
|
+
|
|
208
|
+
// Validate blockhash is fresh (no RPC, just check cache age)
|
|
209
|
+
if (!opts.skipBlockhashValidation && !this.state.isDataFresh()) {
|
|
210
|
+
return {
|
|
211
|
+
signature: '',
|
|
212
|
+
success: false,
|
|
213
|
+
error: 'Stale blockhash - prefetch required',
|
|
214
|
+
latencyMs: 0,
|
|
215
|
+
blockhashUsed: '',
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Get current blockhash for tracking
|
|
220
|
+
const blockhashData = this.state.getBlockhash();
|
|
221
|
+
const blockhashUsed = blockhashData?.blockhash || '';
|
|
222
|
+
|
|
223
|
+
// Get clients
|
|
224
|
+
const clients = Array.from(this.swqosClients.values());
|
|
225
|
+
if (clients.length === 0) {
|
|
226
|
+
return {
|
|
227
|
+
signature: '',
|
|
228
|
+
success: false,
|
|
229
|
+
error: 'No SWQoS clients configured',
|
|
230
|
+
latencyMs: 0,
|
|
231
|
+
blockhashUsed,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Submit transaction
|
|
236
|
+
let result: ExecuteResult;
|
|
237
|
+
if (opts.parallelSubmit && clients.length > 1) {
|
|
238
|
+
result = await this.executeParallel(tradeType, transactionBytes, clients, opts);
|
|
239
|
+
} else {
|
|
240
|
+
result = await this.executeSequential(tradeType, transactionBytes, clients, opts);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
result.latencyMs = Date.now() - startTime;
|
|
244
|
+
result.blockhashUsed = blockhashUsed;
|
|
245
|
+
|
|
246
|
+
// Update metrics
|
|
247
|
+
this.metrics.record(result.success, result.latencyMs);
|
|
248
|
+
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Submit to all SWQoS clients in parallel - NO RPC
|
|
254
|
+
*/
|
|
255
|
+
private async executeParallel(
|
|
256
|
+
tradeType: TradeType,
|
|
257
|
+
txBytes: Buffer,
|
|
258
|
+
clients: SwqosClient[],
|
|
259
|
+
opts: ExecuteOptions
|
|
260
|
+
): Promise<ExecuteResult> {
|
|
261
|
+
const submitToClient = async (client: SwqosClient): Promise<ExecuteResult> => {
|
|
262
|
+
try {
|
|
263
|
+
const signature = await Promise.race([
|
|
264
|
+
client.sendTransaction(tradeType, txBytes, false),
|
|
265
|
+
new Promise<never>((_, reject) =>
|
|
266
|
+
setTimeout(() => reject(new Error('Timeout')), opts.timeoutMs)
|
|
267
|
+
),
|
|
268
|
+
]);
|
|
269
|
+
return {
|
|
270
|
+
signature,
|
|
271
|
+
success: true,
|
|
272
|
+
swqosType: client.getSwqosType(),
|
|
273
|
+
latencyMs: 0,
|
|
274
|
+
blockhashUsed: '',
|
|
275
|
+
};
|
|
276
|
+
} catch (error) {
|
|
277
|
+
return {
|
|
278
|
+
signature: '',
|
|
279
|
+
success: false,
|
|
280
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
281
|
+
swqosType: client.getSwqosType(),
|
|
282
|
+
latencyMs: 0,
|
|
283
|
+
blockhashUsed: '',
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Race all submissions - first success wins
|
|
289
|
+
const promises = clients.map(submitToClient);
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
// Use Promise.any for first-success-wins
|
|
293
|
+
const result = await Promise.any(promises);
|
|
294
|
+
return result;
|
|
295
|
+
} catch {
|
|
296
|
+
// All failed - aggregate errors
|
|
297
|
+
const results = await Promise.allSettled(promises);
|
|
298
|
+
const errors = results
|
|
299
|
+
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
|
|
300
|
+
.map((r) => r.reason);
|
|
301
|
+
return {
|
|
302
|
+
signature: '',
|
|
303
|
+
success: false,
|
|
304
|
+
error: `All parallel submissions failed: ${errors.join(', ')}`,
|
|
305
|
+
latencyMs: 0,
|
|
306
|
+
blockhashUsed: '',
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Submit to SWQoS clients sequentially - NO RPC
|
|
313
|
+
*/
|
|
314
|
+
private async executeSequential(
|
|
315
|
+
tradeType: TradeType,
|
|
316
|
+
txBytes: Buffer,
|
|
317
|
+
clients: SwqosClient[],
|
|
318
|
+
opts: ExecuteOptions
|
|
319
|
+
): Promise<ExecuteResult> {
|
|
320
|
+
let lastError = 'No clients available';
|
|
321
|
+
|
|
322
|
+
for (let retry = 0; retry < opts.maxRetries; retry++) {
|
|
323
|
+
for (const client of clients) {
|
|
324
|
+
try {
|
|
325
|
+
const signature = await Promise.race([
|
|
326
|
+
client.sendTransaction(tradeType, txBytes, false),
|
|
327
|
+
new Promise<never>((_, reject) =>
|
|
328
|
+
setTimeout(() => reject(new Error('Timeout')), opts.timeoutMs)
|
|
329
|
+
),
|
|
330
|
+
]);
|
|
331
|
+
return {
|
|
332
|
+
signature,
|
|
333
|
+
success: true,
|
|
334
|
+
swqosType: client.getSwqosType(),
|
|
335
|
+
latencyMs: 0,
|
|
336
|
+
blockhashUsed: '',
|
|
337
|
+
};
|
|
338
|
+
} catch (error) {
|
|
339
|
+
lastError = error instanceof Error ? error.message : 'Unknown error';
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
signature: '',
|
|
346
|
+
success: false,
|
|
347
|
+
error: `All sequential submissions failed after ${opts.maxRetries} retries: ${lastError}`,
|
|
348
|
+
latencyMs: 0,
|
|
349
|
+
blockhashUsed: '',
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Execute multiple transactions in parallel
|
|
355
|
+
*/
|
|
356
|
+
async executeMultiple(
|
|
357
|
+
tradeType: TradeType,
|
|
358
|
+
transactions: Buffer[],
|
|
359
|
+
opts: ExecuteOptions = defaultExecuteOptions()
|
|
360
|
+
): Promise<ExecuteResult[]> {
|
|
361
|
+
return Promise.all((transactions).map((tx) => this.execute(tradeType, tx, opts)));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Get cached blockhash - NO RPC CALL
|
|
366
|
+
* Use this to build transactions before execution
|
|
367
|
+
*/
|
|
368
|
+
getBlockhash(): { blockhash: string; lastValidBlockHeight: number } | null {
|
|
369
|
+
return this.state.getBlockhash();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get execution metrics
|
|
374
|
+
*/
|
|
375
|
+
getMetrics(): ReturnType<HotPathMetrics['getStats']> {
|
|
376
|
+
return this.metrics.getStats();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
private sleep(ms: number): Promise<void> {
|
|
380
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ===== Transaction Builder Helper =====
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Builds transactions using prefetched data - NO RPC CALLS
|
|
388
|
+
*
|
|
389
|
+
* Use this to construct transactions before hot path execution.
|
|
390
|
+
*/
|
|
391
|
+
export class TransactionBuilder {
|
|
392
|
+
constructor(private executor: HotPathExecutor) {}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Build a transaction using prefetched blockhash - NO RPC
|
|
396
|
+
*/
|
|
397
|
+
async buildTransaction(
|
|
398
|
+
payer: PublicKey,
|
|
399
|
+
instructions: TransactionInstruction[],
|
|
400
|
+
signers: any[], // Keypair[]
|
|
401
|
+
gasConfig?: GasFeeConfig
|
|
402
|
+
): Promise<Transaction | null> {
|
|
403
|
+
// Get blockhash from cache
|
|
404
|
+
const blockhashData = this.executor.getBlockhash();
|
|
405
|
+
if (!blockhashData) {
|
|
406
|
+
throw new StaleBlockhashError('Stale blockhash - prefetch required');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Build transaction
|
|
410
|
+
const tx = new Transaction();
|
|
411
|
+
|
|
412
|
+
// Add compute budget instructions if gas config provided
|
|
413
|
+
if (gasConfig) {
|
|
414
|
+
// Add compute budget instructions
|
|
415
|
+
// These would use the compute budget program
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Add main instructions
|
|
419
|
+
tx.add(...instructions);
|
|
420
|
+
|
|
421
|
+
// Set blockhash and payer
|
|
422
|
+
tx.recentBlockhash = blockhashData.blockhash;
|
|
423
|
+
tx.feePayer = payer;
|
|
424
|
+
|
|
425
|
+
// Sign transaction
|
|
426
|
+
tx.sign(...signers);
|
|
427
|
+
|
|
428
|
+
return tx;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// ===== Convenience Factory =====
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Create a hot path executor with default configuration.
|
|
436
|
+
*
|
|
437
|
+
* Usage:
|
|
438
|
+
* const executor = createHotPathExecutor(
|
|
439
|
+
* connection,
|
|
440
|
+
* [jitoClient, bloxrouteClient]
|
|
441
|
+
* );
|
|
442
|
+
* await executor.start();
|
|
443
|
+
*
|
|
444
|
+
* // Prefetch required data
|
|
445
|
+
* await executor.prefetchAccounts([tokenAccountPubkey]);
|
|
446
|
+
*
|
|
447
|
+
* // Now ready for hot path execution
|
|
448
|
+
* const result = await executor.execute('buy', txBytes);
|
|
449
|
+
*/
|
|
450
|
+
export function createHotPathExecutor(
|
|
451
|
+
connection: Connection,
|
|
452
|
+
swqosClients?: SwqosClient[],
|
|
453
|
+
config?: Partial<HotPathConfig>
|
|
454
|
+
): HotPathExecutor {
|
|
455
|
+
const executor = new HotPathExecutor(connection, config);
|
|
456
|
+
|
|
457
|
+
if (swqosClients) {
|
|
458
|
+
for (const client of swqosClients) {
|
|
459
|
+
executor.addSwqosClient(client);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return executor;
|
|
464
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hot Path Module for Sol Trade SDK
|
|
3
|
+
*
|
|
4
|
+
* Provides optimized trading execution with ZERO RPC calls in the hot path.
|
|
5
|
+
* All data is prefetched before trading to minimize latency.
|
|
6
|
+
*
|
|
7
|
+
* Key Components:
|
|
8
|
+
* - HotPathState: Manages prefetched blockchain state
|
|
9
|
+
* - HotPathExecutor: Executes trades using cached data only
|
|
10
|
+
* - TradingContext: Context object for a single trade with all required data
|
|
11
|
+
*
|
|
12
|
+
* Usage:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const executor = new HotPathExecutor(connection);
|
|
15
|
+
* await executor.start();
|
|
16
|
+
*
|
|
17
|
+
* // Prefetch required data BEFORE trading
|
|
18
|
+
* await executor.prefetchAccounts([tokenAccountPubkey]);
|
|
19
|
+
*
|
|
20
|
+
* // Build transaction with cached blockhash
|
|
21
|
+
* const blockhash = executor.getBlockhash();
|
|
22
|
+
* // ... build transaction ...
|
|
23
|
+
*
|
|
24
|
+
* // Execute - NO RPC calls during this phase
|
|
25
|
+
* const result = await executor.execute('buy', txBytes);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
export {
|
|
30
|
+
// State management
|
|
31
|
+
HotPathState,
|
|
32
|
+
TradingContext,
|
|
33
|
+
defaultHotPathConfig,
|
|
34
|
+
} from './state';
|
|
35
|
+
|
|
36
|
+
export type {
|
|
37
|
+
HotPathConfig,
|
|
38
|
+
PrefetchedData,
|
|
39
|
+
AccountState,
|
|
40
|
+
PoolState,
|
|
41
|
+
} from './state';
|
|
42
|
+
|
|
43
|
+
export type {
|
|
44
|
+
ExecuteOptions,
|
|
45
|
+
ExecuteResult,
|
|
46
|
+
GasFeeConfig,
|
|
47
|
+
} from './executor';
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
// Execution
|
|
51
|
+
HotPathExecutor,
|
|
52
|
+
HotPathMetrics,
|
|
53
|
+
TransactionBuilder,
|
|
54
|
+
defaultExecuteOptions,
|
|
55
|
+
createHotPathExecutor,
|
|
56
|
+
} from './executor';
|
|
57
|
+
|
|
58
|
+
export {
|
|
59
|
+
// Errors
|
|
60
|
+
HotPathError,
|
|
61
|
+
StaleBlockhashError,
|
|
62
|
+
MissingAccountError,
|
|
63
|
+
ContextExpiredError,
|
|
64
|
+
} from './state';
|