@stabbleorg/mclmm-sdk 0.3.2 → 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 +440 -53
- package/lib/index.mjs +439 -53
- package/lib/position-manager.d.ts +14 -1
- package/lib/position-manager.d.ts.map +1 -1
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.d.ts.map +1 -1
- package/lib/utils/position.d.ts +191 -0
- package/lib/utils/position.d.ts.map +1 -0
- package/lib/utils/tick.d.ts +1 -0
- package/lib/utils/tick.d.ts.map +1 -1
- package/package.json +1 -1
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
|
|
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
|
|
7679
|
-
new
|
|
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
|
|
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
|
|
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");
|
|
@@ -8461,21 +8740,22 @@ var PositionManager = class {
|
|
|
8461
8740
|
* Enrich position state with computed fields from pool data
|
|
8462
8741
|
* @param position - Raw position state from blockchain
|
|
8463
8742
|
* @param pool - Pool state from blockchain
|
|
8743
|
+
* @param fees - Position fees
|
|
8464
8744
|
* @returns Enriched position info with calculated amounts and prices
|
|
8465
8745
|
*/
|
|
8466
|
-
enrichPositionInfo(position, pool) {
|
|
8746
|
+
enrichPositionInfo(position, pool, fees, rewards) {
|
|
8467
8747
|
const sqrtPriceLowerX64 = SqrtPriceMath.getSqrtPriceX64FromTick(
|
|
8468
8748
|
position.tickLowerIndex
|
|
8469
8749
|
);
|
|
8470
8750
|
const sqrtPriceUpperX64 = SqrtPriceMath.getSqrtPriceX64FromTick(
|
|
8471
8751
|
position.tickUpperIndex
|
|
8472
8752
|
);
|
|
8473
|
-
const sqrtPriceCurrentX64 = new
|
|
8753
|
+
const sqrtPriceCurrentX64 = new import_bn7.default(pool.sqrtPriceX64.toString());
|
|
8474
8754
|
const { amountA, amountB } = LiquidityMath.getAmountsFromLiquidity(
|
|
8475
8755
|
sqrtPriceCurrentX64,
|
|
8476
8756
|
sqrtPriceLowerX64,
|
|
8477
8757
|
sqrtPriceUpperX64,
|
|
8478
|
-
new
|
|
8758
|
+
new import_bn7.default(position.liquidity.toString()),
|
|
8479
8759
|
true
|
|
8480
8760
|
);
|
|
8481
8761
|
const [_amountA, _amountB] = [
|
|
@@ -8496,9 +8776,13 @@ var PositionManager = class {
|
|
|
8496
8776
|
});
|
|
8497
8777
|
const inRange = pool.tickCurrent >= position.tickLowerIndex && pool.tickCurrent < position.tickUpperIndex;
|
|
8498
8778
|
const unclaimedFees = {
|
|
8499
|
-
token0: new
|
|
8500
|
-
token1: new
|
|
8779
|
+
token0: fees?.tokenFees0 ? fees?.tokenFees0 : new import_bn7.default(0),
|
|
8780
|
+
token1: fees?.tokenFees1 ? fees?.tokenFees1 : new import_bn7.default(0)
|
|
8501
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;
|
|
8502
8786
|
const ageSeconds = 0;
|
|
8503
8787
|
return {
|
|
8504
8788
|
...position,
|
|
@@ -8511,10 +8795,8 @@ var PositionManager = class {
|
|
|
8511
8795
|
inRange,
|
|
8512
8796
|
ageSeconds,
|
|
8513
8797
|
unclaimedFees,
|
|
8514
|
-
|
|
8515
|
-
valueUsd: void 0
|
|
8516
|
-
// unclaimedRewards is optional
|
|
8517
|
-
unclaimedRewards: void 0
|
|
8798
|
+
unclaimedRewards,
|
|
8799
|
+
valueUsd: void 0
|
|
8518
8800
|
};
|
|
8519
8801
|
}
|
|
8520
8802
|
/**
|
|
@@ -8554,7 +8836,16 @@ var PositionManager = class {
|
|
|
8554
8836
|
console.warn(`Pool ${position.poolId} not found for position`);
|
|
8555
8837
|
return null;
|
|
8556
8838
|
}
|
|
8557
|
-
|
|
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
|
+
);
|
|
8558
8849
|
} catch (error) {
|
|
8559
8850
|
console.error(`Failed to enrich position: ${error}`);
|
|
8560
8851
|
return null;
|
|
@@ -8569,6 +8860,101 @@ var PositionManager = class {
|
|
|
8569
8860
|
);
|
|
8570
8861
|
}
|
|
8571
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
|
+
}
|
|
8572
8958
|
};
|
|
8573
8959
|
|
|
8574
8960
|
// src/api/config.ts
|
|
@@ -9540,7 +9926,7 @@ var PriceApiClient = class _PriceApiClient {
|
|
|
9540
9926
|
};
|
|
9541
9927
|
|
|
9542
9928
|
// src/swap.ts
|
|
9543
|
-
var
|
|
9929
|
+
var import_bn8 = __toESM(require("bn.js"));
|
|
9544
9930
|
var import_decimal6 = __toESM(require("decimal.js"));
|
|
9545
9931
|
var DEFAULT_RETRY_CONFIG = {
|
|
9546
9932
|
maxRetries: 3,
|
|
@@ -9600,7 +9986,7 @@ var SwapMathEngine = class {
|
|
|
9600
9986
|
slippageTolerance,
|
|
9601
9987
|
poolAddress
|
|
9602
9988
|
} = params;
|
|
9603
|
-
if (amountIn.lte(new
|
|
9989
|
+
if (amountIn.lte(new import_bn8.default(0))) {
|
|
9604
9990
|
throw new ClmmError(
|
|
9605
9991
|
"SWAP_AMOUNT_CANNOT_BE_ZERO" /* SWAP_AMOUNT_CANNOT_BE_ZERO */,
|
|
9606
9992
|
"Swap amount must be greater than zero"
|
|
@@ -9612,8 +9998,8 @@ var SwapMathEngine = class {
|
|
|
9612
9998
|
`Slippage tolerance must be between 0 and 1, got ${slippageTolerance}`
|
|
9613
9999
|
);
|
|
9614
10000
|
}
|
|
9615
|
-
const liquidity = new
|
|
9616
|
-
const sqrtPriceCurrentX64 = new
|
|
10001
|
+
const liquidity = new import_bn8.default(pool.liquidity.toString());
|
|
10002
|
+
const sqrtPriceCurrentX64 = new import_bn8.default(pool.sqrtPriceX64.toString());
|
|
9617
10003
|
const feeRate = ammConfig.tradeFeeRate;
|
|
9618
10004
|
const sqrtPriceTargetX64 = this.calculateSqrtPriceLimit(
|
|
9619
10005
|
sqrtPriceCurrentX64,
|
|
@@ -9641,9 +10027,9 @@ var SwapMathEngine = class {
|
|
|
9641
10027
|
pool.mintDecimals1
|
|
9642
10028
|
);
|
|
9643
10029
|
const priceImpact = priceAfter.minus(priceBefore).div(priceBefore).abs().toNumber();
|
|
9644
|
-
const slippageBN = new
|
|
10030
|
+
const slippageBN = new import_bn8.default(Math.floor(slippageTolerance * 1e4));
|
|
9645
10031
|
const minAmountOut = step.amountOut.sub(
|
|
9646
|
-
step.amountOut.mul(slippageBN).div(new
|
|
10032
|
+
step.amountOut.mul(slippageBN).div(new import_bn8.default(1e4))
|
|
9647
10033
|
);
|
|
9648
10034
|
return {
|
|
9649
10035
|
amountIn,
|
|
@@ -9690,17 +10076,17 @@ var SwapMathEngine = class {
|
|
|
9690
10076
|
tickArrayCache
|
|
9691
10077
|
} = params;
|
|
9692
10078
|
const sqrtPriceLimitX64 = this.calculateSqrtPriceLimit(
|
|
9693
|
-
new
|
|
10079
|
+
new import_bn8.default(pool.sqrtPriceX64.toString()),
|
|
9694
10080
|
zeroForOne,
|
|
9695
10081
|
slippageTolerance
|
|
9696
10082
|
);
|
|
9697
10083
|
const result = await SwapMath.swapCompute({
|
|
9698
10084
|
poolState: {
|
|
9699
|
-
sqrtPriceX64: new
|
|
10085
|
+
sqrtPriceX64: new import_bn8.default(pool.sqrtPriceX64.toString()),
|
|
9700
10086
|
tickCurrent: pool.tickCurrent,
|
|
9701
|
-
liquidity: new
|
|
9702
|
-
feeGrowthGlobal0X64: new
|
|
9703
|
-
feeGrowthGlobal1X64: new
|
|
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())
|
|
9704
10090
|
},
|
|
9705
10091
|
tickArrayCache,
|
|
9706
10092
|
tickSpacing: pool.tickSpacing,
|
|
@@ -9717,7 +10103,7 @@ var SwapMathEngine = class {
|
|
|
9717
10103
|
poolId: poolAddress
|
|
9718
10104
|
});
|
|
9719
10105
|
const priceBefore = SqrtPriceMath.sqrtPriceX64ToPrice(
|
|
9720
|
-
new
|
|
10106
|
+
new import_bn8.default(pool.sqrtPriceX64.toString()),
|
|
9721
10107
|
pool.mintDecimals0,
|
|
9722
10108
|
pool.mintDecimals1
|
|
9723
10109
|
);
|
|
@@ -9727,9 +10113,9 @@ var SwapMathEngine = class {
|
|
|
9727
10113
|
pool.mintDecimals1
|
|
9728
10114
|
);
|
|
9729
10115
|
const priceImpact = priceAfter.minus(priceBefore).div(priceBefore).abs().toNumber();
|
|
9730
|
-
const slippageBN = new
|
|
10116
|
+
const slippageBN = new import_bn8.default(Math.floor(slippageTolerance * 1e4));
|
|
9731
10117
|
const minAmountOut = result.amountOut.sub(
|
|
9732
|
-
result.amountOut.mul(slippageBN).div(new
|
|
10118
|
+
result.amountOut.mul(slippageBN).div(new import_bn8.default(1e4))
|
|
9733
10119
|
);
|
|
9734
10120
|
const feeImpact = ammConfig.tradeFeeRate / FEE_RATE_DENOMINATOR_NUMBER;
|
|
9735
10121
|
return {
|
|
@@ -9773,10 +10159,10 @@ var SwapMathEngine = class {
|
|
|
9773
10159
|
*/
|
|
9774
10160
|
calculateSqrtPriceLimit(sqrtPriceX64, zeroForOne, slippageTolerance) {
|
|
9775
10161
|
const bps = Math.floor(slippageTolerance * 1e4);
|
|
9776
|
-
const base = new
|
|
9777
|
-
const scaled = zeroForOne ? sqrtPriceX64.mul(base.sub(new
|
|
9778
|
-
const min2 = new
|
|
9779
|
-
const max = new
|
|
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);
|
|
9780
10166
|
if (scaled.lt(min2)) return min2;
|
|
9781
10167
|
if (scaled.gt(max)) return max;
|
|
9782
10168
|
return scaled;
|
|
@@ -10200,7 +10586,7 @@ var SwapManager = class {
|
|
|
10200
10586
|
`Invalid slippage tolerance: ${slippageTolerance}. Must be between 0 and 1.`
|
|
10201
10587
|
);
|
|
10202
10588
|
}
|
|
10203
|
-
if (amountIn.lte(new
|
|
10589
|
+
if (amountIn.lte(new import_bn8.default(0))) {
|
|
10204
10590
|
throw new ClmmError(
|
|
10205
10591
|
"SWAP_AMOUNT_CANNOT_BE_ZERO" /* SWAP_AMOUNT_CANNOT_BE_ZERO */,
|
|
10206
10592
|
"Swap amount must be greater than zero."
|
|
@@ -10302,7 +10688,7 @@ var SwapManager = class {
|
|
|
10302
10688
|
`Invalid slippage tolerance: ${slippageTolerance}. Must be between 0 and 1.`
|
|
10303
10689
|
);
|
|
10304
10690
|
}
|
|
10305
|
-
if (amountIn.lte(new
|
|
10691
|
+
if (amountIn.lte(new import_bn8.default(0))) {
|
|
10306
10692
|
throw new ClmmError(
|
|
10307
10693
|
"SWAP_AMOUNT_CANNOT_BE_ZERO" /* SWAP_AMOUNT_CANNOT_BE_ZERO */,
|
|
10308
10694
|
"Swap amount must be greater than zero."
|
|
@@ -10356,7 +10742,7 @@ var SwapManager = class {
|
|
|
10356
10742
|
poolAddress
|
|
10357
10743
|
});
|
|
10358
10744
|
const priceBefore = SqrtPriceMath.sqrtPriceX64ToPrice(
|
|
10359
|
-
new
|
|
10745
|
+
new import_bn8.default(pool.sqrtPriceX64.toString()),
|
|
10360
10746
|
pool.mintDecimals0,
|
|
10361
10747
|
pool.mintDecimals1
|
|
10362
10748
|
);
|
|
@@ -10466,21 +10852,21 @@ var SwapManager = class {
|
|
|
10466
10852
|
* @returns Number of tick arrays to fetch (includes safety buffer)
|
|
10467
10853
|
*/
|
|
10468
10854
|
estimateTickArrayCount(pool, amountIn) {
|
|
10469
|
-
const liquidity = new
|
|
10470
|
-
if (liquidity.eq(new
|
|
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))) {
|
|
10471
10857
|
return 10;
|
|
10472
10858
|
}
|
|
10473
|
-
const roughImpact = amountIn.mul(new
|
|
10859
|
+
const roughImpact = amountIn.mul(new import_bn8.default(1e3)).div(liquidity);
|
|
10474
10860
|
let baseArrays;
|
|
10475
|
-
if (roughImpact.lte(new
|
|
10861
|
+
if (roughImpact.lte(new import_bn8.default(1))) {
|
|
10476
10862
|
baseArrays = 2;
|
|
10477
|
-
} else if (roughImpact.lte(new
|
|
10863
|
+
} else if (roughImpact.lte(new import_bn8.default(10))) {
|
|
10478
10864
|
baseArrays = 4;
|
|
10479
|
-
} else if (roughImpact.lte(new
|
|
10865
|
+
} else if (roughImpact.lte(new import_bn8.default(50))) {
|
|
10480
10866
|
baseArrays = 6;
|
|
10481
|
-
} else if (roughImpact.lte(new
|
|
10867
|
+
} else if (roughImpact.lte(new import_bn8.default(100))) {
|
|
10482
10868
|
baseArrays = 8;
|
|
10483
|
-
} else if (roughImpact.lte(new
|
|
10869
|
+
} else if (roughImpact.lte(new import_bn8.default(200))) {
|
|
10484
10870
|
baseArrays = 12;
|
|
10485
10871
|
} else {
|
|
10486
10872
|
baseArrays = 15;
|
|
@@ -10525,7 +10911,7 @@ var SwapManager = class {
|
|
|
10525
10911
|
const decOut = zeroForOne ? pool.mintDecimals1 : pool.mintDecimals0;
|
|
10526
10912
|
const promises = params.amounts.map(async (amountIn) => {
|
|
10527
10913
|
try {
|
|
10528
|
-
if (amountIn.lte(new
|
|
10914
|
+
if (amountIn.lte(new import_bn8.default(0))) return;
|
|
10529
10915
|
const quote = await this.mathEngine.calculateSimpleSwap({
|
|
10530
10916
|
pool,
|
|
10531
10917
|
ammConfig,
|
|
@@ -10567,7 +10953,7 @@ var SwapManager = class {
|
|
|
10567
10953
|
options
|
|
10568
10954
|
);
|
|
10569
10955
|
const priceBefore = SqrtPriceMath.sqrtPriceX64ToPrice(
|
|
10570
|
-
new
|
|
10956
|
+
new import_bn8.default(pool.sqrtPriceX64.toString()),
|
|
10571
10957
|
pool.mintDecimals0,
|
|
10572
10958
|
pool.mintDecimals1
|
|
10573
10959
|
);
|
|
@@ -10690,13 +11076,13 @@ var SwapManager = class {
|
|
|
10690
11076
|
`Extremely high price impact: ${(quote.priceImpact * 100).toFixed(2)}%. Swap likely to fail or result in significant slippage.`
|
|
10691
11077
|
);
|
|
10692
11078
|
}
|
|
10693
|
-
const oneUnit = new
|
|
11079
|
+
const oneUnit = new import_bn8.default(10).pow(new import_bn8.default(outputDecimals));
|
|
10694
11080
|
if (quote.amountOut.lt(oneUnit)) {
|
|
10695
11081
|
warnings.push(
|
|
10696
11082
|
`Output amount is less than 1 unit of the output token. Consider increasing input amount or slippage tolerance.`
|
|
10697
11083
|
);
|
|
10698
11084
|
}
|
|
10699
|
-
if (quote.amountOut.lte(new
|
|
11085
|
+
if (quote.amountOut.lte(new import_bn8.default(0))) {
|
|
10700
11086
|
errors.push(
|
|
10701
11087
|
"Swap would result in zero output. Amount may be too small."
|
|
10702
11088
|
);
|
|
@@ -10717,11 +11103,11 @@ var SwapManager = class {
|
|
|
10717
11103
|
return {
|
|
10718
11104
|
quote: {
|
|
10719
11105
|
amountIn: params.amountIn,
|
|
10720
|
-
amountOut: new
|
|
10721
|
-
minAmountOut: new
|
|
11106
|
+
amountOut: new import_bn8.default(0),
|
|
11107
|
+
minAmountOut: new import_bn8.default(0),
|
|
10722
11108
|
priceImpact: 0,
|
|
10723
11109
|
route: [],
|
|
10724
|
-
fee: new
|
|
11110
|
+
fee: new import_bn8.default(0)
|
|
10725
11111
|
},
|
|
10726
11112
|
willSucceed: false,
|
|
10727
11113
|
errors,
|
|
@@ -10821,7 +11207,7 @@ var SwapManager = class {
|
|
|
10821
11207
|
tokenProgram: import_token5.TOKEN_PROGRAM_ADDRESS
|
|
10822
11208
|
});
|
|
10823
11209
|
const sqrtPriceLimitX64 = params.sqrtPriceLimitX64 || this.mathEngine.calculateSqrtPriceLimit(
|
|
10824
|
-
new
|
|
11210
|
+
new import_bn8.default(pool.sqrtPriceX64.toString()),
|
|
10825
11211
|
zeroForOne,
|
|
10826
11212
|
params.slippageTolerance || DEFAULT_SLIPPAGE_TOLERANCE
|
|
10827
11213
|
);
|
|
@@ -10846,7 +11232,7 @@ var SwapManager = class {
|
|
|
10846
11232
|
async getCurrentPrice(poolAddress, options) {
|
|
10847
11233
|
const pool = await this.poolDataManager.getPoolState(poolAddress, options);
|
|
10848
11234
|
return SqrtPriceMath.sqrtPriceX64ToPrice(
|
|
10849
|
-
new
|
|
11235
|
+
new import_bn8.default(pool.sqrtPriceX64.toString()),
|
|
10850
11236
|
pool.mintDecimals0,
|
|
10851
11237
|
pool.mintDecimals1
|
|
10852
11238
|
);
|
|
@@ -11059,6 +11445,7 @@ var DEFAULT_SDK_CONFIG = {
|
|
|
11059
11445
|
PoolManager,
|
|
11060
11446
|
PoolUtils,
|
|
11061
11447
|
PositionManager,
|
|
11448
|
+
PositionUtils,
|
|
11062
11449
|
PriceApiClient,
|
|
11063
11450
|
Q128,
|
|
11064
11451
|
Q64,
|