@stabbleorg/mclmm-sdk 0.3.1 → 0.3.3

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/lib/index.js CHANGED
@@ -66,6 +66,7 @@ __export(index_exports, {
66
66
  PoolManager: () => PoolManager,
67
67
  PoolUtils: () => PoolUtils,
68
68
  PositionManager: () => PositionManager,
69
+ PositionUtils: () => PositionUtils,
69
70
  PriceApiClient: () => PriceApiClient,
70
71
  Q128: () => Q128,
71
72
  Q64: () => Q64,
@@ -5348,6 +5349,22 @@ var TickUtils = class _TickUtils {
5348
5349
  );
5349
5350
  }
5350
5351
  }
5352
+ static getTickOffsetInArray(tickIndex, tickSpacing) {
5353
+ if (tickIndex % tickSpacing != 0) {
5354
+ throw new Error("tickIndex % tickSpacing not equal 0");
5355
+ }
5356
+ const startTickIndex = _TickUtils.getTickArrayStartIndexByTick(
5357
+ tickIndex,
5358
+ tickSpacing
5359
+ );
5360
+ const offsetInArray = Math.floor(
5361
+ (tickIndex - startTickIndex) / tickSpacing
5362
+ );
5363
+ if (offsetInArray < 0 || offsetInArray >= TICK_ARRAY_SIZE) {
5364
+ throw new Error("tick offset in array overflow");
5365
+ }
5366
+ return offsetInArray;
5367
+ }
5351
5368
  /**
5352
5369
  * Get the start index of the tick array containing a specific tick
5353
5370
  * @param tick - Target tick
@@ -7471,6 +7488,268 @@ var PoolUtils = class {
7471
7488
  }
7472
7489
  };
7473
7490
 
7491
+ // src/utils/position.ts
7492
+ var import_bn5 = __toESM(require("bn.js"));
7493
+ var PositionUtils = class _PositionUtils {
7494
+ /**
7495
+ * Calculate fee growth inside a position's tick range.
7496
+ *
7497
+ * formula:
7498
+ * ```
7499
+ * feeGrowthInside = feeGrowthGlobal - feeGrowthBelow - feeGrowthAbove
7500
+ * ```
7501
+ *
7502
+ * Where feeGrowthBelow and feeGrowthAbove depend on the current tick
7503
+ * relative to the position's tick boundaries.
7504
+ *
7505
+ * @param params - Parameters for fee growth calculation
7506
+ * @returns Fee growth inside for both tokens (X64 fixed-point)
7507
+ */
7508
+ static getFeeGrowthInside(params) {
7509
+ const {
7510
+ tickCurrent,
7511
+ tickLower,
7512
+ tickUpper,
7513
+ tickLowerState,
7514
+ tickUpperState,
7515
+ feeGrowthGlobal0X64,
7516
+ feeGrowthGlobal1X64
7517
+ } = params;
7518
+ const feeGrowthGlobal0 = new import_bn5.default(feeGrowthGlobal0X64.toString());
7519
+ const feeGrowthGlobal1 = new import_bn5.default(feeGrowthGlobal1X64.toString());
7520
+ const tickLowerFeeGrowthOutside0 = new import_bn5.default(
7521
+ tickLowerState.feeGrowthOutside0X64.toString()
7522
+ );
7523
+ const tickLowerFeeGrowthOutside1 = new import_bn5.default(
7524
+ tickLowerState.feeGrowthOutside1X64.toString()
7525
+ );
7526
+ const tickUpperFeeGrowthOutside0 = new import_bn5.default(
7527
+ tickUpperState.feeGrowthOutside0X64.toString()
7528
+ );
7529
+ const tickUpperFeeGrowthOutside1 = new import_bn5.default(
7530
+ tickUpperState.feeGrowthOutside1X64.toString()
7531
+ );
7532
+ let feeGrowthBelow0X64;
7533
+ let feeGrowthBelow1X64;
7534
+ if (tickCurrent >= tickLower) {
7535
+ feeGrowthBelow0X64 = tickLowerFeeGrowthOutside0;
7536
+ feeGrowthBelow1X64 = tickLowerFeeGrowthOutside1;
7537
+ } else {
7538
+ feeGrowthBelow0X64 = MathUtils.wrappingSubU128(
7539
+ feeGrowthGlobal0,
7540
+ tickLowerFeeGrowthOutside0
7541
+ );
7542
+ feeGrowthBelow1X64 = MathUtils.wrappingSubU128(
7543
+ feeGrowthGlobal1,
7544
+ tickLowerFeeGrowthOutside1
7545
+ );
7546
+ }
7547
+ let feeGrowthAbove0X64;
7548
+ let feeGrowthAbove1X64;
7549
+ if (tickCurrent < tickUpper) {
7550
+ feeGrowthAbove0X64 = tickUpperFeeGrowthOutside0;
7551
+ feeGrowthAbove1X64 = tickUpperFeeGrowthOutside1;
7552
+ } else {
7553
+ feeGrowthAbove0X64 = MathUtils.wrappingSubU128(
7554
+ feeGrowthGlobal0,
7555
+ tickUpperFeeGrowthOutside0
7556
+ );
7557
+ feeGrowthAbove1X64 = MathUtils.wrappingSubU128(
7558
+ feeGrowthGlobal1,
7559
+ tickUpperFeeGrowthOutside1
7560
+ );
7561
+ }
7562
+ const feeGrowthInside0X64 = MathUtils.wrappingSubU128(
7563
+ MathUtils.wrappingSubU128(feeGrowthGlobal0, feeGrowthBelow0X64),
7564
+ feeGrowthAbove0X64
7565
+ );
7566
+ const feeGrowthInside1X64 = MathUtils.wrappingSubU128(
7567
+ MathUtils.wrappingSubU128(feeGrowthGlobal1, feeGrowthBelow1X64),
7568
+ feeGrowthAbove1X64
7569
+ );
7570
+ return {
7571
+ feeGrowthInside0X64,
7572
+ feeGrowthInside1X64
7573
+ };
7574
+ }
7575
+ /**
7576
+ * Calculate pending fees for a position.
7577
+ *
7578
+ * Formula:
7579
+ * ```
7580
+ * feeDelta = (feeGrowthInside - feeGrowthInsideLast) × liquidity / 2^64
7581
+ * totalFees = tokenFeesOwed + feeDelta
7582
+ * ```
7583
+ *
7584
+ * @param params - Parameters for fee calculation
7585
+ * @returns Pending fees for both tokens in native units
7586
+ */
7587
+ static getPositionFees(params) {
7588
+ const {
7589
+ liquidity,
7590
+ tickLower,
7591
+ tickUpper,
7592
+ feeGrowthInside0LastX64,
7593
+ feeGrowthInside1LastX64,
7594
+ tokenFeesOwed0,
7595
+ tokenFeesOwed1,
7596
+ tickCurrent,
7597
+ feeGrowthGlobal0X64,
7598
+ feeGrowthGlobal1X64,
7599
+ tickLowerState,
7600
+ tickUpperState
7601
+ } = params;
7602
+ const { feeGrowthInside0X64, feeGrowthInside1X64 } = _PositionUtils.getFeeGrowthInside({
7603
+ tickCurrent,
7604
+ tickLower,
7605
+ tickUpper,
7606
+ tickLowerState,
7607
+ tickUpperState,
7608
+ feeGrowthGlobal0X64,
7609
+ feeGrowthGlobal1X64
7610
+ });
7611
+ const liquidityBN = new import_bn5.default(liquidity.toString());
7612
+ const feeGrowthInside0Last = new import_bn5.default(feeGrowthInside0LastX64.toString());
7613
+ const feeGrowthInside1Last = new import_bn5.default(feeGrowthInside1LastX64.toString());
7614
+ const feesOwed0 = new import_bn5.default(tokenFeesOwed0.toString());
7615
+ const feesOwed1 = new import_bn5.default(tokenFeesOwed1.toString());
7616
+ const feeGrowthDelta0 = MathUtils.wrappingSubU128(
7617
+ feeGrowthInside0X64,
7618
+ feeGrowthInside0Last
7619
+ );
7620
+ const feeGrowthDelta1 = MathUtils.wrappingSubU128(
7621
+ feeGrowthInside1X64,
7622
+ feeGrowthInside1Last
7623
+ );
7624
+ const feeAmount0 = MathUtils.mulDivFloor(feeGrowthDelta0, liquidityBN, Q64);
7625
+ const feeAmount1 = MathUtils.mulDivFloor(feeGrowthDelta1, liquidityBN, Q64);
7626
+ return {
7627
+ tokenFees0: feesOwed0.add(feeAmount0),
7628
+ tokenFees1: feesOwed1.add(feeAmount1)
7629
+ };
7630
+ }
7631
+ /**
7632
+ * Calculate reward growth inside a position's tick range for all reward tokens.
7633
+ *
7634
+ * Formula:
7635
+ * ```
7636
+ * rewardGrowthInside = rewardGrowthGlobal - rewardGrowthBelow - rewardGrowthAbove
7637
+ * ```
7638
+ *
7639
+ * Special cases:
7640
+ * - If tickLower has no liquidity (liquidityGross = 0), rewardGrowthBelow = rewardGrowthGlobal
7641
+ * - If tickUpper has no liquidity (liquidityGross = 0), rewardGrowthAbove = 0
7642
+ *
7643
+ * @param params - Parameters for reward growth calculation
7644
+ * @returns Reward growth inside for each reward token (X64 fixed-point)
7645
+ */
7646
+ static getRewardGrowthInside(params) {
7647
+ const {
7648
+ tickCurrent,
7649
+ tickLower,
7650
+ tickUpper,
7651
+ tickLowerState,
7652
+ tickUpperState,
7653
+ rewardInfos
7654
+ } = params;
7655
+ const rewardGrowthsInside = [];
7656
+ for (let i = 0; i < rewardInfos.length; i++) {
7657
+ const rewardGrowthGlobal = new import_bn5.default(
7658
+ rewardInfos[i].rewardGrowthGlobalX64.toString()
7659
+ );
7660
+ let rewardGrowthBelow;
7661
+ if (tickLowerState.liquidityGross === 0n) {
7662
+ rewardGrowthBelow = rewardGrowthGlobal;
7663
+ } else if (tickCurrent < tickLower) {
7664
+ rewardGrowthBelow = rewardGrowthGlobal.sub(
7665
+ new import_bn5.default(tickLowerState.rewardGrowthsOutsideX64[i].toString())
7666
+ );
7667
+ } else {
7668
+ rewardGrowthBelow = new import_bn5.default(
7669
+ tickLowerState.rewardGrowthsOutsideX64[i].toString()
7670
+ );
7671
+ }
7672
+ let rewardGrowthAbove;
7673
+ if (tickUpperState.liquidityGross === 0n) {
7674
+ rewardGrowthAbove = new import_bn5.default(0);
7675
+ } else if (tickCurrent < tickUpper) {
7676
+ rewardGrowthAbove = new import_bn5.default(
7677
+ tickUpperState.rewardGrowthsOutsideX64[i].toString()
7678
+ );
7679
+ } else {
7680
+ rewardGrowthAbove = rewardGrowthGlobal.sub(
7681
+ new import_bn5.default(tickUpperState.rewardGrowthsOutsideX64[i].toString())
7682
+ );
7683
+ }
7684
+ const rewardGrowthInside = MathUtils.wrappingSubU128(
7685
+ MathUtils.wrappingSubU128(rewardGrowthGlobal, rewardGrowthBelow),
7686
+ rewardGrowthAbove
7687
+ );
7688
+ rewardGrowthsInside.push(rewardGrowthInside);
7689
+ }
7690
+ return rewardGrowthsInside;
7691
+ }
7692
+ /**
7693
+ * Calculate pending rewards for a position.
7694
+ *
7695
+ * Formula:
7696
+ * ```
7697
+ * rewardDelta = (rewardGrowthInside - rewardGrowthInsideLast) × liquidity / 2^64
7698
+ * totalReward = rewardAmountOwed + rewardDelta
7699
+ * ```
7700
+ *
7701
+ * @param params - Parameters for reward calculation
7702
+ * @returns Pending rewards for each reward token in native units
7703
+ */
7704
+ static getPositionRewards(params) {
7705
+ const {
7706
+ liquidity,
7707
+ tickLower,
7708
+ tickUpper,
7709
+ positionRewardInfos,
7710
+ tickCurrent,
7711
+ rewardInfos,
7712
+ tickLowerState,
7713
+ tickUpperState
7714
+ } = params;
7715
+ const rewardGrowthsInside = _PositionUtils.getRewardGrowthInside({
7716
+ tickCurrent,
7717
+ tickLower,
7718
+ tickUpper,
7719
+ tickLowerState,
7720
+ tickUpperState,
7721
+ rewardInfos
7722
+ });
7723
+ const liquidityBN = new import_bn5.default(liquidity.toString());
7724
+ const rewards = [];
7725
+ for (let i = 0; i < rewardGrowthsInside.length; i++) {
7726
+ const rewardGrowthInside = rewardGrowthsInside[i];
7727
+ const positionRewardInfo = positionRewardInfos[i];
7728
+ if (!positionRewardInfo) {
7729
+ rewards.push(new import_bn5.default(0));
7730
+ continue;
7731
+ }
7732
+ const growthInsideLast = new import_bn5.default(
7733
+ positionRewardInfo.growthInsideLastX64.toString()
7734
+ );
7735
+ const rewardAmountOwed = new import_bn5.default(
7736
+ positionRewardInfo.rewardAmountOwed.toString()
7737
+ );
7738
+ const rewardGrowthDelta = MathUtils.wrappingSubU128(
7739
+ rewardGrowthInside,
7740
+ growthInsideLast
7741
+ );
7742
+ const rewardAmountDelta = MathUtils.mulDivFloor(
7743
+ rewardGrowthDelta,
7744
+ liquidityBN,
7745
+ Q64
7746
+ );
7747
+ rewards.push(rewardAmountOwed.add(rewardAmountDelta));
7748
+ }
7749
+ return { rewards };
7750
+ }
7751
+ };
7752
+
7474
7753
  // src/utils/index.ts
7475
7754
  var import_kit51 = require("@solana/kit");
7476
7755
  function validateAddress(address6, name = "address") {
@@ -7636,7 +7915,7 @@ var Clmm = class {
7636
7915
  // src/pool-manager.ts
7637
7916
  var import_kit52 = require("@solana/kit");
7638
7917
  var import_token2 = require("@solana-program/token");
7639
- var import_bn5 = __toESM(require("bn.js"));
7918
+ var import_bn6 = __toESM(require("bn.js"));
7640
7919
  var import_decimal3 = __toESM(require("decimal.js"));
7641
7920
 
7642
7921
  // src/utils/token.ts
@@ -7675,8 +7954,8 @@ var PoolManager = class {
7675
7954
  } = params;
7676
7955
  const addressA = (0, import_kit52.address)(tokenMintA);
7677
7956
  const addressB = (0, import_kit52.address)(tokenMintB);
7678
- const isAFirst = new import_bn5.default(Buffer.from(addressB)).gt(
7679
- new import_bn5.default(Buffer.from(addressA))
7957
+ const isAFirst = new import_bn6.default(Buffer.from(addressB)).gt(
7958
+ new import_bn6.default(Buffer.from(addressA))
7680
7959
  );
7681
7960
  const [token0, token1, decimals0, decimals1, priceAdjusted] = isAFirst ? [tokenMintA, tokenMintB, mintADecimals, mintBDecimals, initialPrice] : [
7682
7961
  tokenMintB,
@@ -7858,7 +8137,7 @@ var PoolManager = class {
7858
8137
  getToken(this.config.rpc, poolState.tokenVault1)
7859
8138
  ]);
7860
8139
  const currentPrice = this.calculatePoolPrice(
7861
- new import_bn5.default(poolState.sqrtPriceX64.toString()),
8140
+ new import_bn6.default(poolState.sqrtPriceX64.toString()),
7862
8141
  tokenA.decimals,
7863
8142
  tokenB.decimals
7864
8143
  );
@@ -7903,7 +8182,7 @@ var PoolManager = class {
7903
8182
  var import_kit53 = require("@solana/kit");
7904
8183
  var import_token4 = require("@solana-program/token");
7905
8184
  var import_token_20222 = require("@solana-program/token-2022");
7906
- var import_bn6 = __toESM(require("bn.js"));
8185
+ var import_bn7 = __toESM(require("bn.js"));
7907
8186
 
7908
8187
  // ../node_modules/@solana/spl-token/lib/esm/constants.js
7909
8188
  var import_web3 = require("@solana/web3.js");
@@ -7940,16 +8219,6 @@ var PositionManager = class {
7940
8219
  (0, import_token4.getSyncNativeInstruction)({ account: ata })
7941
8220
  ];
7942
8221
  }
7943
- buildUnwrapSolInstruction(params) {
7944
- const { owner, destination, ata } = params;
7945
- return [
7946
- (0, import_token4.getCloseAccountInstruction)({
7947
- account: ata,
7948
- destination,
7949
- owner
7950
- })
7951
- ];
7952
- }
7953
8222
  /**
7954
8223
  * Build partial unwrap SOL instructions using a temp account:
7955
8224
  * 1. Create temp account
@@ -8387,27 +8656,17 @@ var PositionManager = class {
8387
8656
  ];
8388
8657
  if (isNative) {
8389
8658
  const destination = ownerInfo.wallet.address;
8390
- const isFullWithdrawal = liquidity === ownerPosition.liquidity;
8391
8659
  const isTokenANative = poolState.data.tokenMint0.toString() === NATIVE_MINT.toString();
8392
8660
  const wsolAta = isTokenANative ? ownerInfo.tokenAccountA : ownerInfo.tokenAccountB;
8393
8661
  const amount = isTokenANative ? amountMinA : amountMinB;
8394
- if (isFullWithdrawal) {
8395
- const unwrapIxs = this.buildUnwrapSolInstruction({
8396
- ata: wsolAta,
8397
- owner: ownerInfo.wallet.address,
8398
- destination
8399
- });
8400
- instructions.push(...unwrapIxs);
8401
- } else {
8402
- const { instructions: partialUnwrapIxs, signers: partialSigners } = await this.buildPartialUnwrapSolInstructions({
8403
- payer: ownerInfo.wallet,
8404
- sourceAta: wsolAta,
8405
- destination,
8406
- amount
8407
- });
8408
- instructions.push(...partialUnwrapIxs);
8409
- signers.push(...partialSigners);
8410
- }
8662
+ const { instructions: unwrapIxs, signers: unwrapSigners } = await this.buildPartialUnwrapSolInstructions({
8663
+ payer: ownerInfo.wallet,
8664
+ sourceAta: wsolAta,
8665
+ destination,
8666
+ amount
8667
+ });
8668
+ instructions.push(...unwrapIxs);
8669
+ signers.push(...unwrapSigners);
8411
8670
  }
8412
8671
  return {
8413
8672
  instructions,
@@ -8481,21 +8740,22 @@ var PositionManager = class {
8481
8740
  * Enrich position state with computed fields from pool data
8482
8741
  * @param position - Raw position state from blockchain
8483
8742
  * @param pool - Pool state from blockchain
8743
+ * @param fees - Position fees
8484
8744
  * @returns Enriched position info with calculated amounts and prices
8485
8745
  */
8486
- enrichPositionInfo(position, pool) {
8746
+ enrichPositionInfo(position, pool, fees, rewards) {
8487
8747
  const sqrtPriceLowerX64 = SqrtPriceMath.getSqrtPriceX64FromTick(
8488
8748
  position.tickLowerIndex
8489
8749
  );
8490
8750
  const sqrtPriceUpperX64 = SqrtPriceMath.getSqrtPriceX64FromTick(
8491
8751
  position.tickUpperIndex
8492
8752
  );
8493
- const sqrtPriceCurrentX64 = new import_bn6.default(pool.sqrtPriceX64.toString());
8753
+ const sqrtPriceCurrentX64 = new import_bn7.default(pool.sqrtPriceX64.toString());
8494
8754
  const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
8495
8755
  sqrtPriceCurrentX64,
8496
8756
  sqrtPriceLowerX64,
8497
8757
  sqrtPriceUpperX64,
8498
- new import_bn6.default(position.liquidity.toString()),
8758
+ new import_bn7.default(position.liquidity.toString()),
8499
8759
  true
8500
8760
  );
8501
8761
  const [_amountA, _amountB] = [
@@ -8516,9 +8776,13 @@ var PositionManager = class {
8516
8776
  });
8517
8777
  const inRange = pool.tickCurrent >= position.tickLowerIndex && pool.tickCurrent < position.tickUpperIndex;
8518
8778
  const unclaimedFees = {
8519
- token0: new import_bn6.default(position.tokenFeesOwed0.toString()),
8520
- token1: new import_bn6.default(position.tokenFeesOwed1.toString())
8779
+ token0: fees?.tokenFees0 ? fees?.tokenFees0 : new import_bn7.default(0),
8780
+ token1: fees?.tokenFees1 ? fees?.tokenFees1 : new import_bn7.default(0)
8521
8781
  };
8782
+ const unclaimedRewards = rewards?.rewards ? rewards.rewards.map((amount, i) => ({
8783
+ mint: pool.rewardInfos[i]?.tokenMint,
8784
+ amount
8785
+ })).filter((r) => r.mint !== void 0) : void 0;
8522
8786
  const ageSeconds = 0;
8523
8787
  return {
8524
8788
  ...position,
@@ -8531,10 +8795,8 @@ var PositionManager = class {
8531
8795
  inRange,
8532
8796
  ageSeconds,
8533
8797
  unclaimedFees,
8534
- // valueUsd is optional and requires external price feeds
8535
- valueUsd: void 0,
8536
- // unclaimedRewards is optional
8537
- unclaimedRewards: void 0
8798
+ unclaimedRewards,
8799
+ valueUsd: void 0
8538
8800
  };
8539
8801
  }
8540
8802
  /**
@@ -8574,7 +8836,16 @@ var PositionManager = class {
8574
8836
  console.warn(`Pool ${position.poolId} not found for position`);
8575
8837
  return null;
8576
8838
  }
8577
- return this.enrichPositionInfo(position, poolAccount.data);
8839
+ const { fees, rewards } = await this.getPositionFeeAndRewards(
8840
+ position,
8841
+ poolAccount.data
8842
+ );
8843
+ return this.enrichPositionInfo(
8844
+ position,
8845
+ poolAccount.data,
8846
+ fees,
8847
+ rewards
8848
+ );
8578
8849
  } catch (error) {
8579
8850
  console.error(`Failed to enrich position: ${error}`);
8580
8851
  return null;
@@ -8589,6 +8860,101 @@ var PositionManager = class {
8589
8860
  );
8590
8861
  }
8591
8862
  }
8863
+ /**
8864
+ * Calculate pending fees and rewards for a position.
8865
+ *
8866
+ * @param position - Personal position state
8867
+ * @param pool - Pool state
8868
+ * @returns Pending fees for both tokens and rewards for each reward token (up to 3)
8869
+ */
8870
+ async getPositionFeeAndRewards(position, pool) {
8871
+ const [tickArrayLower] = await PdaUtils.getTickArrayStatePda(
8872
+ position.poolId,
8873
+ PdaUtils.getTickArrayStartIndex(
8874
+ position.tickLowerIndex,
8875
+ pool.tickSpacing
8876
+ )
8877
+ );
8878
+ const [tickArrayUpper] = await PdaUtils.getTickArrayStatePda(
8879
+ position.poolId,
8880
+ PdaUtils.getTickArrayStartIndex(
8881
+ position.tickUpperIndex,
8882
+ pool.tickSpacing
8883
+ )
8884
+ );
8885
+ const tickArrayLowerAccount = await fetchMaybeTickArrayState(
8886
+ this.config.rpc,
8887
+ tickArrayLower
8888
+ );
8889
+ const tickArrayUpperAccount = await fetchMaybeTickArrayState(
8890
+ this.config.rpc,
8891
+ tickArrayUpper
8892
+ );
8893
+ if (!tickArrayLowerAccount.exists || !tickArrayUpperAccount.exists) {
8894
+ console.log(
8895
+ "[getPositionFeeAndRewards] tick array state accounts do not exist."
8896
+ );
8897
+ return {
8898
+ fees: { tokenFees0: new import_bn7.default(0), tokenFees1: new import_bn7.default(0) },
8899
+ rewards: { rewards: [new import_bn7.default(0), new import_bn7.default(0), new import_bn7.default(0)] }
8900
+ };
8901
+ }
8902
+ const tickSpacing = pool.tickSpacing;
8903
+ const tickArrayLowerIndex = TickUtils.getTickOffsetInArray(
8904
+ position.tickLowerIndex,
8905
+ tickSpacing
8906
+ );
8907
+ const tickArrayUpperIndex = TickUtils.getTickOffsetInArray(
8908
+ position.tickUpperIndex,
8909
+ tickSpacing
8910
+ );
8911
+ if (tickArrayLowerIndex < 0 || tickArrayUpperIndex < 0) {
8912
+ console.log("[getPositionFeeAndRewards] tick array indexes < 0.");
8913
+ return {
8914
+ fees: { tokenFees0: new import_bn7.default(0), tokenFees1: new import_bn7.default(0) },
8915
+ rewards: { rewards: [new import_bn7.default(0), new import_bn7.default(0), new import_bn7.default(0)] }
8916
+ };
8917
+ }
8918
+ const lowerTickState = tickArrayLowerAccount.data.ticks[tickArrayLowerIndex];
8919
+ const upperTickState = tickArrayUpperAccount.data.ticks[tickArrayUpperIndex];
8920
+ const fees = PositionUtils.getPositionFees({
8921
+ liquidity: position.liquidity,
8922
+ tickLower: position.tickLowerIndex,
8923
+ tickUpper: position.tickUpperIndex,
8924
+ feeGrowthInside0LastX64: position.feeGrowthInside0LastX64,
8925
+ feeGrowthInside1LastX64: position.feeGrowthInside1LastX64,
8926
+ tokenFeesOwed0: position.tokenFeesOwed0,
8927
+ tokenFeesOwed1: position.tokenFeesOwed1,
8928
+ tickCurrent: pool.tickCurrent,
8929
+ feeGrowthGlobal0X64: pool.feeGrowthGlobal0X64,
8930
+ feeGrowthGlobal1X64: pool.feeGrowthGlobal1X64,
8931
+ tickLowerState: {
8932
+ feeGrowthOutside0X64: lowerTickState.feeGrowthOutside0X64,
8933
+ feeGrowthOutside1X64: lowerTickState.feeGrowthOutside1X64
8934
+ },
8935
+ tickUpperState: {
8936
+ feeGrowthOutside0X64: upperTickState.feeGrowthOutside0X64,
8937
+ feeGrowthOutside1X64: upperTickState.feeGrowthOutside1X64
8938
+ }
8939
+ });
8940
+ const rewards = PositionUtils.getPositionRewards({
8941
+ liquidity: position.liquidity,
8942
+ tickLower: position.tickLowerIndex,
8943
+ tickUpper: position.tickUpperIndex,
8944
+ positionRewardInfos: position.rewardInfos,
8945
+ tickCurrent: pool.tickCurrent,
8946
+ rewardInfos: pool.rewardInfos,
8947
+ tickLowerState: {
8948
+ liquidityGross: lowerTickState.liquidityGross,
8949
+ rewardGrowthsOutsideX64: lowerTickState.rewardGrowthsOutsideX64
8950
+ },
8951
+ tickUpperState: {
8952
+ liquidityGross: upperTickState.liquidityGross,
8953
+ rewardGrowthsOutsideX64: upperTickState.rewardGrowthsOutsideX64
8954
+ }
8955
+ });
8956
+ return { fees, rewards };
8957
+ }
8592
8958
  };
8593
8959
 
8594
8960
  // src/api/config.ts
@@ -9560,7 +9926,7 @@ var PriceApiClient = class _PriceApiClient {
9560
9926
  };
9561
9927
 
9562
9928
  // src/swap.ts
9563
- var import_bn7 = __toESM(require("bn.js"));
9929
+ var import_bn8 = __toESM(require("bn.js"));
9564
9930
  var import_decimal6 = __toESM(require("decimal.js"));
9565
9931
  var DEFAULT_RETRY_CONFIG = {
9566
9932
  maxRetries: 3,
@@ -9620,7 +9986,7 @@ var SwapMathEngine = class {
9620
9986
  slippageTolerance,
9621
9987
  poolAddress
9622
9988
  } = params;
9623
- if (amountIn.lte(new import_bn7.default(0))) {
9989
+ if (amountIn.lte(new import_bn8.default(0))) {
9624
9990
  throw new ClmmError(
9625
9991
  "SWAP_AMOUNT_CANNOT_BE_ZERO" /* SWAP_AMOUNT_CANNOT_BE_ZERO */,
9626
9992
  "Swap amount must be greater than zero"
@@ -9632,8 +9998,8 @@ var SwapMathEngine = class {
9632
9998
  `Slippage tolerance must be between 0 and 1, got ${slippageTolerance}`
9633
9999
  );
9634
10000
  }
9635
- const liquidity = new import_bn7.default(pool.liquidity.toString());
9636
- const sqrtPriceCurrentX64 = new import_bn7.default(pool.sqrtPriceX64.toString());
10001
+ const liquidity = new import_bn8.default(pool.liquidity.toString());
10002
+ const sqrtPriceCurrentX64 = new import_bn8.default(pool.sqrtPriceX64.toString());
9637
10003
  const feeRate = ammConfig.tradeFeeRate;
9638
10004
  const sqrtPriceTargetX64 = this.calculateSqrtPriceLimit(
9639
10005
  sqrtPriceCurrentX64,
@@ -9661,9 +10027,9 @@ var SwapMathEngine = class {
9661
10027
  pool.mintDecimals1
9662
10028
  );
9663
10029
  const priceImpact = priceAfter.minus(priceBefore).div(priceBefore).abs().toNumber();
9664
- const slippageBN = new import_bn7.default(Math.floor(slippageTolerance * 1e4));
10030
+ const slippageBN = new import_bn8.default(Math.floor(slippageTolerance * 1e4));
9665
10031
  const minAmountOut = step.amountOut.sub(
9666
- step.amountOut.mul(slippageBN).div(new import_bn7.default(1e4))
10032
+ step.amountOut.mul(slippageBN).div(new import_bn8.default(1e4))
9667
10033
  );
9668
10034
  return {
9669
10035
  amountIn,
@@ -9710,17 +10076,17 @@ var SwapMathEngine = class {
9710
10076
  tickArrayCache
9711
10077
  } = params;
9712
10078
  const sqrtPriceLimitX64 = this.calculateSqrtPriceLimit(
9713
- new import_bn7.default(pool.sqrtPriceX64.toString()),
10079
+ new import_bn8.default(pool.sqrtPriceX64.toString()),
9714
10080
  zeroForOne,
9715
10081
  slippageTolerance
9716
10082
  );
9717
10083
  const result = await SwapMath.swapCompute({
9718
10084
  poolState: {
9719
- sqrtPriceX64: new import_bn7.default(pool.sqrtPriceX64.toString()),
10085
+ sqrtPriceX64: new import_bn8.default(pool.sqrtPriceX64.toString()),
9720
10086
  tickCurrent: pool.tickCurrent,
9721
- liquidity: new import_bn7.default(pool.liquidity.toString()),
9722
- feeGrowthGlobal0X64: new import_bn7.default(pool.feeGrowthGlobal0X64.toString()),
9723
- feeGrowthGlobal1X64: new import_bn7.default(pool.feeGrowthGlobal1X64.toString())
10087
+ liquidity: new import_bn8.default(pool.liquidity.toString()),
10088
+ feeGrowthGlobal0X64: new import_bn8.default(pool.feeGrowthGlobal0X64.toString()),
10089
+ feeGrowthGlobal1X64: new import_bn8.default(pool.feeGrowthGlobal1X64.toString())
9724
10090
  },
9725
10091
  tickArrayCache,
9726
10092
  tickSpacing: pool.tickSpacing,
@@ -9737,7 +10103,7 @@ var SwapMathEngine = class {
9737
10103
  poolId: poolAddress
9738
10104
  });
9739
10105
  const priceBefore = SqrtPriceMath.sqrtPriceX64ToPrice(
9740
- new import_bn7.default(pool.sqrtPriceX64.toString()),
10106
+ new import_bn8.default(pool.sqrtPriceX64.toString()),
9741
10107
  pool.mintDecimals0,
9742
10108
  pool.mintDecimals1
9743
10109
  );
@@ -9747,9 +10113,9 @@ var SwapMathEngine = class {
9747
10113
  pool.mintDecimals1
9748
10114
  );
9749
10115
  const priceImpact = priceAfter.minus(priceBefore).div(priceBefore).abs().toNumber();
9750
- const slippageBN = new import_bn7.default(Math.floor(slippageTolerance * 1e4));
10116
+ const slippageBN = new import_bn8.default(Math.floor(slippageTolerance * 1e4));
9751
10117
  const minAmountOut = result.amountOut.sub(
9752
- result.amountOut.mul(slippageBN).div(new import_bn7.default(1e4))
10118
+ result.amountOut.mul(slippageBN).div(new import_bn8.default(1e4))
9753
10119
  );
9754
10120
  const feeImpact = ammConfig.tradeFeeRate / FEE_RATE_DENOMINATOR_NUMBER;
9755
10121
  return {
@@ -9793,10 +10159,10 @@ var SwapMathEngine = class {
9793
10159
  */
9794
10160
  calculateSqrtPriceLimit(sqrtPriceX64, zeroForOne, slippageTolerance) {
9795
10161
  const bps = Math.floor(slippageTolerance * 1e4);
9796
- const base = new import_bn7.default(1e4);
9797
- const scaled = zeroForOne ? sqrtPriceX64.mul(base.sub(new import_bn7.default(bps))).div(base) : sqrtPriceX64.mul(base.add(new import_bn7.default(bps))).div(base);
9798
- const min2 = new import_bn7.default(MIN_SQRT_PRICE_X64);
9799
- const max = new import_bn7.default(MAX_SQRT_PRICE_X64);
10162
+ const base = new import_bn8.default(1e4);
10163
+ const scaled = zeroForOne ? sqrtPriceX64.mul(base.sub(new import_bn8.default(bps))).div(base) : sqrtPriceX64.mul(base.add(new import_bn8.default(bps))).div(base);
10164
+ const min2 = new import_bn8.default(MIN_SQRT_PRICE_X64);
10165
+ const max = new import_bn8.default(MAX_SQRT_PRICE_X64);
9800
10166
  if (scaled.lt(min2)) return min2;
9801
10167
  if (scaled.gt(max)) return max;
9802
10168
  return scaled;
@@ -10220,7 +10586,7 @@ var SwapManager = class {
10220
10586
  `Invalid slippage tolerance: ${slippageTolerance}. Must be between 0 and 1.`
10221
10587
  );
10222
10588
  }
10223
- if (amountIn.lte(new import_bn7.default(0))) {
10589
+ if (amountIn.lte(new import_bn8.default(0))) {
10224
10590
  throw new ClmmError(
10225
10591
  "SWAP_AMOUNT_CANNOT_BE_ZERO" /* SWAP_AMOUNT_CANNOT_BE_ZERO */,
10226
10592
  "Swap amount must be greater than zero."
@@ -10322,7 +10688,7 @@ var SwapManager = class {
10322
10688
  `Invalid slippage tolerance: ${slippageTolerance}. Must be between 0 and 1.`
10323
10689
  );
10324
10690
  }
10325
- if (amountIn.lte(new import_bn7.default(0))) {
10691
+ if (amountIn.lte(new import_bn8.default(0))) {
10326
10692
  throw new ClmmError(
10327
10693
  "SWAP_AMOUNT_CANNOT_BE_ZERO" /* SWAP_AMOUNT_CANNOT_BE_ZERO */,
10328
10694
  "Swap amount must be greater than zero."
@@ -10376,7 +10742,7 @@ var SwapManager = class {
10376
10742
  poolAddress
10377
10743
  });
10378
10744
  const priceBefore = SqrtPriceMath.sqrtPriceX64ToPrice(
10379
- new import_bn7.default(pool.sqrtPriceX64.toString()),
10745
+ new import_bn8.default(pool.sqrtPriceX64.toString()),
10380
10746
  pool.mintDecimals0,
10381
10747
  pool.mintDecimals1
10382
10748
  );
@@ -10486,21 +10852,21 @@ var SwapManager = class {
10486
10852
  * @returns Number of tick arrays to fetch (includes safety buffer)
10487
10853
  */
10488
10854
  estimateTickArrayCount(pool, amountIn) {
10489
- const liquidity = new import_bn7.default(pool.liquidity.toString());
10490
- if (liquidity.eq(new import_bn7.default(0)) || liquidity.lt(new import_bn7.default(1e3))) {
10855
+ const liquidity = new import_bn8.default(pool.liquidity.toString());
10856
+ if (liquidity.eq(new import_bn8.default(0)) || liquidity.lt(new import_bn8.default(1e3))) {
10491
10857
  return 10;
10492
10858
  }
10493
- const roughImpact = amountIn.mul(new import_bn7.default(1e3)).div(liquidity);
10859
+ const roughImpact = amountIn.mul(new import_bn8.default(1e3)).div(liquidity);
10494
10860
  let baseArrays;
10495
- if (roughImpact.lte(new import_bn7.default(1))) {
10861
+ if (roughImpact.lte(new import_bn8.default(1))) {
10496
10862
  baseArrays = 2;
10497
- } else if (roughImpact.lte(new import_bn7.default(10))) {
10863
+ } else if (roughImpact.lte(new import_bn8.default(10))) {
10498
10864
  baseArrays = 4;
10499
- } else if (roughImpact.lte(new import_bn7.default(50))) {
10865
+ } else if (roughImpact.lte(new import_bn8.default(50))) {
10500
10866
  baseArrays = 6;
10501
- } else if (roughImpact.lte(new import_bn7.default(100))) {
10867
+ } else if (roughImpact.lte(new import_bn8.default(100))) {
10502
10868
  baseArrays = 8;
10503
- } else if (roughImpact.lte(new import_bn7.default(200))) {
10869
+ } else if (roughImpact.lte(new import_bn8.default(200))) {
10504
10870
  baseArrays = 12;
10505
10871
  } else {
10506
10872
  baseArrays = 15;
@@ -10545,7 +10911,7 @@ var SwapManager = class {
10545
10911
  const decOut = zeroForOne ? pool.mintDecimals1 : pool.mintDecimals0;
10546
10912
  const promises = params.amounts.map(async (amountIn) => {
10547
10913
  try {
10548
- if (amountIn.lte(new import_bn7.default(0))) return;
10914
+ if (amountIn.lte(new import_bn8.default(0))) return;
10549
10915
  const quote = await this.mathEngine.calculateSimpleSwap({
10550
10916
  pool,
10551
10917
  ammConfig,
@@ -10587,7 +10953,7 @@ var SwapManager = class {
10587
10953
  options
10588
10954
  );
10589
10955
  const priceBefore = SqrtPriceMath.sqrtPriceX64ToPrice(
10590
- new import_bn7.default(pool.sqrtPriceX64.toString()),
10956
+ new import_bn8.default(pool.sqrtPriceX64.toString()),
10591
10957
  pool.mintDecimals0,
10592
10958
  pool.mintDecimals1
10593
10959
  );
@@ -10710,13 +11076,13 @@ var SwapManager = class {
10710
11076
  `Extremely high price impact: ${(quote.priceImpact * 100).toFixed(2)}%. Swap likely to fail or result in significant slippage.`
10711
11077
  );
10712
11078
  }
10713
- const oneUnit = new import_bn7.default(10).pow(new import_bn7.default(outputDecimals));
11079
+ const oneUnit = new import_bn8.default(10).pow(new import_bn8.default(outputDecimals));
10714
11080
  if (quote.amountOut.lt(oneUnit)) {
10715
11081
  warnings.push(
10716
11082
  `Output amount is less than 1 unit of the output token. Consider increasing input amount or slippage tolerance.`
10717
11083
  );
10718
11084
  }
10719
- if (quote.amountOut.lte(new import_bn7.default(0))) {
11085
+ if (quote.amountOut.lte(new import_bn8.default(0))) {
10720
11086
  errors.push(
10721
11087
  "Swap would result in zero output. Amount may be too small."
10722
11088
  );
@@ -10737,11 +11103,11 @@ var SwapManager = class {
10737
11103
  return {
10738
11104
  quote: {
10739
11105
  amountIn: params.amountIn,
10740
- amountOut: new import_bn7.default(0),
10741
- minAmountOut: new import_bn7.default(0),
11106
+ amountOut: new import_bn8.default(0),
11107
+ minAmountOut: new import_bn8.default(0),
10742
11108
  priceImpact: 0,
10743
11109
  route: [],
10744
- fee: new import_bn7.default(0)
11110
+ fee: new import_bn8.default(0)
10745
11111
  },
10746
11112
  willSucceed: false,
10747
11113
  errors,
@@ -10841,7 +11207,7 @@ var SwapManager = class {
10841
11207
  tokenProgram: import_token5.TOKEN_PROGRAM_ADDRESS
10842
11208
  });
10843
11209
  const sqrtPriceLimitX64 = params.sqrtPriceLimitX64 || this.mathEngine.calculateSqrtPriceLimit(
10844
- new import_bn7.default(pool.sqrtPriceX64.toString()),
11210
+ new import_bn8.default(pool.sqrtPriceX64.toString()),
10845
11211
  zeroForOne,
10846
11212
  params.slippageTolerance || DEFAULT_SLIPPAGE_TOLERANCE
10847
11213
  );
@@ -10866,7 +11232,7 @@ var SwapManager = class {
10866
11232
  async getCurrentPrice(poolAddress, options) {
10867
11233
  const pool = await this.poolDataManager.getPoolState(poolAddress, options);
10868
11234
  return SqrtPriceMath.sqrtPriceX64ToPrice(
10869
- new import_bn7.default(pool.sqrtPriceX64.toString()),
11235
+ new import_bn8.default(pool.sqrtPriceX64.toString()),
10870
11236
  pool.mintDecimals0,
10871
11237
  pool.mintDecimals1
10872
11238
  );
@@ -11079,6 +11445,7 @@ var DEFAULT_SDK_CONFIG = {
11079
11445
  PoolManager,
11080
11446
  PoolUtils,
11081
11447
  PositionManager,
11448
+ PositionUtils,
11082
11449
  PriceApiClient,
11083
11450
  Q128,
11084
11451
  Q64,