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,1058 @@
1
+ /**
2
+ * Calculation utilities for Sol Trade SDK
3
+ *
4
+ * Security features:
5
+ * - Overflow/underflow protection
6
+ * - Input validation
7
+ * - Bounds checking
8
+ */
9
+
10
+ import { PublicKey } from '@solana/web3.js';
11
+ import BN from 'bn.js';
12
+
13
+ // ===== Security Constants =====
14
+
15
+ const MAX_SAFE_BIGINT = BigInt('18446744073709551615'); // 2^64 - 1
16
+ const MAX_BASIS_POINTS = BigInt(10000);
17
+
18
+ /// Maximum slippage in basis points (99.99% = 9999 bps)
19
+ /// This prevents the wrap amount from doubling when slippage is 100%
20
+ const MAX_SLIPPAGE_BASIS_POINTS = BigInt(9999);
21
+
22
+ // ===== Error Classes =====
23
+
24
+ export class CalculationError extends Error {
25
+ constructor(message: string) {
26
+ super(message);
27
+ this.name = 'CalculationError';
28
+ }
29
+ }
30
+
31
+ // ===== Validation Functions =====
32
+
33
+ function validateAmount(amount: bigint, name: string = 'amount'): void {
34
+ if (amount < BigInt(0)) {
35
+ throw new CalculationError(`${name} cannot be negative: ${amount}`);
36
+ }
37
+ if (amount > MAX_SAFE_BIGINT) {
38
+ throw new CalculationError(`${name} exceeds maximum safe value: ${amount}`);
39
+ }
40
+ }
41
+
42
+ function validateBasisPoints(basisPoints: bigint): void {
43
+ if (basisPoints < BigInt(0) || basisPoints > MAX_BASIS_POINTS) {
44
+ throw new CalculationError(`Basis points must be between 0 and 10000, got ${basisPoints}`);
45
+ }
46
+ }
47
+
48
+ function checkOverflow(a: bigint, b: bigint, operation: 'multiply' | 'add'): void {
49
+ if (operation === 'multiply') {
50
+ // Check if multiplication would overflow
51
+ if (a !== BigInt(0) && b > MAX_SAFE_BIGINT / a) {
52
+ throw new CalculationError(`Multiplication overflow: ${a} * ${b}`);
53
+ }
54
+ } else if (operation === 'add') {
55
+ // Check if addition would overflow
56
+ if (a > MAX_SAFE_BIGINT - b) {
57
+ throw new CalculationError(`Addition overflow: ${a} + ${b}`);
58
+ }
59
+ }
60
+ }
61
+
62
+ // ===== Common Calculation Functions =====
63
+
64
+ /**
65
+ * Compute fee based on amount and fee basis points
66
+ * Includes overflow protection
67
+ */
68
+ export function computeFee(amount: bigint, feeBasisPoints: bigint): bigint {
69
+ validateAmount(amount, 'amount');
70
+ validateBasisPoints(feeBasisPoints);
71
+
72
+ checkOverflow(amount, feeBasisPoints, 'multiply');
73
+ return ceilDiv(amount * feeBasisPoints, BigInt(10000));
74
+ }
75
+
76
+ /**
77
+ * Ceiling division with zero check
78
+ */
79
+ export function ceilDiv(a: bigint, b: bigint): bigint {
80
+ if (b === BigInt(0)) {
81
+ throw new CalculationError('Division by zero');
82
+ }
83
+ validateAmount(a, 'dividend');
84
+ validateAmount(b, 'divisor');
85
+
86
+ checkOverflow(a, b - BigInt(1), 'add');
87
+ return (a + b - BigInt(1)) / b;
88
+ }
89
+
90
+ /**
91
+ * Calculate buy amount with slippage protection
92
+ * Includes overflow protection and validation
93
+ *
94
+ * Note: Basis points are clamped to MAX_SLIPPAGE_BASIS_POINTS (9999 = 99.99%)
95
+ * to prevent the amount from doubling when basisPoints = 10000.
96
+ */
97
+ export function calculateWithSlippageBuy(amount: bigint, basisPoints: bigint): bigint {
98
+ validateAmount(amount, 'amount');
99
+
100
+ // Clamp basis points to max 9999 (99.99%) to prevent amount doubling at 100%
101
+ const bps = basisPoints > MAX_SLIPPAGE_BASIS_POINTS ? MAX_SLIPPAGE_BASIS_POINTS : basisPoints;
102
+
103
+ checkOverflow(amount, bps, 'multiply');
104
+ const slippageAmount = (amount * bps) / BigInt(10000);
105
+
106
+ checkOverflow(amount, slippageAmount, 'add');
107
+ return amount + slippageAmount;
108
+ }
109
+
110
+ /**
111
+ * Calculate sell amount with slippage protection
112
+ * Includes underflow protection
113
+ *
114
+ * 100% from Rust: src/utils/calc/common.rs calculate_with_slippage_sell
115
+ *
116
+ * Note: Returns 1n if amount <= basisPoints / 10000n to ensure minimum output.
117
+ */
118
+ export function calculateWithSlippageSell(amount: bigint, basisPoints: bigint): bigint {
119
+ validateAmount(amount, 'amount');
120
+ validateBasisPoints(basisPoints);
121
+
122
+ // Rust: if amount <= basis_points / 10000 { 1 } else { ... }
123
+ if (amount <= basisPoints / BigInt(10000)) {
124
+ return BigInt(1);
125
+ }
126
+
127
+ checkOverflow(amount, basisPoints, 'multiply');
128
+ const slippageAmount = (amount * basisPoints) / BigInt(10000);
129
+
130
+ return amount - slippageAmount;
131
+ }
132
+
133
+ // ===== PumpFun Constants =====
134
+ // Values from Rust: src/instruction/utils/pumpfun.rs global_constants
135
+ export const PUMPFUN_CONSTANTS = {
136
+ FEE_BASIS_POINTS: BigInt(95), // Protocol fee (NOT 100!)
137
+ CREATOR_FEE: BigInt(30), // Creator fee (NOT 50!)
138
+ INITIAL_VIRTUAL_TOKEN_RESERVES: BigInt('1073000000000000'),
139
+ INITIAL_VIRTUAL_SOL_RESERVES: BigInt('30000000000'),
140
+ INITIAL_REAL_TOKEN_RESERVES: BigInt('793100000000000'), // Fixed: was 793000000000000
141
+ TOKEN_TOTAL_SUPPLY: BigInt('1000000000000000'),
142
+ };
143
+
144
+ /**
145
+ * Calculate buy token amount from SOL amount for PumpFun
146
+ */
147
+ export function getBuyTokenAmountFromSolAmount(
148
+ virtualTokenReserves: bigint,
149
+ virtualSolReserves: bigint,
150
+ realTokenReserves: bigint,
151
+ hasCreator: boolean,
152
+ amount: bigint
153
+ ): bigint {
154
+ if (amount === BigInt(0) || virtualTokenReserves === BigInt(0)) {
155
+ return BigInt(0);
156
+ }
157
+
158
+ let totalFeeBasisPoints = PUMPFUN_CONSTANTS.FEE_BASIS_POINTS;
159
+ if (hasCreator) {
160
+ totalFeeBasisPoints += PUMPFUN_CONSTANTS.CREATOR_FEE;
161
+ }
162
+
163
+ const inputAmount =
164
+ (amount * BigInt(10000)) / (totalFeeBasisPoints + BigInt(10000));
165
+ const denominator = virtualSolReserves + inputAmount;
166
+
167
+ let tokensReceived =
168
+ (inputAmount * virtualTokenReserves) / denominator;
169
+
170
+ if (tokensReceived > realTokenReserves) {
171
+ tokensReceived = realTokenReserves;
172
+ }
173
+
174
+ // Minimum token protection
175
+ if (tokensReceived <= BigInt(100) * BigInt(1000000)) {
176
+ if (amount > BigInt(10000000)) {
177
+ // > 0.01 SOL
178
+ tokensReceived = BigInt('25547619000000000');
179
+ } else {
180
+ tokensReceived = BigInt('255476000000000');
181
+ }
182
+ }
183
+
184
+ return tokensReceived;
185
+ }
186
+
187
+ /**
188
+ * Calculate sell SOL amount from token amount for PumpFun
189
+ */
190
+ export function getSellSolAmountFromTokenAmount(
191
+ virtualTokenReserves: bigint,
192
+ virtualSolReserves: bigint,
193
+ hasCreator: boolean,
194
+ amount: bigint
195
+ ): bigint {
196
+ if (amount === BigInt(0) || virtualTokenReserves === BigInt(0)) {
197
+ return BigInt(0);
198
+ }
199
+
200
+ const numerator = amount * virtualSolReserves;
201
+ const denominator = virtualTokenReserves + amount;
202
+
203
+ const solCost = numerator / denominator;
204
+
205
+ let totalFeeBasisPoints = PUMPFUN_CONSTANTS.FEE_BASIS_POINTS;
206
+ if (hasCreator) {
207
+ totalFeeBasisPoints += PUMPFUN_CONSTANTS.CREATOR_FEE;
208
+ }
209
+
210
+ const fee = computeFee(solCost, totalFeeBasisPoints);
211
+
212
+ if (solCost < fee) {
213
+ return BigInt(0);
214
+ }
215
+ return solCost - fee;
216
+ }
217
+
218
+ // ===== PumpSwap Constants =====
219
+ // Values from Rust: src/instruction/utils/pumpswap.rs accounts
220
+ export const PUMPSWAP_CONSTANTS = {
221
+ LP_FEE_BASIS_POINTS: BigInt(25), // 0.25% (was 20)
222
+ PROTOCOL_FEE_BASIS_POINTS: BigInt(5), // 0.05% (was 20)
223
+ COIN_CREATOR_FEE_BASIS_POINTS: BigInt(5), // 0.05% (was 10)
224
+ };
225
+
226
+ export interface BuyBaseInputResult {
227
+ internalQuoteAmount: bigint;
228
+ uiQuote: bigint;
229
+ maxQuote: bigint;
230
+ }
231
+
232
+ export interface BuyQuoteInputResult {
233
+ base: bigint;
234
+ internalQuoteWithoutFees: bigint;
235
+ maxQuote: bigint;
236
+ }
237
+
238
+ export interface SellBaseInputResult {
239
+ uiQuote: bigint;
240
+ minQuote: bigint;
241
+ internalQuoteAmountOut: bigint;
242
+ }
243
+
244
+ export interface SellQuoteInputResult {
245
+ internalRawQuote: bigint;
246
+ base: bigint;
247
+ minQuote: bigint;
248
+ }
249
+
250
+ /**
251
+ * Calculate quote needed to buy base tokens on PumpSwap
252
+ */
253
+ export function buyBaseInputInternal(
254
+ base: bigint,
255
+ slippageBasisPoints: bigint,
256
+ baseReserve: bigint,
257
+ quoteReserve: bigint,
258
+ hasCoinCreator: boolean
259
+ ): BuyBaseInputResult {
260
+ if (baseReserve === BigInt(0) || quoteReserve === BigInt(0)) {
261
+ throw new Error('Invalid input: reserves cannot be zero');
262
+ }
263
+ if (base > baseReserve) {
264
+ throw new Error('Cannot buy more base tokens than pool reserves');
265
+ }
266
+
267
+ const numerator = quoteReserve * base;
268
+ const denominator = baseReserve - base;
269
+
270
+ if (denominator === BigInt(0)) {
271
+ throw new Error('Pool would be depleted');
272
+ }
273
+
274
+ const quoteAmountIn = ceilDiv(numerator, denominator);
275
+
276
+ const lpFee = computeFee(quoteAmountIn, PUMPSWAP_CONSTANTS.LP_FEE_BASIS_POINTS);
277
+ const protocolFee = computeFee(quoteAmountIn, PUMPSWAP_CONSTANTS.PROTOCOL_FEE_BASIS_POINTS);
278
+ let coinCreatorFee = BigInt(0);
279
+ if (hasCoinCreator) {
280
+ coinCreatorFee = computeFee(quoteAmountIn, PUMPSWAP_CONSTANTS.COIN_CREATOR_FEE_BASIS_POINTS);
281
+ }
282
+
283
+ const totalQuote = quoteAmountIn + lpFee + protocolFee + coinCreatorFee;
284
+ const maxQuote = calculateWithSlippageBuy(totalQuote, slippageBasisPoints);
285
+
286
+ return {
287
+ internalQuoteAmount: quoteAmountIn,
288
+ uiQuote: totalQuote,
289
+ maxQuote,
290
+ };
291
+ }
292
+
293
+ /**
294
+ * Calculate base tokens received for quote input on PumpSwap
295
+ */
296
+ export function buyQuoteInputInternal(
297
+ quote: bigint,
298
+ slippageBasisPoints: bigint,
299
+ baseReserve: bigint,
300
+ quoteReserve: bigint,
301
+ hasCoinCreator: boolean
302
+ ): BuyQuoteInputResult {
303
+ if (baseReserve === BigInt(0) || quoteReserve === BigInt(0)) {
304
+ throw new Error('Invalid input: reserves cannot be zero');
305
+ }
306
+
307
+ let totalFeeBps =
308
+ PUMPSWAP_CONSTANTS.LP_FEE_BASIS_POINTS +
309
+ PUMPSWAP_CONSTANTS.PROTOCOL_FEE_BASIS_POINTS;
310
+ if (hasCoinCreator) {
311
+ totalFeeBps += PUMPSWAP_CONSTANTS.COIN_CREATOR_FEE_BASIS_POINTS;
312
+ }
313
+ const denominator = BigInt(10000) + totalFeeBps;
314
+
315
+ const effectiveQuote = (quote * BigInt(10000)) / denominator;
316
+
317
+ const numerator = baseReserve * effectiveQuote;
318
+ const denominatorEffective = quoteReserve + effectiveQuote;
319
+
320
+ if (denominatorEffective === BigInt(0)) {
321
+ throw new Error('Pool would be depleted');
322
+ }
323
+
324
+ const baseAmountOut = numerator / denominatorEffective;
325
+ const maxQuote = calculateWithSlippageBuy(quote, slippageBasisPoints);
326
+
327
+ return {
328
+ base: baseAmountOut,
329
+ internalQuoteWithoutFees: effectiveQuote,
330
+ maxQuote,
331
+ };
332
+ }
333
+
334
+ /**
335
+ * Calculate quote received for selling base tokens on PumpSwap
336
+ */
337
+ export function sellBaseInputInternal(
338
+ base: bigint,
339
+ slippageBasisPoints: bigint,
340
+ baseReserve: bigint,
341
+ quoteReserve: bigint,
342
+ hasCoinCreator: boolean
343
+ ): SellBaseInputResult {
344
+ if (baseReserve === BigInt(0) || quoteReserve === BigInt(0)) {
345
+ throw new Error('Invalid input: reserves cannot be zero');
346
+ }
347
+
348
+ const quoteAmountOut =
349
+ (quoteReserve * base) / (baseReserve + base);
350
+
351
+ const lpFee = computeFee(quoteAmountOut, PUMPSWAP_CONSTANTS.LP_FEE_BASIS_POINTS);
352
+ const protocolFee = computeFee(quoteAmountOut, PUMPSWAP_CONSTANTS.PROTOCOL_FEE_BASIS_POINTS);
353
+ let coinCreatorFee = BigInt(0);
354
+ if (hasCoinCreator) {
355
+ coinCreatorFee = computeFee(quoteAmountOut, PUMPSWAP_CONSTANTS.COIN_CREATOR_FEE_BASIS_POINTS);
356
+ }
357
+
358
+ const totalFees = lpFee + protocolFee + coinCreatorFee;
359
+ if (totalFees > quoteAmountOut) {
360
+ throw new Error('Fees exceed output');
361
+ }
362
+ const finalQuote = quoteAmountOut - totalFees;
363
+ const minQuote = calculateWithSlippageSell(finalQuote, slippageBasisPoints);
364
+
365
+ return {
366
+ uiQuote: finalQuote,
367
+ minQuote,
368
+ internalQuoteAmountOut: quoteAmountOut,
369
+ };
370
+ }
371
+
372
+ /**
373
+ * Calculate base needed to receive quote amount on PumpSwap
374
+ */
375
+ export function sellQuoteInputInternal(
376
+ quote: bigint,
377
+ slippageBasisPoints: bigint,
378
+ baseReserve: bigint,
379
+ quoteReserve: bigint,
380
+ hasCoinCreator: boolean
381
+ ): SellQuoteInputResult {
382
+ if (baseReserve === BigInt(0) || quoteReserve === BigInt(0)) {
383
+ throw new Error('Invalid input: reserves cannot be zero');
384
+ }
385
+ if (quote > quoteReserve) {
386
+ throw new Error('Cannot receive more than pool reserves');
387
+ }
388
+
389
+ let coinCreatorFee = BigInt(0);
390
+ if (hasCoinCreator) {
391
+ coinCreatorFee = PUMPSWAP_CONSTANTS.COIN_CREATOR_FEE_BASIS_POINTS;
392
+ }
393
+
394
+ const rawQuote = calculateQuoteAmountOut(
395
+ quote,
396
+ PUMPSWAP_CONSTANTS.LP_FEE_BASIS_POINTS,
397
+ PUMPSWAP_CONSTANTS.PROTOCOL_FEE_BASIS_POINTS,
398
+ coinCreatorFee
399
+ );
400
+
401
+ if (rawQuote >= quoteReserve) {
402
+ throw new Error('Invalid input: desired amount exceeds reserve');
403
+ }
404
+
405
+ const baseAmountIn = ceilDiv(
406
+ baseReserve * rawQuote,
407
+ quoteReserve - rawQuote
408
+ );
409
+ const minQuote = calculateWithSlippageSell(quote, slippageBasisPoints);
410
+
411
+ return {
412
+ internalRawQuote: rawQuote,
413
+ base: baseAmountIn,
414
+ minQuote,
415
+ };
416
+ }
417
+
418
+ function calculateQuoteAmountOut(
419
+ userQuoteAmountOut: bigint,
420
+ lpFeeBasisPoints: bigint,
421
+ protocolFeeBasisPoints: bigint,
422
+ coinCreatorFeeBasisPoints: bigint
423
+ ): bigint {
424
+ const totalFeeBasisPoints =
425
+ lpFeeBasisPoints + protocolFeeBasisPoints + coinCreatorFeeBasisPoints;
426
+ const denominator = BigInt(10000) - totalFeeBasisPoints;
427
+ return ceilDiv(userQuoteAmountOut * BigInt(10000), denominator);
428
+ }
429
+
430
+ // ===== Bonk Constants =====
431
+
432
+ export const BONK_CONSTANTS = {
433
+ PROTOCOL_FEE_RATE: BigInt(25), // 0.25%
434
+ PLATFORM_FEE_RATE: BigInt(100), // 1%
435
+ SHARE_FEE_RATE: BigInt(0), // 0%
436
+ DEFAULT_VIRTUAL_BASE: BigInt('1073025605596382'),
437
+ DEFAULT_VIRTUAL_QUOTE: BigInt('30000852951'),
438
+ };
439
+
440
+ /**
441
+ * Calculate output amount for Bonk
442
+ */
443
+ export function getBonkAmountOut(
444
+ amountIn: bigint,
445
+ virtualBase: bigint,
446
+ virtualQuote: bigint
447
+ ): bigint {
448
+ if (virtualBase === BigInt(0) || virtualQuote === BigInt(0)) {
449
+ return BigInt(0);
450
+ }
451
+
452
+ const amountOut = (amountIn * virtualQuote) / virtualBase;
453
+ return amountOut;
454
+ }
455
+
456
+ /**
457
+ * Calculate input amount needed for Bonk
458
+ */
459
+ export function getBonkAmountIn(
460
+ amountOut: bigint,
461
+ virtualBase: bigint,
462
+ virtualQuote: bigint
463
+ ): bigint {
464
+ if (virtualBase === BigInt(0) || virtualQuote === BigInt(0)) {
465
+ return BigInt(0);
466
+ }
467
+
468
+ const totalFeeRate =
469
+ BONK_CONSTANTS.PROTOCOL_FEE_RATE +
470
+ BONK_CONSTANTS.PLATFORM_FEE_RATE +
471
+ BONK_CONSTANTS.SHARE_FEE_RATE;
472
+ const amountIn =
473
+ ((amountOut * BigInt(10000)) / (BigInt(10000) - totalFeeRate) * virtualBase) /
474
+ virtualQuote;
475
+
476
+ return amountIn;
477
+ }
478
+
479
+ // ===== Raydium Calculations =====
480
+
481
+ /**
482
+ * Calculate output amount for Raydium AMM V4
483
+ */
484
+ export function raydiumAmmV4GetAmountOut(
485
+ amountIn: bigint,
486
+ inputReserve: bigint,
487
+ outputReserve: bigint
488
+ ): bigint {
489
+ if (inputReserve === BigInt(0) || outputReserve === BigInt(0)) {
490
+ return BigInt(0);
491
+ }
492
+
493
+ // Apply 0.25% fee
494
+ const amountInWithFee = amountIn * BigInt(9975);
495
+ const numerator = amountInWithFee * outputReserve;
496
+ const denominator = inputReserve * BigInt(10000) + amountInWithFee;
497
+
498
+ return numerator / denominator;
499
+ }
500
+
501
+ /**
502
+ * Calculate input amount needed for Raydium AMM V4
503
+ */
504
+ export function raydiumAmmV4GetAmountIn(
505
+ amountOut: bigint,
506
+ inputReserve: bigint,
507
+ outputReserve: bigint
508
+ ): bigint {
509
+ if (inputReserve === BigInt(0) || outputReserve === BigInt(0) || amountOut >= outputReserve) {
510
+ return BigInt(0);
511
+ }
512
+
513
+ const numerator = inputReserve * amountOut * BigInt(10000);
514
+ const denominator = (outputReserve - amountOut) * BigInt(9975);
515
+
516
+ return ceilDiv(numerator, denominator);
517
+ }
518
+
519
+ /**
520
+ * Calculate output amount for Raydium CPMM
521
+ */
522
+ export function raydiumCpmmGetAmountOut(
523
+ amountIn: bigint,
524
+ inputReserve: bigint,
525
+ outputReserve: bigint
526
+ ): bigint {
527
+ if (inputReserve === BigInt(0) || outputReserve === BigInt(0)) {
528
+ return BigInt(0);
529
+ }
530
+
531
+ const amountOut = (amountIn * outputReserve) / (inputReserve + amountIn);
532
+ return amountOut;
533
+ }
534
+
535
+ // ===== Meteora DAMM V2 Calculations =====
536
+
537
+ export interface MeteoraSwapResult {
538
+ amountOut: bigint;
539
+ minAmountOut: bigint;
540
+ }
541
+
542
+ /**
543
+ * Compute swap amount for Meteora DAMM V2
544
+ */
545
+ export function meteoraDammV2ComputeSwapAmount(
546
+ tokenAReserve: bigint,
547
+ tokenBReserve: bigint,
548
+ isAToB: boolean,
549
+ amountIn: bigint,
550
+ slippageBasisPoints: bigint
551
+ ): MeteoraSwapResult {
552
+ if (amountIn === BigInt(0)) {
553
+ return { amountOut: BigInt(0), minAmountOut: BigInt(0) };
554
+ }
555
+
556
+ let amountOut: bigint;
557
+
558
+ if (isAToB) {
559
+ // Swapping token A for token B
560
+ if (tokenAReserve === BigInt(0)) {
561
+ return { amountOut: BigInt(0), minAmountOut: BigInt(0) };
562
+ }
563
+
564
+ // Constant product: b_out = (b_reserve * a_in) / (a_reserve + a_in)
565
+ const numerator = tokenBReserve * amountIn;
566
+ const denominator = tokenAReserve + amountIn;
567
+
568
+ if (denominator === BigInt(0)) {
569
+ return { amountOut: BigInt(0), minAmountOut: BigInt(0) };
570
+ }
571
+
572
+ amountOut = numerator / denominator;
573
+ } else {
574
+ // Swapping token B for token A
575
+ if (tokenBReserve === BigInt(0)) {
576
+ return { amountOut: BigInt(0), minAmountOut: BigInt(0) };
577
+ }
578
+
579
+ // Constant product: a_out = (a_reserve * b_in) / (b_reserve + b_in)
580
+ const numerator = tokenAReserve * amountIn;
581
+ const denominator = tokenBReserve + amountIn;
582
+
583
+ if (denominator === BigInt(0)) {
584
+ return { amountOut: BigInt(0), minAmountOut: BigInt(0) };
585
+ }
586
+
587
+ amountOut = numerator / denominator;
588
+ }
589
+
590
+ // Apply slippage
591
+ const minAmountOut = calculateWithSlippageSell(amountOut, slippageBasisPoints);
592
+
593
+ return { amountOut, minAmountOut };
594
+ }
595
+
596
+ /**
597
+ * Calculate current price (token B per token A) for Meteora DAMM V2
598
+ */
599
+ export function meteoraDammV2CalculatePrice(
600
+ tokenAReserve: bigint,
601
+ tokenBReserve: bigint
602
+ ): number {
603
+ if (tokenAReserve === BigInt(0)) {
604
+ return 0.0;
605
+ }
606
+ return Number(tokenBReserve) / Number(tokenAReserve);
607
+ }
608
+
609
+ /**
610
+ * Calculate liquidity (geometric mean of reserves) for Meteora DAMM V2
611
+ */
612
+ export function meteoraDammV2CalculateLiquidity(
613
+ tokenAReserve: bigint,
614
+ tokenBReserve: bigint
615
+ ): bigint {
616
+ if (tokenAReserve === BigInt(0) || tokenBReserve === BigInt(0)) {
617
+ return BigInt(0);
618
+ }
619
+ return BigInt(Math.floor(Math.sqrt(Number(tokenAReserve) * Number(tokenBReserve))));
620
+ }
621
+
622
+ /**
623
+ * Calculate output amount with fee consideration for Meteora DAMM V2
624
+ */
625
+ export function meteoraDammV2GetAmountOut(
626
+ amountIn: bigint,
627
+ inputReserve: bigint,
628
+ outputReserve: bigint,
629
+ feeBasisPoints: bigint
630
+ ): bigint {
631
+ if (inputReserve === BigInt(0) || outputReserve === BigInt(0) || amountIn === BigInt(0)) {
632
+ return BigInt(0);
633
+ }
634
+
635
+ // Apply fee
636
+ const amountInAfterFee = (amountIn * (BigInt(10000) - feeBasisPoints)) / BigInt(10000);
637
+
638
+ const numerator = amountInAfterFee * outputReserve;
639
+ const denominator = inputReserve + amountInAfterFee;
640
+
641
+ return numerator / denominator;
642
+ }
643
+
644
+ /**
645
+ * Calculate input amount needed for desired output for Meteora DAMM V2
646
+ */
647
+ export function meteoraDammV2GetAmountIn(
648
+ amountOut: bigint,
649
+ inputReserve: bigint,
650
+ outputReserve: bigint,
651
+ feeBasisPoints: bigint
652
+ ): bigint {
653
+ if (inputReserve === BigInt(0) || outputReserve === BigInt(0) || amountOut >= outputReserve) {
654
+ return BigInt(0);
655
+ }
656
+
657
+ const numerator = inputReserve * amountOut * BigInt(10000);
658
+ const denominator = (outputReserve - amountOut) * (BigInt(10000) - feeBasisPoints);
659
+
660
+ return ceilDiv(numerator, denominator);
661
+ }
662
+
663
+ // ===== Utility Functions =====
664
+
665
+ /**
666
+ * Calculate price impact percentage
667
+ */
668
+ export function calculatePriceImpact(reserveIn: bigint, amountIn: bigint): number {
669
+ if (reserveIn === BigInt(0)) {
670
+ return 0;
671
+ }
672
+ return Number((amountIn * BigInt(10000)) / reserveIn) / 100;
673
+ }
674
+
675
+ /**
676
+ * Calculate price from reserves
677
+ */
678
+ export function calculatePrice(
679
+ quoteReserve: bigint,
680
+ baseReserve: bigint,
681
+ quoteDecimals: number,
682
+ baseDecimals: number
683
+ ): number {
684
+ if (baseReserve === BigInt(0)) {
685
+ return 0;
686
+ }
687
+ const quoteAdjusted = Number(quoteReserve) / Math.pow(10, quoteDecimals);
688
+ const baseAdjusted = Number(baseReserve) / Math.pow(10, baseDecimals);
689
+ return quoteAdjusted / baseAdjusted;
690
+ }
691
+
692
+ /**
693
+ * Convert lamports to SOL
694
+ */
695
+ export function lamportsToSol(lamports: bigint | number): number {
696
+ return Number(lamports) / 1e9;
697
+ }
698
+
699
+ // ===== Price Calculation Functions - from Rust: src/utils/price/ =====
700
+
701
+ const DEFAULT_TOKEN_DECIMALS = 6;
702
+ const SOL_DECIMALS = 9;
703
+
704
+ /**
705
+ * Calculate the price of token in WSOL
706
+ * 100% from Rust: src/utils/price/bonk.rs price_token_in_wsol
707
+ */
708
+ export function priceTokenInWsol(
709
+ virtualBase: bigint,
710
+ virtualQuote: bigint,
711
+ realBase: bigint,
712
+ realQuote: bigint
713
+ ): number {
714
+ return priceBaseInQuoteWithVirtual(
715
+ virtualBase,
716
+ virtualQuote,
717
+ realBase,
718
+ realQuote,
719
+ DEFAULT_TOKEN_DECIMALS,
720
+ SOL_DECIMALS
721
+ );
722
+ }
723
+
724
+ /**
725
+ * Calculate the price of base in quote with virtual reserves
726
+ * 100% from Rust: src/utils/price/bonk.rs price_base_in_quote
727
+ */
728
+ export function priceBaseInQuoteWithVirtual(
729
+ virtualBase: bigint,
730
+ virtualQuote: bigint,
731
+ realBase: bigint,
732
+ realQuote: bigint,
733
+ baseDecimals: number,
734
+ quoteDecimals: number
735
+ ): number {
736
+ // Calculate decimal places difference
737
+ const decimalDiff = quoteDecimals - baseDecimals;
738
+ const decimalFactor = decimalDiff >= 0
739
+ ? Math.pow(10, decimalDiff)
740
+ : 1.0 / Math.pow(10, -decimalDiff);
741
+
742
+ // Calculate reserves state before price calculation
743
+ const quoteReserves = virtualQuote + realQuote;
744
+ const baseReserves = virtualBase > realBase ? virtualBase - realBase : BigInt(0);
745
+
746
+ if (baseReserves === BigInt(0)) {
747
+ return 0.0;
748
+ }
749
+
750
+ if (decimalFactor === 0.0) {
751
+ return 0.0;
752
+ }
753
+
754
+ // Use floating point calculation to avoid precision loss
755
+ const price = (Number(quoteReserves) / Number(baseReserves)) / decimalFactor;
756
+
757
+ return price;
758
+ }
759
+
760
+ /**
761
+ * Calculate the token price in quote based on base and quote reserves
762
+ * 100% from Rust: src/utils/price/common.rs price_base_in_quote
763
+ */
764
+ export function priceBaseInQuoteFromReserves(
765
+ baseReserve: bigint,
766
+ quoteReserve: bigint,
767
+ baseDecimals: number,
768
+ quoteDecimals: number
769
+ ): number {
770
+ const base = Number(baseReserve) / Math.pow(10, baseDecimals);
771
+ const quote = Number(quoteReserve) / Math.pow(10, quoteDecimals);
772
+ if (base === 0.0) {
773
+ return 0.0;
774
+ }
775
+ return quote / base;
776
+ }
777
+
778
+ /**
779
+ * Calculate the token price in base based on base and quote reserves
780
+ * 100% from Rust: src/utils/price/common.rs price_quote_in_base
781
+ */
782
+ export function priceQuoteInBase(
783
+ baseReserve: bigint,
784
+ quoteReserve: bigint,
785
+ baseDecimals: number,
786
+ quoteDecimals: number
787
+ ): number {
788
+ const base = Number(baseReserve) / Math.pow(10, baseDecimals);
789
+ const quote = Number(quoteReserve) / Math.pow(10, quoteDecimals);
790
+ if (quote === 0.0) {
791
+ return 0.0;
792
+ }
793
+ return base / quote;
794
+ }
795
+
796
+ // ===== PumpFun Price Calculation =====
797
+
798
+ // Constants from Rust: src/instruction/utils/pumpfun.rs global_constants
799
+ const LAMPORTS_PER_SOL = 1_000_000_000;
800
+ const SCALE = 1_000_000; // 6 decimals for tokens
801
+
802
+ /**
803
+ * Calculate the token price in SOL based on virtual reserves
804
+ * 100% from Rust: src/utils/price/pumpfun.rs price_token_in_sol
805
+ */
806
+ export function priceTokenInSol(
807
+ virtualSolReserves: bigint,
808
+ virtualTokenReserves: bigint
809
+ ): number {
810
+ const vSol = Number(virtualSolReserves) / LAMPORTS_PER_SOL;
811
+ const vTokens = Number(virtualTokenReserves) / SCALE;
812
+ if (vTokens === 0.0) {
813
+ return 0.0;
814
+ }
815
+ return vSol / vTokens;
816
+ }
817
+
818
+ // ===== Bonk Calculations - from Rust: src/utils/calc/bonk.rs =====
819
+
820
+ /**
821
+ * Calculates the amount of tokens to receive when buying with SOL
822
+ * 100% from Rust: src/utils/calc/bonk.rs get_buy_token_amount_from_sol_amount
823
+ */
824
+ export function getBonkBuyTokenAmountFromSolAmount(
825
+ amountIn: bigint,
826
+ virtualBase: bigint,
827
+ virtualQuote: bigint,
828
+ realBase: bigint,
829
+ realQuote: bigint,
830
+ slippageBasisPoints: bigint
831
+ ): bigint {
832
+ const amountInU128 = amountIn;
833
+
834
+ // Fee rates from Bonk - 100% from Rust: src/instruction/utils/bonk.rs accounts
835
+ const PROTOCOL_FEE_RATE = BigInt(25); // 0.25%
836
+ const PLATFORM_FEE_RATE = BigInt(100); // 1%
837
+ const SHARE_FEE_RATE = BigInt(0); // 0%
838
+
839
+ // Calculate fees
840
+ const protocolFee = (amountInU128 * PROTOCOL_FEE_RATE) / BigInt(10000);
841
+ const platformFee = (amountInU128 * PLATFORM_FEE_RATE) / BigInt(10000);
842
+ const shareFee = (amountInU128 * SHARE_FEE_RATE) / BigInt(10000);
843
+
844
+ // Calculate net input after fees
845
+ const amountInNet = amountInU128 - protocolFee - platformFee - shareFee;
846
+
847
+ // Calculate total reserves
848
+ const inputReserve = virtualQuote + realQuote;
849
+ const outputReserve = virtualBase - realBase;
850
+
851
+ // Apply constant product formula
852
+ const numerator = amountInNet * outputReserve;
853
+ const denominator = inputReserve + amountInNet;
854
+ let amountOut = numerator / denominator;
855
+
856
+ // Apply slippage
857
+ amountOut = amountOut - (amountOut * slippageBasisPoints) / BigInt(10000);
858
+
859
+ return amountOut;
860
+ }
861
+
862
+ /**
863
+ * Calculates the amount of SOL to receive when selling tokens
864
+ * 100% from Rust: src/utils/calc/bonk.rs get_sell_sol_amount_from_token_amount
865
+ */
866
+ export function getBonkSellSolAmountFromTokenAmount(
867
+ amountIn: bigint,
868
+ virtualBase: bigint,
869
+ virtualQuote: bigint,
870
+ realBase: bigint,
871
+ realQuote: bigint,
872
+ slippageBasisPoints: bigint
873
+ ): bigint {
874
+ const amountInU128 = amountIn;
875
+
876
+ // For sell, input_reserve is token reserves, output_reserve is SOL reserves
877
+ const inputReserve = virtualBase - realBase;
878
+ const outputReserve = virtualQuote + realQuote;
879
+
880
+ // Use constant product formula
881
+ const numerator = amountInU128 * outputReserve;
882
+ const denominator = inputReserve + amountInU128;
883
+ const solAmountOut = numerator / denominator;
884
+
885
+ // Fee rates from Bonk - 100% from Rust: src/instruction/utils/bonk.rs accounts
886
+ const PROTOCOL_FEE_RATE = BigInt(25); // 0.25%
887
+ const PLATFORM_FEE_RATE = BigInt(100); // 1%
888
+ const SHARE_FEE_RATE = BigInt(0); // 0%
889
+
890
+ // Calculate fees
891
+ const protocolFee = (solAmountOut * PROTOCOL_FEE_RATE) / BigInt(10000);
892
+ const platformFee = (solAmountOut * PLATFORM_FEE_RATE) / BigInt(10000);
893
+ const shareFee = (solAmountOut * SHARE_FEE_RATE) / BigInt(10000);
894
+
895
+ // Net SOL after fees
896
+ const solAmountNet = solAmountOut - protocolFee - platformFee - shareFee;
897
+
898
+ // Apply slippage
899
+ const finalAmount = solAmountNet - (solAmountNet * slippageBasisPoints) / BigInt(10000);
900
+
901
+ return finalAmount;
902
+ }
903
+
904
+ // ===== Raydium CPMM Calculations - from Rust: src/utils/calc/raydium_cpmm.rs =====
905
+
906
+ export interface RaydiumCpmmComputeSwapParams {
907
+ allTrade: boolean;
908
+ amountIn: bigint;
909
+ amountOut: bigint;
910
+ minAmountOut: bigint;
911
+ fee: bigint;
912
+ }
913
+
914
+ export interface RaydiumCpmmSwapResult {
915
+ newInputVaultAmount: bigint;
916
+ newOutputVaultAmount: bigint;
917
+ inputAmount: bigint;
918
+ outputAmount: bigint;
919
+ tradeFee: bigint;
920
+ protocolFee: bigint;
921
+ fundFee: bigint;
922
+ creatorFee: bigint;
923
+ }
924
+
925
+ // Raydium CPMM fee constants
926
+ const RAYDIUM_CPMM_FEE_RATE_DENOMINATOR = BigInt(1_000_000);
927
+ const RAYDIUM_CPMM_TRADE_FEE_RATE = BigInt(2500);
928
+ const RAYDIUM_CPMM_CREATOR_FEE_RATE = BigInt(0);
929
+ const RAYDIUM_CPMM_PROTOCOL_FEE_RATE = BigInt(120000);
930
+ const RAYDIUM_CPMM_FUND_FEE_RATE = BigInt(40000);
931
+
932
+ function computeRaydiumCpmmTradingFee(amount: bigint, feeRate: bigint): bigint {
933
+ const numerator = amount * feeRate;
934
+ return (numerator + RAYDIUM_CPMM_FEE_RATE_DENOMINATOR - BigInt(1)) / RAYDIUM_CPMM_FEE_RATE_DENOMINATOR;
935
+ }
936
+
937
+ function computeRaydiumCpmmProtocolFundFee(amount: bigint, feeRate: bigint): bigint {
938
+ const numerator = amount * feeRate;
939
+ return numerator / RAYDIUM_CPMM_FEE_RATE_DENOMINATOR;
940
+ }
941
+
942
+ /**
943
+ * Computes swap parameters for Raydium CPMM
944
+ * 100% from Rust: src/utils/calc/raydium_cpmm.rs compute_swap_amount
945
+ */
946
+ export function computeRaydiumCpmmSwapAmount(
947
+ baseReserve: bigint,
948
+ quoteReserve: bigint,
949
+ isBaseIn: boolean,
950
+ amountIn: bigint,
951
+ slippageBasisPoints: bigint
952
+ ): RaydiumCpmmComputeSwapParams {
953
+ const [inputReserve, outputReserve] = isBaseIn
954
+ ? [baseReserve, quoteReserve]
955
+ : [quoteReserve, baseReserve];
956
+
957
+ // Calculate swap
958
+ const tradeFee = computeRaydiumCpmmTradingFee(amountIn, RAYDIUM_CPMM_TRADE_FEE_RATE);
959
+ const inputAmountLessFees = amountIn - tradeFee;
960
+
961
+ const protocolFee = computeRaydiumCpmmProtocolFundFee(tradeFee, RAYDIUM_CPMM_PROTOCOL_FEE_RATE);
962
+ const fundFee = computeRaydiumCpmmProtocolFundFee(tradeFee, RAYDIUM_CPMM_FUND_FEE_RATE);
963
+
964
+ // Calculate output
965
+ const outputAmountSwapped = (outputReserve * inputAmountLessFees) / (inputReserve + inputAmountLessFees);
966
+ const outputAmount = outputAmountSwapped; // Creator fee is 0
967
+
968
+ // Calculate min amount out with slippage
969
+ const minAmountOut = outputAmount - (outputAmount * slippageBasisPoints) / BigInt(10000);
970
+
971
+ const allTrade = true;
972
+
973
+ return {
974
+ allTrade,
975
+ amountIn,
976
+ amountOut: outputAmount,
977
+ minAmountOut,
978
+ fee: tradeFee,
979
+ };
980
+ }
981
+
982
+ // ===== Raydium AMM V4 Calculations - from Rust: src/utils/calc/raydium_amm_v4.rs =====
983
+
984
+ const RAYDIUM_AMM_V4_SWAP_FEE_NUMERATOR = BigInt(25);
985
+ const RAYDIUM_AMM_V4_SWAP_FEE_DENOMINATOR = BigInt(10000);
986
+ const RAYDIUM_AMM_V4_TRADE_FEE_NUMERATOR = BigInt(25);
987
+ const RAYDIUM_AMM_V4_TRADE_FEE_DENOMINATOR = BigInt(10000);
988
+
989
+ /**
990
+ * Computes swap parameters for Raydium AMM V4
991
+ * 100% from Rust: src/utils/calc/raydium_amm_v4.rs compute_swap_amount
992
+ */
993
+ export function computeRaydiumAmmV4SwapAmount(
994
+ baseReserve: bigint,
995
+ quoteReserve: bigint,
996
+ isBaseIn: boolean,
997
+ amountIn: bigint,
998
+ slippageBasisPoints: bigint
999
+ ): RaydiumCpmmComputeSwapParams {
1000
+ const [inputReserve, outputReserve] = isBaseIn
1001
+ ? [baseReserve, quoteReserve]
1002
+ : [quoteReserve, baseReserve];
1003
+
1004
+ // Calculate trade fee
1005
+ const tradeFeeNumerator = amountIn * RAYDIUM_AMM_V4_TRADE_FEE_NUMERATOR;
1006
+ const tradeFee = (tradeFeeNumerator + RAYDIUM_AMM_V4_TRADE_FEE_DENOMINATOR - BigInt(1)) / RAYDIUM_AMM_V4_TRADE_FEE_DENOMINATOR;
1007
+
1008
+ const inputAmountLessFees = amountIn - tradeFee;
1009
+
1010
+ // Calculate swap fee
1011
+ const swapFeeNumerator = tradeFee * RAYDIUM_AMM_V4_SWAP_FEE_NUMERATOR;
1012
+ const swapFee = swapFeeNumerator / RAYDIUM_AMM_V4_SWAP_FEE_DENOMINATOR;
1013
+
1014
+ // Calculate output
1015
+ const outputAmountSwapped = (outputReserve * inputAmountLessFees) / (inputReserve + inputAmountLessFees);
1016
+ const outputAmount = outputAmountSwapped - swapFee;
1017
+
1018
+ // Calculate min amount out with slippage
1019
+ const minAmountOut = outputAmount - (outputAmount * slippageBasisPoints) / BigInt(10000);
1020
+
1021
+ return {
1022
+ allTrade: true,
1023
+ amountIn,
1024
+ amountOut: outputAmount,
1025
+ minAmountOut,
1026
+ fee: tradeFee,
1027
+ };
1028
+ }
1029
+
1030
+ // ===== Raydium CLMM Price Calculations - from Rust: src/utils/price/raydium_clmm.rs =====
1031
+
1032
+ /**
1033
+ * Calculate the price of token0 in token1 from sqrt price
1034
+ * 100% from Rust: src/utils/price/raydium_clmm.rs price_token0_in_token1
1035
+ */
1036
+ export function priceToken0InToken1(
1037
+ sqrtPriceX64: bigint,
1038
+ decimalsToken0: number,
1039
+ decimalsToken1: number
1040
+ ): number {
1041
+ const sqrtPrice = Number(sqrtPriceX64) / Math.pow(2, 64); // Q64.64 to float
1042
+ const priceRaw = sqrtPrice * sqrtPrice; // Price without decimal adjustment
1043
+ const scale = Math.pow(10, decimalsToken0 - decimalsToken1);
1044
+ return priceRaw * scale;
1045
+ }
1046
+
1047
+ /**
1048
+ * Calculate the price of token1 in token0 from sqrt price
1049
+ * 100% from Rust: src/utils/price/raydium_clmm.rs price_token1_in_token0
1050
+ */
1051
+ export function priceToken1InToken0(
1052
+ sqrtPriceX64: bigint,
1053
+ decimalsToken0: number,
1054
+ decimalsToken1: number
1055
+ ): number {
1056
+ return 1.0 / priceToken0InToken1(sqrtPriceX64, decimalsToken0, decimalsToken1);
1057
+ }
1058
+