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,682 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol Optimization Module for Sol Trade SDK
|
|
3
|
+
* Provides transaction optimization, compute budget management, and builder patterns.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ComputeBudgetProgram, PublicKey, TransactionInstruction } from '@solana/web3.js';
|
|
7
|
+
|
|
8
|
+
// ===== Types =====
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Transaction configuration
|
|
12
|
+
*/
|
|
13
|
+
export interface TransactionConfig {
|
|
14
|
+
/** Compute unit limit */
|
|
15
|
+
computeUnitLimit: number;
|
|
16
|
+
/** Compute unit price (micro-lamports) */
|
|
17
|
+
computeUnitPrice: number;
|
|
18
|
+
/** Priority fee in lamports */
|
|
19
|
+
priorityFee: number;
|
|
20
|
+
/** Enable dynamic compute budget */
|
|
21
|
+
dynamicComputeBudget: boolean;
|
|
22
|
+
/** Enable instruction packing */
|
|
23
|
+
packInstructions: boolean;
|
|
24
|
+
/** Maximum transaction size */
|
|
25
|
+
maxTransactionSize: number;
|
|
26
|
+
/** Enable address lookup tables */
|
|
27
|
+
useAddressLookupTables: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Default transaction configuration
|
|
32
|
+
*/
|
|
33
|
+
export function defaultTransactionConfig(): TransactionConfig {
|
|
34
|
+
return {
|
|
35
|
+
computeUnitLimit: 200000,
|
|
36
|
+
computeUnitPrice: 100000,
|
|
37
|
+
priorityFee: 100000,
|
|
38
|
+
dynamicComputeBudget: true,
|
|
39
|
+
packInstructions: true,
|
|
40
|
+
maxTransactionSize: 1232, // Solana transaction size limit
|
|
41
|
+
useAddressLookupTables: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Compute budget statistics
|
|
47
|
+
*/
|
|
48
|
+
export interface ComputeBudgetStats {
|
|
49
|
+
totalComputeUsed: number;
|
|
50
|
+
totalComputeLimit: number;
|
|
51
|
+
averageComputePerInstruction: number;
|
|
52
|
+
estimatedFee: number;
|
|
53
|
+
efficiency: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Instruction group for batching
|
|
58
|
+
*/
|
|
59
|
+
export interface InstructionGroup {
|
|
60
|
+
instructions: TransactionInstruction[];
|
|
61
|
+
computeEstimate: number;
|
|
62
|
+
priority: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Transaction optimization result
|
|
67
|
+
*/
|
|
68
|
+
export interface OptimizationResult {
|
|
69
|
+
instructions: TransactionInstruction[];
|
|
70
|
+
computeLimit: number;
|
|
71
|
+
computePrice: number;
|
|
72
|
+
estimatedSize: number;
|
|
73
|
+
optimizations: string[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ===== Transaction Builder =====
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* High-performance transaction builder with optimization.
|
|
80
|
+
* Constructs optimized Solana transactions for trading.
|
|
81
|
+
*/
|
|
82
|
+
export class TransactionBuilder {
|
|
83
|
+
private instructions: TransactionInstruction[] = [];
|
|
84
|
+
private config: TransactionConfig;
|
|
85
|
+
private computeEstimates: Map<string, number> = new Map();
|
|
86
|
+
private signers: PublicKey[] = [];
|
|
87
|
+
|
|
88
|
+
constructor(config: TransactionConfig = defaultTransactionConfig()) {
|
|
89
|
+
this.config = config;
|
|
90
|
+
this.initializeComputeEstimates();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Initialize default compute estimates for common instructions
|
|
95
|
+
*/
|
|
96
|
+
private initializeComputeEstimates(): void {
|
|
97
|
+
// Common instruction compute costs (approximate)
|
|
98
|
+
this.computeEstimates.set('transfer', 450);
|
|
99
|
+
this.computeEstimates.set('createAccount', 2500);
|
|
100
|
+
this.computeEstimates.set('createATA', 3500);
|
|
101
|
+
this.computeEstimates.set('closeAccount', 2500);
|
|
102
|
+
this.computeEstimates.set('syncNative', 500);
|
|
103
|
+
this.computeEstimates.set('setComputeUnitLimit', 100);
|
|
104
|
+
this.computeEstimates.set('setComputeUnitPrice', 100);
|
|
105
|
+
this.computeEstimates.set('pumpFunBuy', 45000);
|
|
106
|
+
this.computeEstimates.set('pumpFunSell', 40000);
|
|
107
|
+
this.computeEstimates.set('pumpSwapBuy', 50000);
|
|
108
|
+
this.computeEstimates.set('pumpSwapSell', 45000);
|
|
109
|
+
this.computeEstimates.set('raydiumSwap', 55000);
|
|
110
|
+
this.computeEstimates.set('meteoraSwap', 60000);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Add an instruction to the transaction
|
|
115
|
+
*/
|
|
116
|
+
addInstruction(
|
|
117
|
+
instruction: TransactionInstruction,
|
|
118
|
+
computeEstimate?: number,
|
|
119
|
+
priority: number = 0
|
|
120
|
+
): this {
|
|
121
|
+
this.instructions.push(instruction);
|
|
122
|
+
|
|
123
|
+
// Track signer if new
|
|
124
|
+
for (const key of instruction.keys) {
|
|
125
|
+
if (key.isSigner && !this.signers.some(s => s.equals(key.pubkey))) {
|
|
126
|
+
this.signers.push(key.pubkey);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Add multiple instructions
|
|
135
|
+
*/
|
|
136
|
+
addInstructions(instructions: TransactionInstruction[]): this {
|
|
137
|
+
for (const ix of instructions) {
|
|
138
|
+
this.addInstruction(ix);
|
|
139
|
+
}
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Add compute budget instructions
|
|
145
|
+
*/
|
|
146
|
+
addComputeBudget(units: number, price: number): this {
|
|
147
|
+
this.instructions.unshift(
|
|
148
|
+
ComputeBudgetProgram.setComputeUnitLimit({ units }),
|
|
149
|
+
ComputeBudgetProgram.setComputeUnitPrice({ microLamports: price })
|
|
150
|
+
);
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Estimate total compute units
|
|
156
|
+
*/
|
|
157
|
+
estimateCompute(): number {
|
|
158
|
+
let total = 0;
|
|
159
|
+
|
|
160
|
+
for (const ix of this.instructions) {
|
|
161
|
+
const estimate = this.computeEstimates.get(ix.programId.toBase58()) || 3000;
|
|
162
|
+
total += estimate;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Add overhead for compute budget instructions
|
|
166
|
+
total += 200;
|
|
167
|
+
|
|
168
|
+
return total;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Build optimized transaction instructions
|
|
173
|
+
*/
|
|
174
|
+
build(): OptimizationResult {
|
|
175
|
+
let optimizedInstructions = [...this.instructions];
|
|
176
|
+
const optimizations: string[] = [];
|
|
177
|
+
|
|
178
|
+
// Apply packing optimization
|
|
179
|
+
if (this.config.packInstructions) {
|
|
180
|
+
optimizedInstructions = this.packInstructions(optimizedInstructions);
|
|
181
|
+
optimizations.push('instruction_packing');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Calculate optimal compute budget
|
|
185
|
+
const computeEstimate = this.estimateCompute();
|
|
186
|
+
let computeLimit = this.config.computeUnitLimit;
|
|
187
|
+
|
|
188
|
+
if (this.config.dynamicComputeBudget) {
|
|
189
|
+
computeLimit = this.calculateOptimalComputeLimit(computeEstimate);
|
|
190
|
+
optimizations.push('dynamic_compute_budget');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Calculate optimal price
|
|
194
|
+
const computePrice = this.calculateOptimalPrice();
|
|
195
|
+
|
|
196
|
+
// Estimate transaction size
|
|
197
|
+
const estimatedSize = this.estimateTransactionSize(optimizedInstructions);
|
|
198
|
+
|
|
199
|
+
// Add compute budget instructions at the beginning
|
|
200
|
+
optimizedInstructions = this.addComputeBudgetInstructions(
|
|
201
|
+
optimizedInstructions,
|
|
202
|
+
computeLimit,
|
|
203
|
+
computePrice
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
instructions: optimizedInstructions,
|
|
208
|
+
computeLimit,
|
|
209
|
+
computePrice,
|
|
210
|
+
estimatedSize,
|
|
211
|
+
optimizations,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Build and return only the instructions (without compute budget)
|
|
217
|
+
*/
|
|
218
|
+
buildInstructions(): TransactionInstruction[] {
|
|
219
|
+
return [...this.instructions];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Clear all instructions
|
|
224
|
+
*/
|
|
225
|
+
clear(): this {
|
|
226
|
+
this.instructions = [];
|
|
227
|
+
this.signers = [];
|
|
228
|
+
return this;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get current instruction count
|
|
233
|
+
*/
|
|
234
|
+
getInstructionCount(): number {
|
|
235
|
+
return this.instructions.length;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get current signer count
|
|
240
|
+
*/
|
|
241
|
+
getSignerCount(): number {
|
|
242
|
+
return this.signers.length;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
private packInstructions(
|
|
246
|
+
instructions: TransactionInstruction[]
|
|
247
|
+
): TransactionInstruction[] {
|
|
248
|
+
// Sort instructions by priority and dependencies
|
|
249
|
+
// This is a simplified implementation
|
|
250
|
+
return instructions;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private calculateOptimalComputeLimit(estimate: number): number {
|
|
254
|
+
// Add 20% buffer for safety
|
|
255
|
+
const withBuffer = Math.ceil(estimate * 1.2);
|
|
256
|
+
|
|
257
|
+
// Round up to nearest 10000
|
|
258
|
+
return Math.ceil(withBuffer / 10000) * 10000;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
private calculateOptimalPrice(): number {
|
|
262
|
+
// Base price from config
|
|
263
|
+
return this.config.computeUnitPrice;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
private estimateTransactionSize(instructions: TransactionInstruction[]): number {
|
|
267
|
+
// Rough estimation: signatures + message header + accounts + instructions
|
|
268
|
+
let size = 64; // One signature
|
|
269
|
+
size += 3; // Message header
|
|
270
|
+
size += 32 * (this.signers.length + 1); // Account keys
|
|
271
|
+
|
|
272
|
+
for (const ix of instructions) {
|
|
273
|
+
size += 1; // Program ID index
|
|
274
|
+
size += 1; // Account count
|
|
275
|
+
size += ix.keys.length * 33; // Account meta (pubkey + flags)
|
|
276
|
+
size += 2; // Data length
|
|
277
|
+
size += ix.data.length; // Instruction data
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return size;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private addComputeBudgetInstructions(
|
|
284
|
+
instructions: TransactionInstruction[],
|
|
285
|
+
limit: number,
|
|
286
|
+
price: number
|
|
287
|
+
): TransactionInstruction[] {
|
|
288
|
+
// In a real implementation, this would add:
|
|
289
|
+
// 1. ComputeBudgetProgram.setComputeUnitLimit
|
|
290
|
+
// 2. ComputeBudgetProgram.setComputeUnitPrice
|
|
291
|
+
// For now, we return the instructions as-is
|
|
292
|
+
return instructions;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ===== Compute Budget Optimizer =====
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Optimizes compute budget allocation for transactions.
|
|
300
|
+
* Provides dynamic adjustment based on network conditions.
|
|
301
|
+
*/
|
|
302
|
+
export class ComputeBudgetOptimizer {
|
|
303
|
+
private baseConfig: TransactionConfig;
|
|
304
|
+
private networkStats: NetworkStats = {
|
|
305
|
+
averageComputePrice: 0,
|
|
306
|
+
congestionLevel: 0,
|
|
307
|
+
recentSuccessRate: 1.0,
|
|
308
|
+
};
|
|
309
|
+
private history: BudgetHistoryEntry[] = [];
|
|
310
|
+
private maxHistorySize: number = 100;
|
|
311
|
+
|
|
312
|
+
constructor(config: TransactionConfig = defaultTransactionConfig()) {
|
|
313
|
+
this.baseConfig = config;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Update network statistics
|
|
318
|
+
*/
|
|
319
|
+
updateNetworkStats(stats: Partial<NetworkStats>): void {
|
|
320
|
+
this.networkStats = { ...this.networkStats, ...stats };
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get optimized compute budget for current conditions
|
|
325
|
+
*/
|
|
326
|
+
getOptimizedBudget(priority: 'low' | 'normal' | 'high' | 'critical' = 'normal'): {
|
|
327
|
+
computeLimit: number;
|
|
328
|
+
computePrice: number;
|
|
329
|
+
priorityFee: number;
|
|
330
|
+
} {
|
|
331
|
+
const multipliers: Record<string, number> = {
|
|
332
|
+
low: 0.5,
|
|
333
|
+
normal: 1.0,
|
|
334
|
+
high: 2.0,
|
|
335
|
+
critical: 5.0,
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const multiplier = multipliers[priority] ?? 1.0;
|
|
339
|
+
|
|
340
|
+
// Adjust based on congestion
|
|
341
|
+
const congestionMultiplier = 1 + this.networkStats.congestionLevel;
|
|
342
|
+
|
|
343
|
+
// Adjust based on recent success rate
|
|
344
|
+
const successMultiplier = this.networkStats.recentSuccessRate < 0.8 ? 1.5 : 1.0;
|
|
345
|
+
|
|
346
|
+
const computeLimit = this.baseConfig.computeUnitLimit;
|
|
347
|
+
const computePrice = Math.floor(
|
|
348
|
+
this.baseConfig.computeUnitPrice * multiplier * congestionMultiplier * successMultiplier
|
|
349
|
+
);
|
|
350
|
+
const priorityFee = Math.floor(
|
|
351
|
+
this.baseConfig.priorityFee * multiplier * congestionMultiplier * successMultiplier
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
return {
|
|
355
|
+
computeLimit,
|
|
356
|
+
computePrice,
|
|
357
|
+
priorityFee,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Record transaction result for learning
|
|
363
|
+
*/
|
|
364
|
+
recordResult(
|
|
365
|
+
computeUsed: number,
|
|
366
|
+
computeLimit: number,
|
|
367
|
+
success: boolean,
|
|
368
|
+
confirmationTimeMs: number
|
|
369
|
+
): void {
|
|
370
|
+
this.history.push({
|
|
371
|
+
computeUsed,
|
|
372
|
+
computeLimit,
|
|
373
|
+
success,
|
|
374
|
+
confirmationTimeMs,
|
|
375
|
+
timestamp: Date.now(),
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
if (this.history.length > this.maxHistorySize) {
|
|
379
|
+
this.history.shift();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Update success rate
|
|
383
|
+
const recent = this.history.slice(-20);
|
|
384
|
+
const successes = recent.filter(h => h.success).length;
|
|
385
|
+
this.networkStats.recentSuccessRate = successes / recent.length;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Get recommended compute limit based on history
|
|
390
|
+
*/
|
|
391
|
+
getRecommendedComputeLimit(): number {
|
|
392
|
+
if (this.history.length === 0) {
|
|
393
|
+
return this.baseConfig.computeUnitLimit;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Find 95th percentile of compute used
|
|
397
|
+
const computeUsed = this.history.map(h => h.computeUsed).sort((a, b) => a - b);
|
|
398
|
+
const p95Index = Math.floor(computeUsed.length * 0.95);
|
|
399
|
+
const p95Compute = computeUsed[p95Index] ?? computeUsed[computeUsed.length - 1] ?? this.baseConfig.computeUnitLimit;
|
|
400
|
+
|
|
401
|
+
// Add 20% buffer
|
|
402
|
+
return Math.ceil(p95Compute * 1.2);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Get optimization statistics
|
|
407
|
+
*/
|
|
408
|
+
getStats(): ComputeBudgetStats {
|
|
409
|
+
if (this.history.length === 0) {
|
|
410
|
+
return {
|
|
411
|
+
totalComputeUsed: 0,
|
|
412
|
+
totalComputeLimit: 0,
|
|
413
|
+
averageComputePerInstruction: 0,
|
|
414
|
+
estimatedFee: 0,
|
|
415
|
+
efficiency: 0,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const totalUsed = this.history.reduce((sum, h) => sum + h.computeUsed, 0);
|
|
420
|
+
const totalLimit = this.history.reduce((sum, h) => sum + h.computeLimit, 0);
|
|
421
|
+
|
|
422
|
+
return {
|
|
423
|
+
totalComputeUsed: totalUsed,
|
|
424
|
+
totalComputeLimit: totalLimit,
|
|
425
|
+
averageComputePerInstruction: totalUsed / this.history.length,
|
|
426
|
+
estimatedFee: this.calculateEstimatedFee(),
|
|
427
|
+
efficiency: totalLimit > 0 ? totalUsed / totalLimit : 0,
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Reset history
|
|
433
|
+
*/
|
|
434
|
+
reset(): void {
|
|
435
|
+
this.history = [];
|
|
436
|
+
this.networkStats = {
|
|
437
|
+
averageComputePrice: 0,
|
|
438
|
+
congestionLevel: 0,
|
|
439
|
+
recentSuccessRate: 1.0,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
private calculateEstimatedFee(): number {
|
|
444
|
+
const recent = this.history.slice(-10);
|
|
445
|
+
if (recent.length === 0) return 0;
|
|
446
|
+
|
|
447
|
+
const avgCompute = recent.reduce((sum, h) => sum + h.computeUsed, 0) / recent.length;
|
|
448
|
+
return avgCompute * this.baseConfig.computeUnitPrice;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Network statistics
|
|
454
|
+
*/
|
|
455
|
+
interface NetworkStats {
|
|
456
|
+
averageComputePrice: number;
|
|
457
|
+
congestionLevel: number;
|
|
458
|
+
recentSuccessRate: number;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Budget history entry
|
|
463
|
+
*/
|
|
464
|
+
interface BudgetHistoryEntry {
|
|
465
|
+
computeUsed: number;
|
|
466
|
+
computeLimit: number;
|
|
467
|
+
success: boolean;
|
|
468
|
+
confirmationTimeMs: number;
|
|
469
|
+
timestamp: number;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// ===== Instruction Batcher =====
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Batches multiple instructions into optimized groups.
|
|
476
|
+
*/
|
|
477
|
+
export class InstructionBatcher {
|
|
478
|
+
private groups: InstructionGroup[] = [];
|
|
479
|
+
private maxComputePerGroup: number = 1200000; // 1.2M compute units
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Add an instruction group
|
|
483
|
+
*/
|
|
484
|
+
addGroup(group: InstructionGroup): this {
|
|
485
|
+
this.groups.push(group);
|
|
486
|
+
return this;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Batch all groups into optimal transaction sets
|
|
491
|
+
*/
|
|
492
|
+
batch(): InstructionGroup[][] {
|
|
493
|
+
const batches: InstructionGroup[][] = [];
|
|
494
|
+
let currentBatch: InstructionGroup[] = [];
|
|
495
|
+
let currentCompute = 0;
|
|
496
|
+
|
|
497
|
+
// Sort by priority (highest first)
|
|
498
|
+
const sorted = [...this.groups].sort((a, b) => b.priority - a.priority);
|
|
499
|
+
|
|
500
|
+
for (const group of sorted) {
|
|
501
|
+
if (currentCompute + group.computeEstimate > this.maxComputePerGroup) {
|
|
502
|
+
// Start new batch
|
|
503
|
+
if (currentBatch.length > 0) {
|
|
504
|
+
batches.push(currentBatch);
|
|
505
|
+
}
|
|
506
|
+
currentBatch = [group];
|
|
507
|
+
currentCompute = group.computeEstimate;
|
|
508
|
+
} else {
|
|
509
|
+
// Add to current batch
|
|
510
|
+
currentBatch.push(group);
|
|
511
|
+
currentCompute += group.computeEstimate;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Add final batch
|
|
516
|
+
if (currentBatch.length > 0) {
|
|
517
|
+
batches.push(currentBatch);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return batches;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Set maximum compute per batch
|
|
525
|
+
*/
|
|
526
|
+
setMaxComputePerGroup(compute: number): this {
|
|
527
|
+
this.maxComputePerGroup = compute;
|
|
528
|
+
return this;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Clear all groups
|
|
533
|
+
*/
|
|
534
|
+
clear(): this {
|
|
535
|
+
this.groups = [];
|
|
536
|
+
return this;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// ===== Transaction Optimizer =====
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* High-level transaction optimizer.
|
|
544
|
+
* Applies multiple optimization strategies.
|
|
545
|
+
*/
|
|
546
|
+
export class TransactionOptimizer {
|
|
547
|
+
private config: TransactionConfig;
|
|
548
|
+
private budgetOptimizer: ComputeBudgetOptimizer;
|
|
549
|
+
|
|
550
|
+
constructor(config: TransactionConfig = defaultTransactionConfig()) {
|
|
551
|
+
this.config = config;
|
|
552
|
+
this.budgetOptimizer = new ComputeBudgetOptimizer(config);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Optimize a set of instructions
|
|
557
|
+
*/
|
|
558
|
+
optimize(
|
|
559
|
+
instructions: TransactionInstruction[],
|
|
560
|
+
options: {
|
|
561
|
+
priority?: 'low' | 'normal' | 'high' | 'critical';
|
|
562
|
+
useLookupTables?: boolean;
|
|
563
|
+
} = {}
|
|
564
|
+
): OptimizationResult {
|
|
565
|
+
const builder = new TransactionBuilder(this.config);
|
|
566
|
+
builder.addInstructions(instructions);
|
|
567
|
+
|
|
568
|
+
const result = builder.build();
|
|
569
|
+
|
|
570
|
+
// Apply priority adjustments
|
|
571
|
+
if (options.priority) {
|
|
572
|
+
const budget = this.budgetOptimizer.getOptimizedBudget(options.priority);
|
|
573
|
+
result.computeLimit = budget.computeLimit;
|
|
574
|
+
result.computePrice = budget.computePrice;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return result;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Optimize for minimum latency
|
|
582
|
+
*/
|
|
583
|
+
optimizeForLatency(instructions: TransactionInstruction[]): OptimizationResult {
|
|
584
|
+
return this.optimize(instructions, { priority: 'critical' });
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Optimize for minimum cost
|
|
589
|
+
*/
|
|
590
|
+
optimizeForCost(instructions: TransactionInstruction[]): OptimizationResult {
|
|
591
|
+
return this.optimize(instructions, { priority: 'low' });
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Get the compute budget optimizer
|
|
596
|
+
*/
|
|
597
|
+
getBudgetOptimizer(): ComputeBudgetOptimizer {
|
|
598
|
+
return this.budgetOptimizer;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Update configuration
|
|
603
|
+
*/
|
|
604
|
+
updateConfig(config: Partial<TransactionConfig>): void {
|
|
605
|
+
this.config = { ...this.config, ...config };
|
|
606
|
+
this.budgetOptimizer = new ComputeBudgetOptimizer(this.config);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// ===== Convenience Functions =====
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Create a transaction builder
|
|
614
|
+
*/
|
|
615
|
+
export function createTransactionBuilder(
|
|
616
|
+
config?: Partial<TransactionConfig>
|
|
617
|
+
): TransactionBuilder {
|
|
618
|
+
const fullConfig = { ...defaultTransactionConfig(), ...config };
|
|
619
|
+
return new TransactionBuilder(fullConfig);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Create a compute budget optimizer
|
|
624
|
+
*/
|
|
625
|
+
export function createComputeBudgetOptimizer(
|
|
626
|
+
config?: Partial<TransactionConfig>
|
|
627
|
+
): ComputeBudgetOptimizer {
|
|
628
|
+
const fullConfig = { ...defaultTransactionConfig(), ...config };
|
|
629
|
+
return new ComputeBudgetOptimizer(fullConfig);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Create an instruction batcher
|
|
634
|
+
*/
|
|
635
|
+
export function createInstructionBatcher(): InstructionBatcher {
|
|
636
|
+
return new InstructionBatcher();
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* Create a transaction optimizer
|
|
641
|
+
*/
|
|
642
|
+
export function createTransactionOptimizer(
|
|
643
|
+
config?: Partial<TransactionConfig>
|
|
644
|
+
): TransactionOptimizer {
|
|
645
|
+
const fullConfig = { ...defaultTransactionConfig(), ...config };
|
|
646
|
+
return new TransactionOptimizer(fullConfig);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Estimate compute units for common operations
|
|
651
|
+
*/
|
|
652
|
+
export function estimateCompute(operation: string): number {
|
|
653
|
+
const estimates: Record<string, number> = {
|
|
654
|
+
transfer: 450,
|
|
655
|
+
createAccount: 2500,
|
|
656
|
+
createATA: 3500,
|
|
657
|
+
closeAccount: 2500,
|
|
658
|
+
syncNative: 500,
|
|
659
|
+
pumpFunBuy: 45000,
|
|
660
|
+
pumpFunSell: 40000,
|
|
661
|
+
pumpSwapBuy: 50000,
|
|
662
|
+
pumpSwapSell: 45000,
|
|
663
|
+
raydiumSwap: 55000,
|
|
664
|
+
meteoraSwap: 60000,
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
return estimates[operation] || 3000;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Calculate optimal compute unit price
|
|
672
|
+
*/
|
|
673
|
+
export function calculateOptimalPrice(
|
|
674
|
+
targetLatencyMs: number,
|
|
675
|
+
currentCongestion: number
|
|
676
|
+
): number {
|
|
677
|
+
const basePrice = 100000;
|
|
678
|
+
const latencyMultiplier = Math.max(1, 100 / targetLatencyMs);
|
|
679
|
+
const congestionMultiplier = 1 + currentCongestion;
|
|
680
|
+
|
|
681
|
+
return Math.floor(basePrice * latencyMultiplier * congestionMultiplier);
|
|
682
|
+
}
|