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,692 @@
1
+ /**
2
+ * Raydium AMM V4 Protocol Instruction Builder
3
+ *
4
+ * Production-grade instruction builder for Raydium AMM V4 protocol.
5
+ * 100% port of Rust implementation.
6
+ */
7
+
8
+ import {
9
+ PublicKey,
10
+ Keypair,
11
+ AccountMeta,
12
+ TransactionInstruction,
13
+ SystemProgram,
14
+ } from "@solana/web3.js";
15
+ import {
16
+ getAssociatedTokenAddressSync,
17
+ createAssociatedTokenAccountInstruction,
18
+ TOKEN_PROGRAM_ID,
19
+ createCloseAccountInstruction,
20
+ NATIVE_MINT,
21
+ createSyncNativeInstruction,
22
+ } from "@solana/spl-token";
23
+
24
+ // ============================================
25
+ // Program IDs and Constants
26
+ // ============================================
27
+
28
+ /** Raydium AMM V4 program ID */
29
+ export const RAYDIUM_AMM_V4_PROGRAM_ID = new PublicKey(
30
+ "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"
31
+ );
32
+
33
+ /** Authority */
34
+ export const RAYDIUM_AMM_V4_AUTHORITY = new PublicKey(
35
+ "5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"
36
+ );
37
+
38
+ /** Fee rates */
39
+ export const RAYDIUM_AMM_V4_TRADE_FEE_NUMERATOR = BigInt(25);
40
+ export const RAYDIUM_AMM_V4_TRADE_FEE_DENOMINATOR = BigInt(10000);
41
+ export const RAYDIUM_AMM_V4_SWAP_FEE_NUMERATOR = BigInt(25);
42
+ export const RAYDIUM_AMM_V4_SWAP_FEE_DENOMINATOR = BigInt(10000);
43
+
44
+ // ============================================
45
+ // Discriminators
46
+ // ============================================
47
+
48
+ /** Swap base in instruction discriminator (single byte) */
49
+ export const RAYDIUM_AMM_V4_SWAP_BASE_IN_DISCRIMINATOR: Buffer = Buffer.from([9]);
50
+
51
+ /** Swap base out instruction discriminator (single byte) */
52
+ export const RAYDIUM_AMM_V4_SWAP_BASE_OUT_DISCRIMINATOR: Buffer = Buffer.from([11]);
53
+
54
+ // ============================================
55
+ // Seeds
56
+ // ============================================
57
+
58
+ export const RAYDIUM_AMM_V4_POOL_SEED = Buffer.from("pool");
59
+
60
+ // ============================================
61
+ // Helper Functions
62
+ // ============================================
63
+
64
+ /**
65
+ * Compute swap amount for AMM V4
66
+ */
67
+ export function computeRaydiumAmmV4SwapAmount(
68
+ coinReserve: bigint,
69
+ pcReserve: bigint,
70
+ isCoinIn: boolean,
71
+ amountIn: bigint,
72
+ slippageBasisPoints: bigint
73
+ ): { amountOut: bigint; minAmountOut: bigint } {
74
+ // Apply trade fee (0.25%)
75
+ const amountInAfterFee = amountIn - (amountIn * RAYDIUM_AMM_V4_TRADE_FEE_NUMERATOR) / RAYDIUM_AMM_V4_TRADE_FEE_DENOMINATOR;
76
+
77
+ // Calculate output using constant product formula
78
+ let amountOut: bigint;
79
+ if (isCoinIn) {
80
+ // Selling coin for pc: output = (pcReserve * amountIn) / (coinReserve + amountIn)
81
+ const denominator = coinReserve + amountInAfterFee;
82
+ amountOut = (pcReserve * amountInAfterFee) / denominator;
83
+ } else {
84
+ // Selling pc for coin: output = (coinReserve * amountIn) / (pcReserve + amountIn)
85
+ const denominator = pcReserve + amountInAfterFee;
86
+ amountOut = (coinReserve * amountInAfterFee) / denominator;
87
+ }
88
+
89
+ // Apply slippage
90
+ const minAmountOut = amountOut - (amountOut * slippageBasisPoints) / BigInt(10000);
91
+
92
+ return { amountOut, minAmountOut };
93
+ }
94
+
95
+ // ============================================
96
+ // Types
97
+ // ============================================
98
+
99
+ export interface RaydiumAmmV4Params {
100
+ amm: PublicKey;
101
+ coinMint: PublicKey;
102
+ pcMint: PublicKey;
103
+ tokenCoin: PublicKey;
104
+ tokenPc: PublicKey;
105
+ coinReserve: bigint;
106
+ pcReserve: bigint;
107
+ }
108
+
109
+ export interface BuildRaydiumAmmV4BuyInstructionsParams {
110
+ payer: Keypair | PublicKey;
111
+ outputMint: PublicKey;
112
+ inputAmount: bigint;
113
+ slippageBasisPoints?: bigint;
114
+ fixedOutputAmount?: bigint;
115
+ createInputMintAta?: boolean;
116
+ createOutputMintAta?: boolean;
117
+ closeInputMintAta?: boolean;
118
+ protocolParams: RaydiumAmmV4Params;
119
+ }
120
+
121
+ export interface BuildRaydiumAmmV4SellInstructionsParams {
122
+ payer: Keypair | PublicKey;
123
+ inputMint: PublicKey;
124
+ inputAmount: bigint;
125
+ slippageBasisPoints?: bigint;
126
+ fixedOutputAmount?: bigint;
127
+ createOutputMintAta?: boolean;
128
+ closeOutputMintAta?: boolean;
129
+ closeInputMintAta?: boolean;
130
+ protocolParams: RaydiumAmmV4Params;
131
+ }
132
+
133
+ // ============================================
134
+ // Instruction Builders
135
+ // ============================================
136
+
137
+ /**
138
+ * Build buy instructions for Raydium AMM V4 protocol
139
+ */
140
+ export function buildRaydiumAmmV4BuyInstructions(
141
+ params: BuildRaydiumAmmV4BuyInstructionsParams
142
+ ): TransactionInstruction[] {
143
+ const {
144
+ payer,
145
+ outputMint,
146
+ inputAmount,
147
+ slippageBasisPoints = BigInt(1000),
148
+ fixedOutputAmount,
149
+ createInputMintAta = true,
150
+ createOutputMintAta = true,
151
+ closeInputMintAta = false,
152
+ protocolParams,
153
+ } = params;
154
+
155
+ if (inputAmount === BigInt(0)) {
156
+ throw new Error("Amount cannot be zero");
157
+ }
158
+
159
+ const payerPubkey = payer instanceof Keypair ? payer.publicKey : payer;
160
+ const instructions: TransactionInstruction[] = [];
161
+
162
+ const WSOL_TOKEN_ACCOUNT = new PublicKey("So11111111111111111111111111111111111111112");
163
+ const USDC_TOKEN_ACCOUNT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
164
+
165
+ const {
166
+ amm,
167
+ coinMint,
168
+ pcMint,
169
+ tokenCoin,
170
+ tokenPc,
171
+ coinReserve,
172
+ pcReserve,
173
+ } = protocolParams;
174
+
175
+ // Check pool type
176
+ const isWsol = coinMint.equals(WSOL_TOKEN_ACCOUNT) || pcMint.equals(WSOL_TOKEN_ACCOUNT);
177
+ const isUsdc = coinMint.equals(USDC_TOKEN_ACCOUNT) || pcMint.equals(USDC_TOKEN_ACCOUNT);
178
+
179
+ if (!isWsol && !isUsdc) {
180
+ throw new Error("Pool must contain WSOL or USDC");
181
+ }
182
+
183
+ // Determine swap direction
184
+ const isBaseIn = coinMint.equals(WSOL_TOKEN_ACCOUNT) || coinMint.equals(USDC_TOKEN_ACCOUNT);
185
+
186
+ // Calculate output
187
+ const swapResult = computeRaydiumAmmV4SwapAmount(
188
+ coinReserve,
189
+ pcReserve,
190
+ isBaseIn,
191
+ inputAmount,
192
+ slippageBasisPoints
193
+ );
194
+ const minimumAmountOut = fixedOutputAmount || swapResult.minAmountOut;
195
+
196
+ // Determine input/output mints
197
+ const inputMint = isWsol ? WSOL_TOKEN_ACCOUNT : USDC_TOKEN_ACCOUNT;
198
+
199
+ // Derive user token accounts
200
+ const userSourceTokenAccount = getAssociatedTokenAddressSync(
201
+ inputMint,
202
+ payerPubkey,
203
+ true,
204
+ TOKEN_PROGRAM_ID
205
+ );
206
+ const userDestinationTokenAccount = getAssociatedTokenAddressSync(
207
+ outputMint,
208
+ payerPubkey,
209
+ true,
210
+ TOKEN_PROGRAM_ID
211
+ );
212
+
213
+ // Handle WSOL wrapping
214
+ if (createInputMintAta && isWsol) {
215
+ const wsolAta = getAssociatedTokenAddressSync(NATIVE_MINT, payerPubkey, true);
216
+ instructions.push(
217
+ createAssociatedTokenAccountInstruction(
218
+ payerPubkey,
219
+ wsolAta,
220
+ payerPubkey,
221
+ NATIVE_MINT,
222
+ TOKEN_PROGRAM_ID
223
+ )
224
+ );
225
+ instructions.push(createSyncNativeInstruction(wsolAta));
226
+ }
227
+
228
+ // Create output mint ATA if needed
229
+ if (createOutputMintAta) {
230
+ instructions.push(
231
+ createAssociatedTokenAccountInstruction(
232
+ payerPubkey,
233
+ userDestinationTokenAccount,
234
+ payerPubkey,
235
+ outputMint,
236
+ TOKEN_PROGRAM_ID
237
+ )
238
+ );
239
+ }
240
+
241
+ // Build instruction data (1 byte discriminator + 8 bytes amountIn + 8 bytes minAmountOut)
242
+ const data = Buffer.alloc(17);
243
+ RAYDIUM_AMM_V4_SWAP_BASE_IN_DISCRIMINATOR.copy(data, 0);
244
+ data.writeBigUInt64LE(inputAmount, 1);
245
+ data.writeBigUInt64LE(minimumAmountOut, 9);
246
+
247
+ // Build accounts (Raydium AMM V4 has a specific account order - 17 accounts)
248
+ const accounts: AccountMeta[] = [
249
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
250
+ { pubkey: amm, isSigner: false, isWritable: true },
251
+ { pubkey: RAYDIUM_AMM_V4_AUTHORITY, isSigner: false, isWritable: false },
252
+ { pubkey: amm, isSigner: false, isWritable: true }, // Amm Open Orders (same as amm for simplicity)
253
+ { pubkey: tokenCoin, isSigner: false, isWritable: true }, // Pool Coin Token Account
254
+ { pubkey: tokenPc, isSigner: false, isWritable: true }, // Pool Pc Token Account
255
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Program (placeholder)
256
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Market (placeholder)
257
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Bids (placeholder)
258
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Asks (placeholder)
259
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Event Queue (placeholder)
260
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Coin Vault Account (placeholder)
261
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Pc Vault Account (placeholder)
262
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Vault Signer (placeholder)
263
+ { pubkey: userSourceTokenAccount, isSigner: false, isWritable: true },
264
+ { pubkey: userDestinationTokenAccount, isSigner: false, isWritable: true },
265
+ { pubkey: payerPubkey, isSigner: true, isWritable: true },
266
+ ];
267
+
268
+ instructions.push(
269
+ new TransactionInstruction({
270
+ keys: accounts,
271
+ programId: RAYDIUM_AMM_V4_PROGRAM_ID,
272
+ data,
273
+ })
274
+ );
275
+
276
+ // Close WSOL ATA if requested
277
+ if (closeInputMintAta && isWsol) {
278
+ const wsolAta = getAssociatedTokenAddressSync(NATIVE_MINT, payerPubkey, true);
279
+ instructions.push(
280
+ createCloseAccountInstruction(wsolAta, payerPubkey, payerPubkey, [], TOKEN_PROGRAM_ID)
281
+ );
282
+ }
283
+
284
+ return instructions;
285
+ }
286
+
287
+ /**
288
+ * Build sell instructions for Raydium AMM V4 protocol
289
+ */
290
+ export function buildRaydiumAmmV4SellInstructions(
291
+ params: BuildRaydiumAmmV4SellInstructionsParams
292
+ ): TransactionInstruction[] {
293
+ const {
294
+ payer,
295
+ inputMint,
296
+ inputAmount,
297
+ slippageBasisPoints = BigInt(1000),
298
+ fixedOutputAmount,
299
+ createOutputMintAta = true,
300
+ closeOutputMintAta = false,
301
+ closeInputMintAta = false,
302
+ protocolParams,
303
+ } = params;
304
+
305
+ if (inputAmount === BigInt(0)) {
306
+ throw new Error("Amount cannot be zero");
307
+ }
308
+
309
+ const payerPubkey = payer instanceof Keypair ? payer.publicKey : payer;
310
+ const instructions: TransactionInstruction[] = [];
311
+
312
+ const WSOL_TOKEN_ACCOUNT = new PublicKey("So11111111111111111111111111111111111111112");
313
+ const USDC_TOKEN_ACCOUNT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
314
+
315
+ const {
316
+ amm,
317
+ coinMint,
318
+ pcMint,
319
+ tokenCoin,
320
+ tokenPc,
321
+ coinReserve,
322
+ pcReserve,
323
+ } = protocolParams;
324
+
325
+ // Check pool type
326
+ const isWsol = coinMint.equals(WSOL_TOKEN_ACCOUNT) || pcMint.equals(WSOL_TOKEN_ACCOUNT);
327
+ const isUsdc = coinMint.equals(USDC_TOKEN_ACCOUNT) || pcMint.equals(USDC_TOKEN_ACCOUNT);
328
+
329
+ if (!isWsol && !isUsdc) {
330
+ throw new Error("Pool must contain WSOL or USDC");
331
+ }
332
+
333
+ // Determine swap direction (selling token for WSOL/USDC means pc is output)
334
+ const isBaseIn = pcMint.equals(WSOL_TOKEN_ACCOUNT) || pcMint.equals(USDC_TOKEN_ACCOUNT);
335
+
336
+ // Calculate output
337
+ const swapResult = computeRaydiumAmmV4SwapAmount(
338
+ coinReserve,
339
+ pcReserve,
340
+ isBaseIn,
341
+ inputAmount,
342
+ slippageBasisPoints
343
+ );
344
+ const minimumAmountOut = fixedOutputAmount || swapResult.minAmountOut;
345
+
346
+ // Determine output mint
347
+ const outputMint = isWsol ? WSOL_TOKEN_ACCOUNT : USDC_TOKEN_ACCOUNT;
348
+
349
+ // Derive user token accounts
350
+ const userSourceTokenAccount = getAssociatedTokenAddressSync(
351
+ inputMint,
352
+ payerPubkey,
353
+ true,
354
+ TOKEN_PROGRAM_ID
355
+ );
356
+ const userDestinationTokenAccount = getAssociatedTokenAddressSync(
357
+ outputMint,
358
+ payerPubkey,
359
+ true,
360
+ TOKEN_PROGRAM_ID
361
+ );
362
+
363
+ // Create WSOL ATA for receiving if needed
364
+ if (createOutputMintAta && isWsol) {
365
+ const wsolAta = getAssociatedTokenAddressSync(NATIVE_MINT, payerPubkey, true);
366
+ instructions.push(
367
+ createAssociatedTokenAccountInstruction(
368
+ payerPubkey,
369
+ wsolAta,
370
+ payerPubkey,
371
+ NATIVE_MINT,
372
+ TOKEN_PROGRAM_ID
373
+ )
374
+ );
375
+ }
376
+
377
+ // Build instruction data
378
+ const data = Buffer.alloc(17);
379
+ RAYDIUM_AMM_V4_SWAP_BASE_IN_DISCRIMINATOR.copy(data, 0);
380
+ data.writeBigUInt64LE(inputAmount, 1);
381
+ data.writeBigUInt64LE(minimumAmountOut, 9);
382
+
383
+ // Build accounts
384
+ const accounts: AccountMeta[] = [
385
+ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
386
+ { pubkey: amm, isSigner: false, isWritable: true },
387
+ { pubkey: RAYDIUM_AMM_V4_AUTHORITY, isSigner: false, isWritable: false },
388
+ { pubkey: amm, isSigner: false, isWritable: true }, // Amm Open Orders
389
+ { pubkey: tokenCoin, isSigner: false, isWritable: true }, // Pool Coin Token Account
390
+ { pubkey: tokenPc, isSigner: false, isWritable: true }, // Pool Pc Token Account
391
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Program
392
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Market
393
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Bids
394
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Asks
395
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Event Queue
396
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Coin Vault Account
397
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Pc Vault Account
398
+ { pubkey: amm, isSigner: false, isWritable: false }, // Serum Vault Signer
399
+ { pubkey: userSourceTokenAccount, isSigner: false, isWritable: true },
400
+ { pubkey: userDestinationTokenAccount, isSigner: false, isWritable: true },
401
+ { pubkey: payerPubkey, isSigner: true, isWritable: true },
402
+ ];
403
+
404
+ instructions.push(
405
+ new TransactionInstruction({
406
+ keys: accounts,
407
+ programId: RAYDIUM_AMM_V4_PROGRAM_ID,
408
+ data,
409
+ })
410
+ );
411
+
412
+ // Close WSOL ATA if requested
413
+ if (closeOutputMintAta && isWsol) {
414
+ const wsolAta = getAssociatedTokenAddressSync(NATIVE_MINT, payerPubkey, true);
415
+ instructions.push(
416
+ createCloseAccountInstruction(wsolAta, payerPubkey, payerPubkey, [], TOKEN_PROGRAM_ID)
417
+ );
418
+ }
419
+
420
+ // Close input token ATA if requested
421
+ if (closeInputMintAta) {
422
+ instructions.push(
423
+ createCloseAccountInstruction(
424
+ userSourceTokenAccount,
425
+ payerPubkey,
426
+ payerPubkey,
427
+ [],
428
+ TOKEN_PROGRAM_ID
429
+ )
430
+ );
431
+ }
432
+
433
+ return instructions;
434
+ }
435
+
436
+ // ===== AMM Info Decoder - from Rust: src/instruction/utils/raydium_amm_v4_types.rs =====
437
+
438
+ export const AMM_INFO_SIZE = 752;
439
+
440
+ export interface RaydiumAmmFees {
441
+ minSeparateNumerator: bigint;
442
+ minSeparateDenominator: bigint;
443
+ tradeFeeNumerator: bigint;
444
+ tradeFeeDenominator: bigint;
445
+ pnlNumerator: bigint;
446
+ pnlDenominator: bigint;
447
+ swapFeeNumerator: bigint;
448
+ swapFeeDenominator: bigint;
449
+ }
450
+
451
+ export interface RaydiumAmmOutputData {
452
+ needTakePnlCoin: bigint;
453
+ needTakePnlPc: bigint;
454
+ totalPnlPc: bigint;
455
+ totalPnlCoin: bigint;
456
+ poolOpenTime: bigint;
457
+ punishPcAmount: bigint;
458
+ punishCoinAmount: bigint;
459
+ orderbookToInitTime: bigint;
460
+ swapCoinInAmount: bigint;
461
+ swapPcOutAmount: bigint;
462
+ swapTakePcFee: bigint;
463
+ swapPcInAmount: bigint;
464
+ swapCoinOutAmount: bigint;
465
+ swapTakeCoinFee: bigint;
466
+ }
467
+
468
+ export interface RaydiumAmmInfo {
469
+ status: bigint;
470
+ nonce: bigint;
471
+ orderNum: bigint;
472
+ depth: bigint;
473
+ coinDecimals: bigint;
474
+ pcDecimals: bigint;
475
+ state: bigint;
476
+ resetFlag: bigint;
477
+ minSize: bigint;
478
+ volMaxCutRatio: bigint;
479
+ amountWave: bigint;
480
+ coinLotSize: bigint;
481
+ pcLotSize: bigint;
482
+ minPriceMultiplier: bigint;
483
+ maxPriceMultiplier: bigint;
484
+ sysDecimalValue: bigint;
485
+ fees: RaydiumAmmFees;
486
+ output: RaydiumAmmOutputData;
487
+ tokenCoin: PublicKey;
488
+ tokenPc: PublicKey;
489
+ coinMint: PublicKey;
490
+ pcMint: PublicKey;
491
+ lpMint: PublicKey;
492
+ openOrders: PublicKey;
493
+ market: PublicKey;
494
+ serumDex: PublicKey;
495
+ targetOrders: PublicKey;
496
+ withdrawQueue: PublicKey;
497
+ tokenTempLp: PublicKey;
498
+ ammOwner: PublicKey;
499
+ lpAmount: bigint;
500
+ clientOrderId: bigint;
501
+ }
502
+
503
+ /**
504
+ * Decode Raydium AMM v4 info from account data.
505
+ * 100% from Rust: src/instruction/utils/raydium_amm_v4_types.rs amm_info_decode
506
+ */
507
+ export function decodeAmmInfo(data: Buffer): RaydiumAmmInfo | null {
508
+ if (data.length < AMM_INFO_SIZE) {
509
+ return null;
510
+ }
511
+
512
+ try {
513
+ let offset = 0;
514
+
515
+ const readU64 = () => {
516
+ const val = data.readBigUInt64LE(offset);
517
+ offset += 8;
518
+ return val;
519
+ };
520
+
521
+ // status: u64
522
+ const status = readU64();
523
+ // nonce: u64
524
+ const nonce = readU64();
525
+ // order_num: u64
526
+ const orderNum = readU64();
527
+ // depth: u64
528
+ const depth = readU64();
529
+ // coin_decimals: u64
530
+ const coinDecimals = readU64();
531
+ // pc_decimals: u64
532
+ const pcDecimals = readU64();
533
+ // state: u64
534
+ const state = readU64();
535
+ // reset_flag: u64
536
+ const resetFlag = readU64();
537
+ // min_size: u64
538
+ const minSize = readU64();
539
+ // vol_max_cut_ratio: u64
540
+ const volMaxCutRatio = readU64();
541
+ // amount_wave: u64
542
+ const amountWave = readU64();
543
+ // coin_lot_size: u64
544
+ const coinLotSize = readU64();
545
+ // pc_lot_size: u64
546
+ const pcLotSize = readU64();
547
+ // min_price_multiplier: u64
548
+ const minPriceMultiplier = readU64();
549
+ // max_price_multiplier: u64
550
+ const maxPriceMultiplier = readU64();
551
+ // sys_decimal_value: u64
552
+ const sysDecimalValue = readU64();
553
+
554
+ // fees: Fees (8 * u64)
555
+ const fees: RaydiumAmmFees = {
556
+ minSeparateNumerator: readU64(),
557
+ minSeparateDenominator: readU64(),
558
+ tradeFeeNumerator: readU64(),
559
+ tradeFeeDenominator: readU64(),
560
+ pnlNumerator: readU64(),
561
+ pnlDenominator: readU64(),
562
+ swapFeeNumerator: readU64(),
563
+ swapFeeDenominator: readU64(),
564
+ };
565
+
566
+ // output: OutPutData
567
+ const output: RaydiumAmmOutputData = {
568
+ needTakePnlCoin: readU64(),
569
+ needTakePnlPc: readU64(),
570
+ totalPnlPc: readU64(),
571
+ totalPnlCoin: readU64(),
572
+ poolOpenTime: readU64(),
573
+ punishPcAmount: readU64(),
574
+ punishCoinAmount: readU64(),
575
+ orderbookToInitTime: readU64(),
576
+ swapCoinInAmount: readU64(),
577
+ swapPcOutAmount: readU64(),
578
+ swapTakePcFee: readU64(),
579
+ swapPcInAmount: readU64(),
580
+ swapCoinOutAmount: readU64(),
581
+ swapTakeCoinFee: readU64(),
582
+ };
583
+
584
+ // token_coin: Pubkey
585
+ const tokenCoin = new PublicKey(data.subarray(offset, offset + 32));
586
+ offset += 32;
587
+
588
+ // token_pc: Pubkey
589
+ const tokenPc = new PublicKey(data.subarray(offset, offset + 32));
590
+ offset += 32;
591
+
592
+ // coin_mint: Pubkey
593
+ const coinMint = new PublicKey(data.subarray(offset, offset + 32));
594
+ offset += 32;
595
+
596
+ // pc_mint: Pubkey
597
+ const pcMint = new PublicKey(data.subarray(offset, offset + 32));
598
+ offset += 32;
599
+
600
+ // lp_mint: Pubkey
601
+ const lpMint = new PublicKey(data.subarray(offset, offset + 32));
602
+ offset += 32;
603
+
604
+ // open_orders: Pubkey
605
+ const openOrders = new PublicKey(data.subarray(offset, offset + 32));
606
+ offset += 32;
607
+
608
+ // market: Pubkey
609
+ const market = new PublicKey(data.subarray(offset, offset + 32));
610
+ offset += 32;
611
+
612
+ // serum_dex: Pubkey
613
+ const serumDex = new PublicKey(data.subarray(offset, offset + 32));
614
+ offset += 32;
615
+
616
+ // target_orders: Pubkey
617
+ const targetOrders = new PublicKey(data.subarray(offset, offset + 32));
618
+ offset += 32;
619
+
620
+ // withdraw_queue: Pubkey
621
+ const withdrawQueue = new PublicKey(data.subarray(offset, offset + 32));
622
+ offset += 32;
623
+
624
+ // token_temp_lp: Pubkey
625
+ const tokenTempLp = new PublicKey(data.subarray(offset, offset + 32));
626
+ offset += 32;
627
+
628
+ // amm_owner: Pubkey
629
+ const ammOwner = new PublicKey(data.subarray(offset, offset + 32));
630
+ offset += 32;
631
+
632
+ // lp_amount: u64
633
+ const lpAmount = readU64();
634
+
635
+ // client_order_id: u64
636
+ const clientOrderId = readU64();
637
+
638
+ return {
639
+ status,
640
+ nonce,
641
+ orderNum,
642
+ depth,
643
+ coinDecimals,
644
+ pcDecimals,
645
+ state,
646
+ resetFlag,
647
+ minSize,
648
+ volMaxCutRatio,
649
+ amountWave,
650
+ coinLotSize,
651
+ pcLotSize,
652
+ minPriceMultiplier,
653
+ maxPriceMultiplier,
654
+ sysDecimalValue,
655
+ fees,
656
+ output,
657
+ tokenCoin,
658
+ tokenPc,
659
+ coinMint,
660
+ pcMint,
661
+ lpMint,
662
+ openOrders,
663
+ market,
664
+ serumDex,
665
+ targetOrders,
666
+ withdrawQueue,
667
+ tokenTempLp,
668
+ ammOwner,
669
+ lpAmount,
670
+ clientOrderId,
671
+ };
672
+ } catch {
673
+ return null;
674
+ }
675
+ }
676
+
677
+ // ===== Async Fetch Functions - from Rust: src/instruction/utils/raydium_amm_v4.rs =====
678
+
679
+ /**
680
+ * Fetch AMM info from RPC.
681
+ * 100% from Rust: src/instruction/utils/raydium_amm_v4.rs fetch_amm_info
682
+ */
683
+ export async function fetchAmmInfo(
684
+ connection: { getAccountInfo: (pubkey: PublicKey) => Promise<{ value?: { data: Buffer } }> },
685
+ amm: PublicKey
686
+ ): Promise<RaydiumAmmInfo | null> {
687
+ const account = await connection.getAccountInfo(amm);
688
+ if (!account?.value?.data) {
689
+ return null;
690
+ }
691
+ return decodeAmmInfo(account.value.data);
692
+ }