@meteora-ag/dlmm 1.6.0-rc.21 → 1.6.0-rc.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/dist/index.mjs CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  SystemProgram as SystemProgram2,
20
20
  Transaction
21
21
  } from "@solana/web3.js";
22
- import Decimal8 from "decimal.js";
22
+ import Decimal7 from "decimal.js";
23
23
 
24
24
  // src/dlmm/constants/index.ts
25
25
  import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";
@@ -11779,1863 +11779,1590 @@ function getTokenProgramId(lbPairState) {
11779
11779
  };
11780
11780
  }
11781
11781
 
11782
- // src/dlmm/helpers/rebalance/rebalancePosition.ts
11783
- import { SYSVAR_CLOCK_PUBKEY } from "@solana/web3.js";
11784
- import BN11 from "bn.js";
11785
- import Decimal6 from "decimal.js";
11786
- function buildBitFlagAndNegateStrategyParameters(x0, y0, deltaX, deltaY) {
11787
- let bitFlag = 0;
11788
- if (x0.isNeg()) {
11789
- bitFlag |= 1;
11790
- x0 = x0.neg();
11791
- }
11792
- if (y0.isNeg()) {
11793
- bitFlag |= 2;
11794
- y0 = y0.neg();
11795
- }
11796
- if (deltaX.isNeg()) {
11797
- bitFlag |= 4;
11798
- deltaX = deltaX.neg();
11799
- }
11800
- if (deltaY.isNeg()) {
11801
- bitFlag |= 8;
11802
- deltaY = deltaY.neg();
11803
- }
11804
- return {
11805
- bitFlag,
11806
- x0,
11807
- y0,
11808
- deltaX,
11809
- deltaY
11810
- };
11811
- }
11812
- function toRebalancePositionBinData(positionData) {
11813
- return positionData.positionBinData.map(
11814
- ({
11815
- binId,
11816
- price,
11817
- pricePerToken,
11818
- positionXAmount,
11819
- positionYAmount,
11820
- positionFeeXAmount,
11821
- positionFeeYAmount,
11822
- positionRewardAmount
11823
- }) => {
11824
- return {
11825
- binId,
11826
- price,
11827
- pricePerToken,
11828
- amountX: new BN11(positionXAmount),
11829
- amountY: new BN11(positionYAmount),
11830
- claimableRewardAmount: positionRewardAmount.map(
11831
- (amount) => new BN11(amount)
11832
- ),
11833
- claimableFeeXAmount: new BN11(positionFeeXAmount),
11834
- claimableFeeYAmount: new BN11(positionFeeYAmount)
11835
- };
11836
- }
11782
+ // src/dlmm/helpers/index.ts
11783
+ function chunks(array, size) {
11784
+ return Array.apply(0, new Array(Math.ceil(array.length / size))).map(
11785
+ (_, index) => array.slice(index * size, (index + 1) * size)
11837
11786
  );
11838
11787
  }
11839
- function getDepositBinIds(activeId, deposits) {
11840
- const uniqueBinId = /* @__PURE__ */ new Set();
11841
- for (const { minDeltaId, maxDeltaId } of deposits) {
11842
- const minBinId = activeId.add(minDeltaId);
11843
- const maxBinId = activeId.add(maxDeltaId);
11844
- for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
11845
- uniqueBinId.add(binId);
11846
- }
11847
- }
11848
- const binIds = Array.from(uniqueBinId);
11849
- binIds.sort((a, b) => a - b);
11850
- return binIds;
11788
+ function range(min, max, mapfn) {
11789
+ const length = max - min + 1;
11790
+ return Array.from({ length }, (_, i) => mapfn(min + i));
11851
11791
  }
11852
- function findMinMaxBinIdWithLiquidity(rebalancePositionBinData) {
11853
- let minBinId = null;
11854
- let maxBinId = null;
11855
- for (const binData of rebalancePositionBinData) {
11856
- if (binData.amountX.isZero() && binData.amountY.isZero() && binData.claimableFeeXAmount.isZero() && binData.claimableFeeYAmount.isZero() && binData.claimableRewardAmount.every((amount) => amount.isZero())) {
11857
- continue;
11858
- }
11859
- if (minBinId == null || binData.binId < minBinId) {
11860
- minBinId = binData.binId;
11861
- }
11862
- if (maxBinId == null || binData.binId > maxBinId) {
11863
- maxBinId = binData.binId;
11864
- }
11865
- }
11866
- return [minBinId, maxBinId];
11792
+ async function chunkedFetchMultiplePoolAccount(program, pks, chunkSize = 100) {
11793
+ const accounts = (await Promise.all(
11794
+ chunks(pks, chunkSize).map(
11795
+ (chunk) => program.account.lbPair.fetchMultiple(chunk)
11796
+ )
11797
+ )).flat();
11798
+ return accounts.filter(Boolean);
11867
11799
  }
11868
- function onlyDepositToBidSide(maxDeltaId, favorXInActiveBin) {
11869
- if (favorXInActiveBin) {
11870
- return maxDeltaId.lt(new BN11(0));
11871
- }
11872
- return maxDeltaId.lte(new BN11(0));
11800
+ async function chunkedFetchMultipleBinArrayBitmapExtensionAccount(program, pks, chunkSize = 100) {
11801
+ const accounts = (await Promise.all(
11802
+ chunks(pks, chunkSize).map(
11803
+ (chunk) => program.account.binArrayBitmapExtension.fetchMultiple(chunk)
11804
+ )
11805
+ )).flat();
11806
+ return accounts;
11873
11807
  }
11874
- function onlyDepositToAskSide(minDeltaId, favorXInActiveBin) {
11875
- if (favorXInActiveBin) {
11876
- return minDeltaId.gte(new BN11(0));
11877
- }
11878
- return minDeltaId.gt(new BN11(0));
11808
+ function getOutAmount(bin, inAmount, swapForY) {
11809
+ return swapForY ? mulShr(inAmount, bin.price, SCALE_OFFSET, 1 /* Down */) : shlDiv(inAmount, bin.price, SCALE_OFFSET, 1 /* Down */);
11879
11810
  }
11880
- function getAmountInBinsBidSide(activeId, minDeltaId, maxDeltaId, deltaY, y0) {
11881
- const amountInBins = [];
11882
- const minBinId = activeId.add(minDeltaId);
11883
- const maxBinId = activeId.add(maxDeltaId);
11884
- for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
11885
- const deltaBin = activeId.toNumber() - binId;
11886
- const totalDeltaY = deltaY.mul(new BN11(deltaBin));
11887
- const amountY = y0.add(totalDeltaY);
11888
- amountInBins.push({
11889
- binId: new BN11(binId),
11890
- amountX: new BN11(0),
11891
- amountY
11892
- });
11893
- }
11894
- return amountInBins;
11811
+ async function getTokenDecimals(conn, mint) {
11812
+ const token = await getMint(conn, mint);
11813
+ return await token.decimals;
11895
11814
  }
11896
- function getAmountInBinsAskSide(activeId, binStep, minDeltaId, maxDeltaId, deltaX, x0) {
11897
- const binCount = maxDeltaId.sub(minDeltaId).add(new BN11(1));
11898
- const minBinId = activeId.add(minDeltaId);
11899
- const maxBinId = activeId.add(maxDeltaId);
11900
- const amountInBins = new Array(binCount.toNumber());
11901
- const base = getQPriceBaseFactor(binStep);
11902
- let inverseBasePrice = pow(base, maxBinId.neg());
11903
- for (let binId = maxBinId.toNumber(); binId >= minBinId.toNumber(); binId--) {
11904
- const delta = binId - activeId.toNumber();
11905
- const totalDeltaX = deltaX.mul(new BN11(delta));
11906
- const amountX = x0.add(totalDeltaX).mul(inverseBasePrice).shrn(SCALE_OFFSET);
11907
- const idx = binId - minBinId.toNumber();
11908
- amountInBins[idx] = {
11909
- binId: new BN11(binId),
11910
- amountX,
11911
- amountY: new BN11(0)
11912
- };
11913
- inverseBasePrice = inverseBasePrice.mul(base).shrn(SCALE_OFFSET);
11815
+ var getOrCreateATAInstruction = async (connection, tokenMint, owner, programId, payer = owner, allowOwnerOffCurve = true) => {
11816
+ programId = programId ?? TOKEN_PROGRAM_ID3;
11817
+ const toAccount = getAssociatedTokenAddressSync(
11818
+ tokenMint,
11819
+ owner,
11820
+ allowOwnerOffCurve,
11821
+ programId,
11822
+ ASSOCIATED_TOKEN_PROGRAM_ID
11823
+ );
11824
+ try {
11825
+ await getAccount(connection, toAccount, connection.commitment, programId);
11826
+ return { ataPubKey: toAccount, ix: void 0 };
11827
+ } catch (e) {
11828
+ if (e instanceof TokenAccountNotFoundError || e instanceof TokenInvalidAccountOwnerError) {
11829
+ const ix = createAssociatedTokenAccountIdempotentInstruction(
11830
+ payer,
11831
+ toAccount,
11832
+ owner,
11833
+ tokenMint,
11834
+ programId,
11835
+ ASSOCIATED_TOKEN_PROGRAM_ID
11836
+ );
11837
+ return { ataPubKey: toAccount, ix };
11838
+ } else {
11839
+ console.error("Error::getOrCreateATAInstruction", e);
11840
+ throw e;
11841
+ }
11914
11842
  }
11915
- return amountInBins;
11843
+ };
11844
+ async function getTokenBalance(conn, tokenAccount) {
11845
+ const acc = await getAccount(conn, tokenAccount);
11846
+ return acc.amount;
11916
11847
  }
11917
- function toAmountIntoBins(activeId, minDeltaId, maxDeltaId, deltaX, deltaY, x0, y0, binStep, favorXInActiveBin) {
11918
- if (onlyDepositToBidSide(maxDeltaId, favorXInActiveBin)) {
11919
- return getAmountInBinsBidSide(activeId, minDeltaId, maxDeltaId, deltaY, y0);
11920
- }
11921
- if (onlyDepositToAskSide(minDeltaId, favorXInActiveBin)) {
11922
- return getAmountInBinsAskSide(
11923
- activeId,
11924
- binStep,
11925
- minDeltaId,
11926
- maxDeltaId,
11927
- deltaX,
11928
- x0
11929
- );
11848
+ var parseLogs = (eventParser, logs) => {
11849
+ if (!logs.length)
11850
+ throw new Error("No logs found");
11851
+ for (const event of eventParser?.parseLogs(logs)) {
11852
+ return event.data;
11930
11853
  }
11931
- const [bidSideEndDeltaId, askSideStartDeltaId] = favorXInActiveBin ? [-1, 0] : [0, 1];
11932
- const amountInBinsBidSide = getAmountInBinsBidSide(
11933
- activeId,
11934
- minDeltaId,
11935
- new BN11(bidSideEndDeltaId),
11936
- deltaY,
11937
- y0
11938
- );
11939
- const amountInBinsAskSide = getAmountInBinsAskSide(
11940
- activeId,
11941
- binStep,
11942
- new BN11(askSideStartDeltaId),
11943
- maxDeltaId,
11944
- deltaX,
11945
- x0
11854
+ throw new Error("No events found");
11855
+ };
11856
+ var wrapSOLInstruction = (from, to, amount) => {
11857
+ return [
11858
+ SystemProgram.transfer({
11859
+ fromPubkey: from,
11860
+ toPubkey: to,
11861
+ lamports: amount
11862
+ }),
11863
+ new TransactionInstruction3({
11864
+ keys: [
11865
+ {
11866
+ pubkey: to,
11867
+ isSigner: false,
11868
+ isWritable: true
11869
+ }
11870
+ ],
11871
+ data: Buffer.from(new Uint8Array([17])),
11872
+ programId: TOKEN_PROGRAM_ID3
11873
+ })
11874
+ ];
11875
+ };
11876
+ var unwrapSOLInstruction = async (owner, allowOwnerOffCurve = true) => {
11877
+ const wSolATAAccount = getAssociatedTokenAddressSync(
11878
+ NATIVE_MINT,
11879
+ owner,
11880
+ allowOwnerOffCurve
11946
11881
  );
11947
- return amountInBinsBidSide.concat(amountInBinsAskSide);
11948
- }
11949
- function getLiquidity(x, y, price) {
11950
- const px = price.mul(x);
11951
- const shly = y.shln(SCALE_OFFSET);
11952
- return px.add(shly);
11953
- }
11954
- function computeCompositionFee(binStep, sParameters3, vParameters3, outAmountX, inAmountX, outAmountY, inAmountY) {
11955
- if (outAmountX.gt(inAmountX)) {
11956
- const delta = inAmountY.sub(outAmountY);
11957
- const totalFeeRate = getTotalFee(
11958
- binStep.toNumber(),
11959
- sParameters3,
11960
- vParameters3
11882
+ if (wSolATAAccount) {
11883
+ const closedWrappedSolInstruction = createCloseAccountInstruction(
11884
+ wSolATAAccount,
11885
+ owner,
11886
+ owner,
11887
+ [],
11888
+ TOKEN_PROGRAM_ID3
11961
11889
  );
11962
- const feeAmount = delta.mul(totalFeeRate);
11963
- return feeAmount.mul(FEE_PRECISION.add(totalFeeRate)).div(FEE_PRECISION.pow(new BN11(2)));
11964
- }
11965
- return new BN11(0);
11966
- }
11967
- function simulateDepositBin(binId, binStep, amountX, amountY, bin) {
11968
- if (!bin) {
11969
- return {
11970
- amountXIntoBin: amountX,
11971
- amountYIntoBin: amountY
11972
- };
11890
+ return closedWrappedSolInstruction;
11973
11891
  }
11974
- const price = getQPriceFromId(binId, binStep);
11975
- const inLiquidity = getLiquidity(amountX, amountY, price);
11976
- const binLiquidity = getLiquidity(bin.amountX, bin.amountY, price);
11977
- if (bin.liquiditySupply.isZero()) {
11978
- return {
11979
- amountXIntoBin: amountX,
11980
- amountYIntoBin: amountY
11981
- };
11892
+ return null;
11893
+ };
11894
+ async function chunkedGetMultipleAccountInfos(connection, pks, chunkSize = 100) {
11895
+ const accountInfos = (await Promise.all(
11896
+ chunks(pks, chunkSize).map(
11897
+ (chunk) => connection.getMultipleAccountsInfo(chunk)
11898
+ )
11899
+ )).flat();
11900
+ return accountInfos;
11901
+ }
11902
+ var getEstimatedComputeUnitUsageWithBuffer = async (connection, instructions, feePayer, buffer) => {
11903
+ if (!buffer) {
11904
+ buffer = 0.1;
11982
11905
  }
11983
- const liquidityShare = inLiquidity.mul(bin.liquiditySupply).div(binLiquidity);
11984
- const updatedBinXAmount = bin.amountX.add(amountX);
11985
- const updatedBinYAmount = bin.amountY.add(amountY);
11986
- const updatedBinSupply = bin.liquiditySupply.add(liquidityShare);
11987
- let amountXIntoBin = liquidityShare.mul(
11988
- updatedBinXAmount.div(updatedBinSupply)
11906
+ buffer = Math.max(0, buffer);
11907
+ buffer = Math.min(1, buffer);
11908
+ const estimatedComputeUnitUsage = await getSimulationComputeUnits(
11909
+ connection,
11910
+ instructions,
11911
+ feePayer,
11912
+ []
11989
11913
  );
11990
- let amountYIntoBin = liquidityShare.mul(
11991
- updatedBinYAmount.div(updatedBinSupply)
11914
+ let extraComputeUnitBuffer = estimatedComputeUnitUsage * buffer;
11915
+ if (extraComputeUnitBuffer > MAX_CU_BUFFER) {
11916
+ extraComputeUnitBuffer = MAX_CU_BUFFER;
11917
+ } else if (extraComputeUnitBuffer < MIN_CU_BUFFER) {
11918
+ extraComputeUnitBuffer = MIN_CU_BUFFER;
11919
+ }
11920
+ return estimatedComputeUnitUsage + extraComputeUnitBuffer;
11921
+ };
11922
+ var getEstimatedComputeUnitIxWithBuffer = async (connection, instructions, feePayer, buffer) => {
11923
+ const units = await getEstimatedComputeUnitUsageWithBuffer(
11924
+ connection,
11925
+ instructions,
11926
+ feePayer,
11927
+ buffer
11928
+ ).catch((error) => {
11929
+ console.error("Error::getEstimatedComputeUnitUsageWithBuffer", error);
11930
+ return 14e5;
11931
+ });
11932
+ return ComputeBudgetProgram2.setComputeUnitLimit({ units });
11933
+ };
11934
+ function createProgram(connection, opt) {
11935
+ const cluster = opt?.cluster || "mainnet-beta";
11936
+ const provider = new AnchorProvider(
11937
+ connection,
11938
+ {},
11939
+ AnchorProvider.defaultOptions()
11992
11940
  );
11993
- if (amountXIntoBin.gt(amountX)) {
11941
+ return new Program2(
11942
+ { ...dlmm_default, address: LBCLMM_PROGRAM_IDS[cluster] },
11943
+ provider
11944
+ );
11945
+ }
11946
+ function decodeAccount(program, accountName, buffer) {
11947
+ return program.coder.accounts.decode(accountName, buffer);
11948
+ }
11949
+ function getAccountDiscriminator(accountName) {
11950
+ return dlmm_default.accounts.find(
11951
+ (acc) => acc.name.toLowerCase() === accountName.toLowerCase()
11952
+ )?.discriminator;
11953
+ }
11954
+ function capSlippagePercentage(slippage) {
11955
+ if (slippage > 100) {
11956
+ slippage = 100;
11957
+ }
11958
+ if (slippage < 0) {
11959
+ slippage = 0;
11994
11960
  }
11961
+ return slippage;
11962
+ }
11963
+
11964
+ // src/dlmm/helpers/accountFilters.ts
11965
+ import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
11966
+ var presetParameter2BinStepFilter = (binStep) => {
11995
11967
  return {
11996
- amountXIntoBin,
11997
- amountYIntoBin
11968
+ memcmp: {
11969
+ bytes: bs58.encode(binStep.toArrayLike(Buffer, "le", 2)),
11970
+ offset: 8
11971
+ }
11998
11972
  };
11999
- }
12000
- var RebalancePosition = class {
12001
- address;
12002
- lowerBinId;
12003
- upperBinId;
12004
- lbPair;
12005
- owner;
12006
- shouldClaimFee;
12007
- shouldClaimReward;
12008
- rebalancePositionBinData;
12009
- activeBin;
12010
- currentTimestamp;
12011
- constructor(positionAddress, positionData, lbPair, activeBin, shouldClaimFee, shouldClaimReward, currentTimestamp) {
12012
- this.address = positionAddress;
12013
- this.rebalancePositionBinData = toRebalancePositionBinData(positionData);
12014
- this.lowerBinId = new BN11(positionData.lowerBinId);
12015
- this.upperBinId = new BN11(positionData.upperBinId);
12016
- this.lbPair = lbPair;
12017
- this.shouldClaimFee = shouldClaimFee;
12018
- this.shouldClaimReward = shouldClaimReward;
12019
- this.owner = positionData.owner;
12020
- this.activeBin = activeBin;
12021
- this.currentTimestamp = currentTimestamp;
11973
+ };
11974
+ var presetParameter2BaseFactorFilter = (baseFactor) => {
11975
+ return {
11976
+ memcmp: {
11977
+ bytes: bs58.encode(baseFactor.toArrayLike(Buffer, "le", 2)),
11978
+ offset: 8 + 2
11979
+ }
11980
+ };
11981
+ };
11982
+ var presetParameter2BaseFeePowerFactor = (baseFeePowerFactor) => {
11983
+ return {
11984
+ memcmp: {
11985
+ bytes: bs58.encode(baseFeePowerFactor.toArrayLike(Buffer, "le", 1)),
11986
+ offset: 8 + 22
11987
+ }
11988
+ };
11989
+ };
11990
+ var binArrayLbPairFilter = (lbPair) => {
11991
+ return {
11992
+ memcmp: {
11993
+ bytes: lbPair.toBase58(),
11994
+ offset: 8 + 16
11995
+ }
11996
+ };
11997
+ };
11998
+ var positionOwnerFilter = (owner) => {
11999
+ return {
12000
+ memcmp: {
12001
+ bytes: owner.toBase58(),
12002
+ offset: 8 + 32
12003
+ }
12004
+ };
12005
+ };
12006
+ var positionLbPairFilter = (lbPair) => {
12007
+ return {
12008
+ memcmp: {
12009
+ bytes: bs58.encode(lbPair.toBuffer()),
12010
+ offset: 8
12011
+ }
12012
+ };
12013
+ };
12014
+ var positionV2Filter = () => {
12015
+ return {
12016
+ memcmp: {
12017
+ bytes: bs58.encode(Buffer.from(getAccountDiscriminator("positionV2"))),
12018
+ offset: 0
12019
+ }
12020
+ };
12021
+ };
12022
+
12023
+ // src/dlmm/helpers/positions/index.ts
12024
+ import BN13 from "bn.js";
12025
+
12026
+ // src/dlmm/helpers/positions/wrapper.ts
12027
+ import BN12 from "bn.js";
12028
+ function combineBaseAndExtendedPositionBinData(base, extended) {
12029
+ const combinedLiquidityShares = base.liquidityShares;
12030
+ const combinedRewardInfos = base.rewardInfos;
12031
+ const combinedFeeInfos = base.feeInfos;
12032
+ for (const binData of extended) {
12033
+ combinedLiquidityShares.push(binData.liquidityShare);
12034
+ combinedRewardInfos.push(binData.rewardInfo);
12035
+ combinedFeeInfos.push(binData.feeInfo);
12022
12036
  }
12023
- static async create(params) {
12024
- const {
12037
+ return {
12038
+ liquidityShares: combinedLiquidityShares,
12039
+ rewardInfos: combinedRewardInfos,
12040
+ feeInfos: combinedFeeInfos
12041
+ };
12042
+ }
12043
+ function wrapPosition(program, key, account) {
12044
+ const disc = account.data.subarray(0, 8);
12045
+ if (disc.equals(Buffer.from(getAccountDiscriminator("positionV2")))) {
12046
+ const state = decodeAccount(
12025
12047
  program,
12026
- positionAddress,
12027
- pairAddress,
12028
- positionData,
12029
- shouldClaimFee,
12030
- shouldClaimReward
12031
- } = params;
12032
- const [lbPairAccount, clockAccount] = await program.provider.connection.getMultipleAccountsInfo([
12033
- pairAddress,
12034
- SYSVAR_CLOCK_PUBKEY
12035
- ]);
12036
- const lbPair = decodeAccount(program, "lbPair", lbPairAccount.data);
12037
- const clock = ClockLayout.decode(clockAccount.data);
12038
- const activeBinArrayIdx = binIdToBinArrayIndex(new BN11(lbPair.activeId));
12039
- const [activeBinArrayPubkey] = deriveBinArray(
12040
- pairAddress,
12041
- activeBinArrayIdx,
12042
- program.programId
12043
- );
12044
- const activeBinArrayState = await program.account.binArray.fetch(
12045
- activeBinArrayPubkey
12048
+ "positionV2",
12049
+ account.data
12046
12050
  );
12047
- const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(activeBinArrayIdx);
12048
- const idx = getBinIdIndexInBinArray(
12049
- new BN11(lbPair.activeId),
12050
- lowerBinId,
12051
- upperBinId
12051
+ const extended = decodeExtendedPosition(
12052
+ state,
12053
+ program,
12054
+ account.data.subarray(8 + POSITION_MIN_SIZE)
12052
12055
  );
12053
- const activeBin = activeBinArrayState[idx.toNumber()];
12054
- return new RebalancePosition(
12055
- positionAddress,
12056
- positionData,
12057
- lbPair,
12058
- activeBin,
12059
- shouldClaimFee,
12060
- shouldClaimReward,
12061
- clock.unixTimestamp
12056
+ const combinedPositionBinData = combineBaseAndExtendedPositionBinData(
12057
+ state,
12058
+ extended
12062
12059
  );
12060
+ return new PositionV2Wrapper(key, state, extended, combinedPositionBinData);
12061
+ } else {
12062
+ throw new Error("Unknown position account");
12063
12063
  }
12064
- _simulateDeposit(binStep, tokenXDecimal, tokenYDecimal, deposits, simulatedWithdrawResult) {
12065
- const { liquidityAndFeeXWithdrawn, liquidityAndFeeYWithdrawn } = simulatedWithdrawResult;
12066
- const activeId = new BN11(this.lbPair.activeId);
12067
- const depositBinIds = getDepositBinIds(activeId, deposits);
12068
- if (depositBinIds.length > 0) {
12069
- const depositMinBinId = depositBinIds[0];
12070
- const depositMaxBinId = depositBinIds[depositBinIds.length - 1];
12071
- this._simulateResize(
12072
- new BN11(depositMinBinId),
12073
- new BN11(depositMaxBinId),
12074
- binStep,
12075
- tokenXDecimal,
12076
- tokenYDecimal
12077
- );
12078
- }
12079
- let totalAmountXDeposited = new BN11(0);
12080
- let totalAmountYDeposited = new BN11(0);
12081
- const addLiquidityParam = [];
12082
- for (const {
12083
- x0,
12084
- y0,
12085
- favorXInActiveBin,
12086
- deltaX,
12087
- deltaY,
12088
- minDeltaId,
12089
- maxDeltaId
12090
- } of deposits) {
12091
- const params = buildBitFlagAndNegateStrategyParameters(
12092
- x0,
12093
- y0,
12094
- deltaX,
12095
- deltaY
12096
- );
12097
- addLiquidityParam.push({
12098
- minDeltaId: minDeltaId.toNumber(),
12099
- maxDeltaId: maxDeltaId.toNumber(),
12100
- x0: params.x0,
12101
- y0: params.y0,
12102
- deltaX: params.deltaX,
12103
- deltaY: params.deltaY,
12104
- bitFlag: params.bitFlag,
12105
- padding: Array(16).fill(0),
12106
- favorXInActiveId: favorXInActiveBin
12107
- });
12108
- const amountIntoBins = toAmountIntoBins(
12109
- activeId,
12110
- minDeltaId,
12111
- maxDeltaId,
12112
- deltaX,
12113
- deltaY,
12114
- x0,
12115
- y0,
12116
- binStep,
12117
- favorXInActiveBin
12118
- );
12119
- for (const { binId, amountX, amountY } of amountIntoBins) {
12120
- totalAmountXDeposited = totalAmountXDeposited.add(amountX);
12121
- totalAmountYDeposited = totalAmountYDeposited.add(amountY);
12122
- const idx = this.rebalancePositionBinData.findIndex(
12123
- (data) => data.binId == binId.toNumber()
12124
- );
12125
- if (binId.eq(activeId)) {
12126
- const vParameters3 = Object.assign({}, this.lbPair.vParameters);
12127
- const sParameters3 = Object.assign({}, this.lbPair.parameters);
12128
- DLMM.updateReference(
12129
- activeId.toNumber(),
12130
- vParameters3,
12131
- sParameters3,
12132
- this.currentTimestamp.toNumber()
12133
- );
12134
- DLMM.updateVolatilityAccumulator(
12135
- vParameters3,
12136
- sParameters3,
12137
- activeId.toNumber()
12138
- );
12139
- const { amountXIntoBin, amountYIntoBin } = simulateDepositBin(
12140
- binId,
12141
- binStep,
12142
- amountX,
12143
- amountY,
12144
- this.activeBin
12145
- );
12146
- const feeY = computeCompositionFee(
12147
- binStep,
12148
- sParameters3,
12149
- vParameters3,
12150
- amountXIntoBin,
12151
- amountX,
12152
- amountYIntoBin,
12153
- amountY
12154
- );
12155
- const feeX = computeCompositionFee(
12156
- binStep,
12157
- sParameters3,
12158
- vParameters3,
12159
- amountYIntoBin,
12160
- amountY,
12161
- amountXIntoBin,
12162
- amountX
12163
- );
12164
- const amountXIntoBinExcludeFee = amountXIntoBin.sub(feeX);
12165
- const amountYIntoBinExcludeFee = amountYIntoBin.sub(feeY);
12166
- this.rebalancePositionBinData[idx].amountX = this.rebalancePositionBinData[idx].amountX.add(
12167
- amountXIntoBinExcludeFee
12168
- );
12169
- this.rebalancePositionBinData[idx].amountY = this.rebalancePositionBinData[idx].amountY.add(
12170
- amountYIntoBinExcludeFee
12171
- );
12172
- } else {
12173
- this.rebalancePositionBinData[idx].amountX = this.rebalancePositionBinData[idx].amountX.add(amountX);
12174
- this.rebalancePositionBinData[idx].amountY = this.rebalancePositionBinData[idx].amountY.add(amountY);
12175
- }
12176
- }
12177
- }
12178
- let actualTotalAmountXDeposited = totalAmountXDeposited;
12179
- let actualTotalAmountYDeposited = totalAmountYDeposited;
12180
- let actualLiquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn;
12181
- let actualLiquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn;
12182
- if (actualTotalAmountXDeposited.gt(actualLiquidityAndFeeXWithdrawn)) {
12183
- actualTotalAmountXDeposited = actualTotalAmountXDeposited.sub(
12184
- actualLiquidityAndFeeXWithdrawn
12185
- );
12186
- actualLiquidityAndFeeXWithdrawn = new BN11(0);
12187
- } else {
12188
- actualLiquidityAndFeeXWithdrawn = actualLiquidityAndFeeXWithdrawn.sub(
12189
- actualTotalAmountXDeposited
12190
- );
12191
- actualTotalAmountXDeposited = new BN11(0);
12192
- }
12193
- if (actualTotalAmountYDeposited.gt(actualLiquidityAndFeeYWithdrawn)) {
12194
- actualTotalAmountYDeposited = actualTotalAmountYDeposited.sub(
12195
- actualLiquidityAndFeeYWithdrawn
12196
- );
12197
- actualLiquidityAndFeeYWithdrawn = new BN11(0);
12198
- } else {
12199
- actualLiquidityAndFeeYWithdrawn = actualLiquidityAndFeeYWithdrawn.sub(
12200
- actualTotalAmountYDeposited
12201
- );
12202
- actualTotalAmountYDeposited = new BN11(0);
12203
- }
12204
- return {
12205
- result: {
12206
- totalAmountXDeposited,
12207
- totalAmountYDeposited,
12208
- actualLiquidityAndFeeXWithdrawn,
12209
- actualLiquidityAndFeeYWithdrawn,
12210
- actualTotalAmountXDeposited,
12211
- actualTotalAmountYDeposited
12212
- },
12213
- depositParams: addLiquidityParam
12214
- };
12064
+ }
12065
+ var PositionV2Wrapper = class {
12066
+ constructor(positionAddress, inner, extended, combinedPositionBinData) {
12067
+ this.positionAddress = positionAddress;
12068
+ this.inner = inner;
12069
+ this.extended = extended;
12070
+ this.combinedPositionBinData = combinedPositionBinData;
12215
12071
  }
12216
- _simulateResize(depositMinBinId, depositMaxBinId, binStep, tokenXDecimal, tokenYDecimal) {
12217
- const tokenXMultiplier = new Decimal6(10 ** tokenXDecimal.toNumber());
12218
- const tokenYMultiplier = new Decimal6(10 ** tokenYDecimal.toNumber());
12219
- const [minBinId, maxBinId] = findMinMaxBinIdWithLiquidity(
12220
- this.rebalancePositionBinData
12221
- );
12222
- const newMinBinId = new BN11(
12223
- Math.min(depositMinBinId.toNumber(), minBinId ?? Number.MAX_SAFE_INTEGER)
12224
- );
12225
- const newMaxBinId = new BN11(
12226
- Math.max(depositMaxBinId.toNumber(), maxBinId ?? Number.MIN_SAFE_INTEGER)
12227
- );
12228
- if (newMinBinId.lt(this.lowerBinId)) {
12229
- const binCountToExpand = this.lowerBinId.sub(depositMinBinId);
12230
- for (let i = 1; i <= binCountToExpand.toNumber(); i++) {
12231
- const binId = this.lowerBinId.subn(i);
12232
- const price = getPriceOfBinByBinId(
12233
- binId.toNumber(),
12234
- binStep.toNumber()
12235
- );
12236
- const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);
12237
- this.rebalancePositionBinData.unshift({
12238
- binId: binId.toNumber(),
12239
- price: adjustedPrice.toString(),
12240
- pricePerToken: adjustedPrice.toString(),
12241
- amountX: new BN11(0),
12242
- amountY: new BN11(0),
12243
- claimableRewardAmount: [new BN11(0), new BN11(0)],
12244
- claimableFeeXAmount: new BN11(0),
12245
- claimableFeeYAmount: new BN11(0)
12246
- });
12247
- }
12248
- } else {
12249
- const binCountToShrink = newMinBinId.sub(this.lowerBinId);
12250
- for (let i = 1; i <= binCountToShrink.toNumber(); i++) {
12251
- this.rebalancePositionBinData.shift();
12252
- }
12253
- }
12254
- if (newMaxBinId.gt(this.upperBinId)) {
12255
- const binCountToExpand = newMaxBinId.sub(this.upperBinId);
12256
- for (let i = 1; i <= binCountToExpand.toNumber(); i++) {
12257
- const binId = this.upperBinId.addn(i);
12258
- const price = getPriceOfBinByBinId(
12259
- binId.toNumber(),
12260
- binStep.toNumber()
12261
- );
12262
- const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);
12263
- this.rebalancePositionBinData.push({
12264
- binId: binId.toNumber(),
12265
- price: adjustedPrice.toString(),
12266
- pricePerToken: adjustedPrice.toString(),
12267
- amountX: new BN11(0),
12268
- amountY: new BN11(0),
12269
- claimableRewardAmount: [new BN11(0), new BN11(0)],
12270
- claimableFeeXAmount: new BN11(0),
12271
- claimableFeeYAmount: new BN11(0)
12272
- });
12273
- }
12274
- } else {
12275
- const binCountToShrink = this.upperBinId.sub(newMaxBinId);
12276
- for (let i = 1; i <= binCountToShrink.toNumber(); i++) {
12277
- this.rebalancePositionBinData.pop();
12278
- }
12279
- }
12280
- this.lowerBinId = newMinBinId;
12281
- this.upperBinId = newMaxBinId;
12072
+ address() {
12073
+ return this.positionAddress;
12282
12074
  }
12283
- _simulateWithdraw(withdraws) {
12284
- let liquidityAndFeeXWithdrawn = new BN11(0);
12285
- let liquidityAndFeeYWithdrawn = new BN11(0);
12286
- let rewardsAmountClaimed = [new BN11(0), new BN11(0)];
12287
- const activeId = new BN11(this.lbPair.activeId);
12288
- for (const { minBinId, maxBinId, bps } of withdraws) {
12289
- const fromBinId = minBinId ?? activeId;
12290
- const toBinId = maxBinId ?? activeId;
12291
- const binIds = binRangeToBinIdArray(fromBinId, toBinId).filter(
12292
- (binId) => binId.gte(this.lowerBinId) && binId.lte(this.upperBinId)
12293
- );
12294
- for (const binId of binIds) {
12295
- const idx = this.rebalancePositionBinData.findIndex(
12296
- (b) => b.binId === binId.toNumber()
12297
- );
12298
- const binData = this.rebalancePositionBinData[idx];
12299
- const amountXWithdrawn = binData.amountX.mul(bps).divn(BASIS_POINT_MAX);
12300
- const amountYWithdrawn = binData.amountY.mul(bps).divn(BASIS_POINT_MAX);
12301
- liquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn.add(amountXWithdrawn);
12302
- liquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn.add(amountYWithdrawn);
12303
- binData.amountX = binData.amountX.sub(amountXWithdrawn);
12304
- binData.amountY = binData.amountY.sub(amountYWithdrawn);
12305
- if (this.shouldClaimFee) {
12306
- liquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn.add(
12307
- binData.claimableFeeXAmount
12308
- );
12309
- liquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn.add(
12310
- binData.claimableFeeYAmount
12311
- );
12312
- binData.claimableFeeXAmount = new BN11(0);
12313
- binData.claimableFeeYAmount = new BN11(0);
12314
- }
12315
- if (this.shouldClaimReward) {
12316
- for (const [idx2, amount] of binData.claimableRewardAmount.entries()) {
12317
- rewardsAmountClaimed[idx2] = rewardsAmountClaimed[idx2].add(amount);
12318
- binData.claimableRewardAmount[idx2] = new BN11(0);
12319
- }
12320
- }
12321
- this.rebalancePositionBinData[idx] = binData;
12322
- }
12323
- }
12324
- const withdrawParams = withdraws.map(
12325
- ({ minBinId, maxBinId, bps }) => {
12326
- return {
12327
- minBinId: minBinId ? minBinId.toNumber() : null,
12328
- maxBinId: maxBinId ? maxBinId.toNumber() : null,
12329
- bps: bps.toNumber(),
12330
- padding: Array(16).fill(0)
12331
- };
12332
- }
12333
- );
12334
- return {
12335
- result: {
12336
- liquidityAndFeeXWithdrawn,
12337
- liquidityAndFeeYWithdrawn,
12338
- rewardsAmountClaimed
12339
- },
12340
- withdrawParams
12341
- };
12075
+ totalClaimedRewards() {
12076
+ return this.inner.totalClaimedRewards;
12342
12077
  }
12343
- async simulateRebalance(connection, binStep, tokenXDecimal, tokenYDecimal, withdraws, deposits) {
12344
- if (withdraws.length == 0 && deposits.length == 0) {
12345
- throw "No rebalance action";
12346
- }
12347
- const activeId = new BN11(this.lbPair.activeId);
12348
- withdraws = validateAndSortRebalanceWithdraw(withdraws, activeId);
12349
- deposits = validateAndSortRebalanceDeposit(deposits);
12350
- const beforeWidth = getPositionWidthWithMinWidth(
12351
- this.lowerBinId.toNumber(),
12352
- this.upperBinId.toNumber()
12353
- );
12354
- const { withdrawParams, result: withdrawResult } = this._simulateWithdraw(withdraws);
12355
- const { depositParams, result: depositResult } = this._simulateDeposit(
12356
- binStep,
12357
- tokenXDecimal,
12358
- tokenYDecimal,
12359
- deposits,
12360
- withdrawResult
12361
- );
12362
- const afterWidth = getPositionWidthWithMinWidth(
12363
- this.lowerBinId.toNumber(),
12364
- this.upperBinId.toNumber()
12365
- );
12366
- const widthDelta = afterWidth - beforeWidth;
12367
- let rentalCostLamports = new BN11(0);
12368
- if (widthDelta != 0) {
12369
- const sizeChanges = Math.abs(widthDelta) * POSITION_BIN_DATA_SIZE;
12370
- const [minimumLamports, rentExemptionLamports] = await Promise.all([
12371
- connection.getMinimumBalanceForRentExemption(0),
12372
- connection.getMinimumBalanceForRentExemption(sizeChanges)
12373
- ]);
12374
- const lamportChanges = new BN11(rentExemptionLamports).sub(
12375
- new BN11(minimumLamports)
12376
- );
12377
- if (widthDelta > 0) {
12378
- rentalCostLamports = rentalCostLamports.add(lamportChanges);
12379
- } else {
12380
- rentalCostLamports = rentalCostLamports.sub(lamportChanges);
12381
- }
12382
- }
12383
- return {
12384
- amountXDeposited: depositResult.totalAmountXDeposited,
12385
- amountYDeposited: depositResult.totalAmountYDeposited,
12386
- actualAmountXDeposited: depositResult.actualTotalAmountXDeposited,
12387
- actualAmountYDeposited: depositResult.actualTotalAmountYDeposited,
12388
- actualAmountXWithdrawn: depositResult.actualLiquidityAndFeeXWithdrawn,
12389
- actualAmountYWithdrawn: depositResult.actualLiquidityAndFeeYWithdrawn,
12390
- rewardAmountsClaimed: withdrawResult.rewardsAmountClaimed,
12391
- withdrawParams,
12392
- depositParams,
12393
- rentalCostLamports
12394
- };
12078
+ feeOwner() {
12079
+ return this.inner.feeOwner;
12080
+ }
12081
+ lockReleasePoint() {
12082
+ return this.inner.lockReleasePoint;
12083
+ }
12084
+ operator() {
12085
+ return this.inner.operator;
12086
+ }
12087
+ totalClaimedFeeYAmount() {
12088
+ return this.inner.totalClaimedFeeYAmount;
12089
+ }
12090
+ totalClaimedFeeXAmount() {
12091
+ return this.inner.totalClaimedFeeXAmount;
12395
12092
  }
12396
- totalAmounts() {
12397
- let totalAmountX = new BN11(0);
12398
- let totalAmountY = new BN11(0);
12399
- for (const binData of this.rebalancePositionBinData) {
12400
- totalAmountX = totalAmountX.add(binData.amountX);
12401
- totalAmountY = totalAmountY.add(binData.amountY);
12402
- }
12403
- return [totalAmountX, totalAmountY];
12093
+ lbPair() {
12094
+ return this.inner.lbPair;
12404
12095
  }
12405
- totalFeeAmounts() {
12406
- let totalFeeXAmount = new BN11(0);
12407
- let totalFeeYAmount = new BN11(0);
12408
- for (const binData of this.rebalancePositionBinData) {
12409
- totalFeeXAmount = totalFeeXAmount.add(binData.claimableFeeXAmount);
12410
- totalFeeYAmount = totalFeeYAmount.add(binData.claimableFeeYAmount);
12411
- }
12412
- return [totalFeeXAmount, totalFeeYAmount];
12096
+ lowerBinId() {
12097
+ return new BN12(this.inner.lowerBinId);
12413
12098
  }
12414
- totalRewardAmounts() {
12415
- let totalRewardAmounts = [new BN11(0), new BN11(0)];
12416
- for (const binData of this.rebalancePositionBinData) {
12417
- totalRewardAmounts[0] = totalRewardAmounts[0].add(
12418
- binData.claimableRewardAmount[0]
12419
- );
12420
- totalRewardAmounts[1] = totalRewardAmounts[1].add(
12421
- binData.claimableRewardAmount[1]
12422
- );
12423
- }
12424
- return totalRewardAmounts;
12099
+ upperBinId() {
12100
+ return new BN12(this.inner.upperBinId);
12425
12101
  }
12426
- };
12427
- function getPositionWidthWithMinWidth(lowerBinId, upperBinId) {
12428
- const width = upperBinId - lowerBinId + 1;
12429
- return Math.max(width, DEFAULT_BIN_PER_POSITION.toNumber());
12430
- }
12431
- function validateAndSortRebalanceDeposit(deposits) {
12432
- const sortedDeposits = deposits.sort(
12433
- (a, b) => a.minDeltaId.sub(b.minDeltaId).toNumber()
12434
- );
12435
- for (const deposit of deposits) {
12436
- if (deposit.minDeltaId.gte(deposit.maxDeltaId)) {
12437
- throw "Invalid minDeltaId or maxDeltaId";
12438
- }
12102
+ liquidityShares() {
12103
+ return this.combinedPositionBinData.liquidityShares;
12439
12104
  }
12440
- for (let i = 1; i < sortedDeposits.length; i++) {
12441
- const prevDeposit = sortedDeposits[i - 1];
12442
- const currDeposit = sortedDeposits[i];
12443
- if (prevDeposit.maxDeltaId.gte(currDeposit.minDeltaId)) {
12444
- throw "Overlap deposit bin range";
12445
- }
12105
+ rewardInfos() {
12106
+ return this.combinedPositionBinData.rewardInfos;
12446
12107
  }
12447
- return sortedDeposits;
12448
- }
12449
- function validateAndSortRebalanceWithdraw(withdraws, activeId) {
12450
- const filledWithdraws = [];
12451
- for (const { minBinId, maxBinId, bps } of withdraws) {
12452
- if (bps.toNumber() < 0 || bps.toNumber() > BASIS_POINT_MAX) {
12453
- throw "Invalid bps";
12454
- }
12455
- const filledMinBinId = minBinId ?? activeId;
12456
- const filledMaxBinId = maxBinId ?? activeId;
12457
- if (filledMinBinId.gt(filledMaxBinId)) {
12458
- throw "Invalid minBinId or maxBinId";
12459
- }
12460
- filledWithdraws.push({
12461
- minBinId: filledMinBinId,
12462
- maxBinId: filledMaxBinId,
12463
- bps
12464
- });
12108
+ feeInfos() {
12109
+ return this.combinedPositionBinData.feeInfos;
12465
12110
  }
12466
- filledWithdraws.sort((a, b) => {
12467
- return a.minBinId.sub(b.minBinId).toNumber();
12468
- });
12469
- for (let i = 1; i < filledWithdraws.length; i++) {
12470
- const prev = filledWithdraws[i - 1];
12471
- const curr = filledWithdraws[i];
12472
- if (curr.minBinId.lte(prev.maxBinId)) {
12473
- throw "Overlap withdraw bin range";
12111
+ lastUpdatedAt() {
12112
+ return this.inner.lastUpdatedAt;
12113
+ }
12114
+ getBinArrayIndexesCoverage() {
12115
+ const isExtended = this.extended.length > 0;
12116
+ if (isExtended) {
12117
+ return getBinArrayIndexesCoverage(this.lowerBinId(), this.upperBinId());
12118
+ } else {
12119
+ const lowerBinArrayIndex = binIdToBinArrayIndex(this.lowerBinId());
12120
+ const upperBinArrayIndex = lowerBinArrayIndex.add(new BN12(1));
12121
+ return [lowerBinArrayIndex, upperBinArrayIndex];
12474
12122
  }
12475
12123
  }
12476
- return filledWithdraws;
12477
- }
12478
- function binRangeToBinIdArray(minBinId, maxBinId) {
12479
- const binIdArray = [];
12480
- const fromBinId = minBinId.toNumber();
12481
- const toBinId = maxBinId.toNumber();
12482
- for (let binId = fromBinId; binId <= toBinId; binId++) {
12483
- binIdArray.push(new BN11(binId));
12124
+ getBinArrayKeysCoverage(programId) {
12125
+ return this.getBinArrayIndexesCoverage().map(
12126
+ (index) => deriveBinArray(this.lbPair(), index, programId)[0]
12127
+ );
12484
12128
  }
12485
- return binIdArray;
12129
+ version() {
12130
+ return 1 /* V2 */;
12131
+ }
12132
+ owner() {
12133
+ return this.inner.owner;
12134
+ }
12135
+ width() {
12136
+ return this.upperBinId().sub(this.lowerBinId()).add(new BN12(1));
12137
+ }
12138
+ };
12139
+
12140
+ // src/dlmm/helpers/positions/index.ts
12141
+ function getBinArrayIndexesCoverage(lowerBinId, upperBinId) {
12142
+ const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);
12143
+ const upperBinArrayIndex = binIdToBinArrayIndex(upperBinId);
12144
+ const binArrayIndexes = [];
12145
+ for (let i = lowerBinArrayIndex.toNumber(); i <= upperBinArrayIndex.toNumber(); i++) {
12146
+ binArrayIndexes.push(new BN13(i));
12147
+ }
12148
+ return binArrayIndexes;
12486
12149
  }
12487
- function getRebalanceBinArrayIndexesAndBitmapCoverage(adds, removes, activeId, pairAddress, programId) {
12488
- let indexMap = /* @__PURE__ */ new Map();
12489
- removes.forEach((value) => {
12490
- let minBinId = value.minBinId;
12491
- if (minBinId == null) {
12492
- minBinId = activeId;
12493
- }
12494
- let maxBinId = value.maxBinId;
12495
- if (maxBinId == null) {
12496
- maxBinId = activeId;
12497
- }
12498
- let binArrayIndex = binIdToBinArrayIndex(new BN11(minBinId));
12499
- const upperBinId = new BN11(maxBinId);
12500
- while (true) {
12501
- indexMap.set(binArrayIndex.toNumber(), true);
12502
- const [binArrayLowerBinId, binArrayUpperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
12503
- if (upperBinId.gte(binArrayLowerBinId) && upperBinId.lte(binArrayUpperBinId)) {
12504
- break;
12505
- } else {
12506
- binArrayIndex = binArrayIndex.add(new BN11(1));
12507
- }
12508
- }
12150
+ function getBinArrayKeysCoverage2(lowerBinId, upperBinId, lbPair, programId) {
12151
+ const binArrayIndexes = getBinArrayIndexesCoverage(lowerBinId, upperBinId);
12152
+ return binArrayIndexes.map((index) => {
12153
+ return deriveBinArray(lbPair, index, programId)[0];
12509
12154
  });
12510
- adds.forEach((value) => {
12511
- const minBinId = activeId + value.minDeltaId;
12512
- const maxBinId = activeId + value.maxDeltaId;
12513
- let binArrayIndex = binIdToBinArrayIndex(new BN11(minBinId));
12514
- const upperBinId = new BN11(maxBinId);
12515
- while (true) {
12516
- indexMap.set(binArrayIndex.toNumber(), true);
12517
- const [binArrayLowerBinId, binArrayUpperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
12518
- if (upperBinId.gte(binArrayLowerBinId) && upperBinId.lte(binArrayUpperBinId)) {
12519
- break;
12520
- } else {
12521
- binArrayIndex = binArrayIndex.add(new BN11(1));
12522
- }
12155
+ }
12156
+ function getBinArrayAccountMetasCoverage(lowerBinId, upperBinId, lbPair, programId) {
12157
+ return getBinArrayKeysCoverage2(lowerBinId, upperBinId, lbPair, programId).map(
12158
+ (key) => {
12159
+ return {
12160
+ pubkey: key,
12161
+ isSigner: false,
12162
+ isWritable: true
12163
+ };
12523
12164
  }
12524
- });
12525
- const binArrayIndexes = Array.from(indexMap.keys()).map((idx) => new BN11(idx));
12526
- const requireBitmapExtension = binArrayIndexes.some(
12527
- (index) => isOverflowDefaultBinArrayBitmap(new BN11(index))
12528
12165
  );
12529
- return {
12530
- binArrayIndexes,
12531
- binArrayBitmap: requireBitmapExtension ? deriveBinArrayBitmapExtension(pairAddress, programId)[0] : programId
12532
- };
12533
12166
  }
12534
-
12535
- // src/dlmm/helpers/rebalance/liquidity_strategy/index.ts
12536
- import BN15 from "bn.js";
12537
-
12538
- // src/dlmm/helpers/rebalance/liquidity_strategy/bidAsk.ts
12539
- import BN12 from "bn.js";
12540
- function findBaseDeltaY(amountY, minDeltaId, maxDeltaId) {
12541
- if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN12(0))) {
12542
- return new BN12(0);
12543
- }
12544
- if (minDeltaId.eq(maxDeltaId)) {
12545
- return amountY;
12546
- }
12547
- const m1 = minDeltaId.neg().subn(1);
12548
- const m2 = maxDeltaId.neg();
12549
- const b = m2.neg().mul(m1.sub(m2).addn(1));
12550
- const c = m1.mul(m1.addn(1)).divn(2);
12551
- const d = m2.mul(m2.subn(1)).divn(2);
12552
- const a = b.add(c.sub(d));
12553
- return amountY.div(a);
12167
+ function getPositionLowerUpperBinIdWithLiquidity(position) {
12168
+ const binWithLiquidity = position.positionBinData.filter(
12169
+ (b) => !new BN13(b.binLiquidity).isZero() || !new BN13(b.positionFeeXAmount.toString()).isZero() || !new BN13(b.positionFeeYAmount.toString()).isZero() || !new BN13(b.positionRewardAmount[0].toString()).isZero() || !new BN13(b.positionRewardAmount[1].toString()).isZero()
12170
+ );
12171
+ return binWithLiquidity.length > 0 ? {
12172
+ lowerBinId: new BN13(binWithLiquidity[0].binId),
12173
+ upperBinId: new BN13(binWithLiquidity[binWithLiquidity.length - 1].binId)
12174
+ } : null;
12554
12175
  }
12555
- function findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId) {
12556
- if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {
12557
- return {
12558
- base: new BN12(0),
12559
- delta: new BN12(0)
12560
- };
12176
+ function isPositionNoFee(position) {
12177
+ return position.feeX.isZero() && position.feeY.isZero();
12178
+ }
12179
+ function isPositionNoReward(position) {
12180
+ return position.rewardOne.isZero() && position.rewardTwo.isZero();
12181
+ }
12182
+ function chunkBinRange(minBinId, maxBinId) {
12183
+ const chunkedBinRange = [];
12184
+ let startBinId = minBinId;
12185
+ while (startBinId <= maxBinId) {
12186
+ const endBinId = Math.min(
12187
+ startBinId + DEFAULT_BIN_PER_POSITION.toNumber() - 1,
12188
+ maxBinId
12189
+ );
12190
+ chunkedBinRange.push({
12191
+ lowerBinId: startBinId,
12192
+ upperBinId: endBinId
12193
+ });
12194
+ startBinId += DEFAULT_BIN_PER_POSITION.toNumber();
12561
12195
  }
12562
- let baseDeltaY = findBaseDeltaY(amountY, minDeltaId, maxDeltaId);
12563
- const y0 = baseDeltaY.neg().mul(maxDeltaId).add(baseDeltaY);
12564
- while (true) {
12565
- const amountInBins = getAmountInBinsBidSide(
12566
- activeId,
12567
- minDeltaId,
12568
- maxDeltaId,
12569
- baseDeltaY,
12570
- y0
12196
+ return chunkedBinRange;
12197
+ }
12198
+ async function getPositionExpandRentExemption(currentMinBinId, currentMaxBinId, connection, binCountToExpand) {
12199
+ const currentPositionWidth = currentMaxBinId.sub(currentMinBinId).addn(1);
12200
+ const positionWidthAfterExpand = currentPositionWidth.add(binCountToExpand);
12201
+ if (positionWidthAfterExpand.lte(DEFAULT_BIN_PER_POSITION)) {
12202
+ return 0;
12203
+ } else {
12204
+ const binCountInExpandedBytes = positionWidthAfterExpand.sub(
12205
+ DEFAULT_BIN_PER_POSITION
12571
12206
  );
12572
- const totalAmountY = amountInBins.reduce((acc, { amountY: amountY2 }) => {
12573
- return acc.add(amountY2);
12574
- }, new BN12(0));
12575
- if (totalAmountY.gt(amountY)) {
12576
- baseDeltaY = baseDeltaY.sub(new BN12(1));
12577
- } else {
12578
- return {
12579
- base: y0,
12580
- delta: baseDeltaY
12581
- };
12582
- }
12207
+ const expandSize = binCountInExpandedBytes.toNumber() * POSITION_BIN_DATA_SIZE;
12208
+ const [minimumLamports, rentExemptionLamports] = await Promise.all([
12209
+ connection.getMinimumBalanceForRentExemption(0),
12210
+ connection.getMinimumBalanceForRentExemption(expandSize)
12211
+ ]);
12212
+ return rentExemptionLamports - minimumLamports;
12213
+ }
12214
+ }
12215
+ function getExtendedPositionBinCount(minBinId, maxBinId) {
12216
+ const width = maxBinId.sub(minBinId).addn(1);
12217
+ const extended = width.sub(DEFAULT_BIN_PER_POSITION);
12218
+ return extended.lte(new BN13(0)) ? new BN13(0) : extended;
12219
+ }
12220
+ function decodeExtendedPosition(base, program, bytes) {
12221
+ const width = base.upperBinId - base.lowerBinId + 1;
12222
+ const extendedWidth = width - DEFAULT_BIN_PER_POSITION.toNumber();
12223
+ const extendedPosition = [];
12224
+ for (let i = 0; i < extendedWidth; i++) {
12225
+ const offset = i * POSITION_BIN_DATA_SIZE;
12226
+ const data = bytes.subarray(offset, offset + POSITION_BIN_DATA_SIZE);
12227
+ const decodedPositionBinData = program.coder.types.decode(
12228
+ // TODO: Find a type safe way
12229
+ "positionBinData",
12230
+ data
12231
+ );
12232
+ extendedPosition.push(decodedPositionBinData);
12583
12233
  }
12234
+ return extendedPosition;
12584
12235
  }
12585
- function findBaseDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12586
- if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN12(0))) {
12587
- return new BN12(0);
12236
+
12237
+ // src/dlmm/helpers/rebalance/rebalancePosition.ts
12238
+ import { SYSVAR_CLOCK_PUBKEY } from "@solana/web3.js";
12239
+ import BN14 from "bn.js";
12240
+ import Decimal6 from "decimal.js";
12241
+ function buildBitFlagAndNegateStrategyParameters(x0, y0, deltaX, deltaY) {
12242
+ let bitFlag = 0;
12243
+ if (x0.isNeg()) {
12244
+ bitFlag |= 1;
12245
+ x0 = x0.neg();
12588
12246
  }
12589
- let b = new BN12(0);
12590
- let c = new BN12(0);
12591
- let m1 = minDeltaId;
12592
- let m2 = maxDeltaId.addn(1);
12593
- for (let m = m1.toNumber(); m <= m2.toNumber(); m++) {
12594
- const binId = activeId.addn(m);
12595
- const pm = getQPriceFromId(binId.neg(), binStep);
12596
- const bDelta = m1.mul(pm);
12597
- b = b.add(bDelta);
12598
- const cDelta = new BN12(m).mul(pm);
12599
- c = c.add(cDelta);
12247
+ if (y0.isNeg()) {
12248
+ bitFlag |= 2;
12249
+ y0 = y0.neg();
12600
12250
  }
12601
- return amountX.shln(SCALE_OFFSET).div(c.sub(b));
12602
- }
12603
- function findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12604
- if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN12(0)) || amountX.isZero()) {
12605
- return {
12606
- base: new BN12(0),
12607
- delta: new BN12(0)
12608
- };
12251
+ if (deltaX.isNeg()) {
12252
+ bitFlag |= 4;
12253
+ deltaX = deltaX.neg();
12609
12254
  }
12610
- let baseDeltaX = findBaseDeltaX(
12611
- amountX,
12612
- minDeltaId,
12613
- maxDeltaId,
12614
- binStep,
12615
- activeId
12616
- );
12617
- const x0 = minDeltaId.neg().mul(baseDeltaX).add(baseDeltaX);
12618
- while (true) {
12619
- const amountInBins = getAmountInBinsAskSide(
12620
- activeId,
12621
- binStep,
12622
- minDeltaId,
12623
- maxDeltaId,
12624
- baseDeltaX,
12625
- x0
12626
- );
12627
- const totalAmountX = amountInBins.reduce((acc, { amountX: amountX2 }) => {
12628
- return acc.add(amountX2);
12629
- }, new BN12(0));
12630
- if (totalAmountX.gt(amountX)) {
12631
- baseDeltaX = baseDeltaX.sub(new BN12(1));
12632
- } else {
12255
+ if (deltaY.isNeg()) {
12256
+ bitFlag |= 8;
12257
+ deltaY = deltaY.neg();
12258
+ }
12259
+ return {
12260
+ bitFlag,
12261
+ x0,
12262
+ y0,
12263
+ deltaX,
12264
+ deltaY
12265
+ };
12266
+ }
12267
+ function toRebalancePositionBinData(positionData) {
12268
+ return positionData.positionBinData.map(
12269
+ ({
12270
+ binId,
12271
+ price,
12272
+ pricePerToken,
12273
+ positionXAmount,
12274
+ positionYAmount,
12275
+ positionFeeXAmount,
12276
+ positionFeeYAmount,
12277
+ positionRewardAmount
12278
+ }) => {
12633
12279
  return {
12634
- base: x0,
12635
- delta: baseDeltaX
12280
+ binId,
12281
+ price,
12282
+ pricePerToken,
12283
+ amountX: new BN14(positionXAmount),
12284
+ amountY: new BN14(positionYAmount),
12285
+ claimableRewardAmount: positionRewardAmount.map(
12286
+ (amount) => new BN14(amount)
12287
+ ),
12288
+ claimableFeeXAmount: new BN14(positionFeeXAmount),
12289
+ claimableFeeYAmount: new BN14(positionFeeYAmount)
12636
12290
  };
12637
12291
  }
12292
+ );
12293
+ }
12294
+ function getDepositBinIds(activeId, deposits) {
12295
+ const uniqueBinId = /* @__PURE__ */ new Set();
12296
+ for (const { minDeltaId, maxDeltaId } of deposits) {
12297
+ const minBinId = activeId.add(minDeltaId);
12298
+ const maxBinId = activeId.add(maxDeltaId);
12299
+ for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
12300
+ uniqueBinId.add(binId);
12301
+ }
12638
12302
  }
12303
+ const binIds = Array.from(uniqueBinId);
12304
+ binIds.sort((a, b) => a - b);
12305
+ return binIds;
12639
12306
  }
12640
- var BidAskStrategyParameterBuilder = class {
12641
- findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12642
- return findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId);
12307
+ function findMinMaxBinIdWithLiquidity(rebalancePositionBinData) {
12308
+ let minBinId = null;
12309
+ let maxBinId = null;
12310
+ for (const binData of rebalancePositionBinData) {
12311
+ if (binData.amountX.isZero() && binData.amountY.isZero() && binData.claimableFeeXAmount.isZero() && binData.claimableFeeYAmount.isZero() && binData.claimableRewardAmount.every((amount) => amount.isZero())) {
12312
+ continue;
12313
+ }
12314
+ if (minBinId == null || binData.binId < minBinId) {
12315
+ minBinId = binData.binId;
12316
+ }
12317
+ if (maxBinId == null || binData.binId > maxBinId) {
12318
+ maxBinId = binData.binId;
12319
+ }
12643
12320
  }
12644
- findYParameters(amountY, minDeltaId, maxDeltaId, activeId) {
12645
- return findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId);
12321
+ return [minBinId, maxBinId];
12322
+ }
12323
+ function onlyDepositToBidSide(maxDeltaId, favorXInActiveBin) {
12324
+ if (favorXInActiveBin) {
12325
+ return maxDeltaId.lt(new BN14(0));
12646
12326
  }
12647
- suggestBalancedXParametersFromY(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountY) {
12648
- const deltaX = amountY.div(
12649
- maxDeltaId.addn(1).mul(maxDeltaId.addn(2)).divn(2)
12650
- );
12651
- const x0 = minDeltaId.neg().mul(deltaX).add(deltaX);
12652
- const totalAmountX = toAmountIntoBins(
12653
- activeId,
12654
- minDeltaId,
12655
- maxDeltaId,
12656
- deltaX,
12657
- new BN12(0),
12658
- x0,
12659
- new BN12(0),
12660
- binStep,
12661
- favorXInActiveBin
12662
- ).reduce((acc, bin) => {
12663
- return acc.add(bin.amountX);
12664
- }, new BN12(0));
12665
- return {
12666
- base: x0,
12667
- delta: deltaX,
12668
- amountX: totalAmountX
12669
- };
12327
+ return maxDeltaId.lte(new BN14(0));
12328
+ }
12329
+ function onlyDepositToAskSide(minDeltaId, favorXInActiveBin) {
12330
+ if (favorXInActiveBin) {
12331
+ return minDeltaId.gte(new BN14(0));
12670
12332
  }
12671
- suggestBalancedYParametersFromX(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountXInQuoteValue) {
12672
- const m1 = minDeltaId.neg().subn(1);
12673
- const m2 = maxDeltaId.neg();
12674
- const a1 = m2.neg().mul(m1.sub(m2).addn(1));
12675
- const a2 = m1.mul(m1.addn(1)).divn(2);
12676
- const a3 = m2.mul(m2.subn(1)).divn(2);
12677
- const a = a1.add(a2.sub(a3));
12678
- const deltaY = amountXInQuoteValue.div(a);
12679
- const y0 = deltaY.neg().mul(m2).add(deltaY);
12680
- const amountY = toAmountIntoBins(
12681
- activeId,
12682
- minDeltaId,
12683
- maxDeltaId,
12684
- new BN12(0),
12685
- deltaY,
12686
- new BN12(0),
12687
- y0,
12688
- binStep,
12689
- favorXInActiveBin
12690
- ).reduce((acc, bin) => {
12691
- return acc.add(bin.amountY);
12692
- }, new BN12(0));
12693
- return {
12694
- base: y0,
12695
- delta: deltaY,
12333
+ return minDeltaId.gt(new BN14(0));
12334
+ }
12335
+ function getAmountInBinsBidSide(activeId, minDeltaId, maxDeltaId, deltaY, y0) {
12336
+ const amountInBins = [];
12337
+ const minBinId = activeId.add(minDeltaId);
12338
+ const maxBinId = activeId.add(maxDeltaId);
12339
+ for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
12340
+ const deltaBin = activeId.toNumber() - binId;
12341
+ const totalDeltaY = deltaY.mul(new BN14(deltaBin));
12342
+ const amountY = y0.add(totalDeltaY);
12343
+ amountInBins.push({
12344
+ binId: new BN14(binId),
12345
+ amountX: new BN14(0),
12696
12346
  amountY
12697
- };
12698
- }
12699
- };
12700
-
12701
- // src/dlmm/helpers/rebalance/liquidity_strategy/curve.ts
12702
- import BN13 from "bn.js";
12703
- function findBaseY0(amountY, minDeltaId, maxDeltaId) {
12704
- if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN13(0))) {
12705
- return new BN13(0);
12706
- }
12707
- if (minDeltaId.eq(maxDeltaId)) {
12708
- return amountY;
12347
+ });
12709
12348
  }
12710
- const m1 = minDeltaId.neg();
12711
- const m2 = maxDeltaId.neg();
12712
- const b = m1.sub(m2).addn(1);
12713
- const c = m1.mul(m1.addn(1)).divn(2);
12714
- const d = m2.mul(m2.subn(1)).divn(2);
12715
- const a = b.sub(c.sub(d).div(m1.addn(1)));
12716
- return amountY.div(a);
12349
+ return amountInBins;
12717
12350
  }
12718
- function findY0AndDeltaY2(amountY, minDeltaId, maxDeltaId, activeId) {
12719
- if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {
12720
- return {
12721
- base: new BN13(0),
12722
- delta: new BN13(0)
12351
+ function getAmountInBinsAskSide(activeId, binStep, minDeltaId, maxDeltaId, deltaX, x0) {
12352
+ const binCount = maxDeltaId.sub(minDeltaId).add(new BN14(1));
12353
+ const minBinId = activeId.add(minDeltaId);
12354
+ const maxBinId = activeId.add(maxDeltaId);
12355
+ const amountInBins = new Array(binCount.toNumber());
12356
+ const base = getQPriceBaseFactor(binStep);
12357
+ let inverseBasePrice = pow(base, maxBinId.neg());
12358
+ for (let binId = maxBinId.toNumber(); binId >= minBinId.toNumber(); binId--) {
12359
+ const delta = binId - activeId.toNumber();
12360
+ const totalDeltaX = deltaX.mul(new BN14(delta));
12361
+ const amountX = x0.add(totalDeltaX).mul(inverseBasePrice).shrn(SCALE_OFFSET);
12362
+ const idx = binId - minBinId.toNumber();
12363
+ amountInBins[idx] = {
12364
+ binId: new BN14(binId),
12365
+ amountX,
12366
+ amountY: new BN14(0)
12723
12367
  };
12368
+ inverseBasePrice = inverseBasePrice.mul(base).shrn(SCALE_OFFSET);
12724
12369
  }
12725
- let baseY0 = findBaseY0(amountY, minDeltaId, maxDeltaId);
12726
- while (true) {
12727
- const deltaY = baseY0.neg().div(minDeltaId.neg().addn(1));
12728
- const amountInBins = getAmountInBinsBidSide(
12729
- activeId,
12730
- minDeltaId,
12731
- maxDeltaId,
12732
- deltaY,
12733
- baseY0
12734
- );
12735
- const totalAmountY = amountInBins.reduce((acc, { amountY: amountY2 }) => {
12736
- return acc.add(amountY2);
12737
- }, new BN13(0));
12738
- if (totalAmountY.gt(amountY)) {
12739
- baseY0 = baseY0.sub(new BN13(1));
12740
- } else {
12741
- return {
12742
- base: baseY0,
12743
- delta: deltaY
12744
- };
12745
- }
12746
- }
12747
- }
12748
- function findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12749
- if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN13(0))) {
12750
- return new BN13(0);
12751
- }
12752
- let b = new BN13(0);
12753
- let c = new BN13(0);
12754
- let m1 = minDeltaId;
12755
- let m2 = maxDeltaId;
12756
- for (let m = m1.toNumber(); m <= m2.toNumber(); m++) {
12757
- const binId = activeId.addn(m);
12758
- const pm = getQPriceFromId(binId.neg(), binStep);
12759
- b = b.add(pm);
12760
- const cDelta = new BN13(m).mul(pm).div(m2);
12761
- c = c.add(cDelta);
12762
- }
12763
- return amountX.shln(SCALE_OFFSET).div(b.sub(c));
12370
+ return amountInBins;
12764
12371
  }
12765
- function findX0AndDeltaX2(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12766
- if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN13(0)) || amountX.isZero()) {
12767
- return {
12768
- base: new BN13(0),
12769
- delta: new BN13(0)
12770
- };
12372
+ function toAmountIntoBins(activeId, minDeltaId, maxDeltaId, deltaX, deltaY, x0, y0, binStep, favorXInActiveBin) {
12373
+ if (onlyDepositToBidSide(maxDeltaId, favorXInActiveBin)) {
12374
+ return getAmountInBinsBidSide(activeId, minDeltaId, maxDeltaId, deltaY, y0);
12771
12375
  }
12772
- let baseX0 = findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId);
12773
- const deltaX = baseX0.neg().div(maxDeltaId);
12774
- while (true) {
12775
- const amountInBins = getAmountInBinsAskSide(
12376
+ if (onlyDepositToAskSide(minDeltaId, favorXInActiveBin)) {
12377
+ return getAmountInBinsAskSide(
12776
12378
  activeId,
12777
12379
  binStep,
12778
12380
  minDeltaId,
12779
12381
  maxDeltaId,
12780
12382
  deltaX,
12781
- baseX0
12383
+ x0
12384
+ );
12385
+ }
12386
+ const [bidSideEndDeltaId, askSideStartDeltaId] = favorXInActiveBin ? [-1, 0] : [0, 1];
12387
+ const amountInBinsBidSide = getAmountInBinsBidSide(
12388
+ activeId,
12389
+ minDeltaId,
12390
+ new BN14(bidSideEndDeltaId),
12391
+ deltaY,
12392
+ y0
12393
+ );
12394
+ const amountInBinsAskSide = getAmountInBinsAskSide(
12395
+ activeId,
12396
+ binStep,
12397
+ new BN14(askSideStartDeltaId),
12398
+ maxDeltaId,
12399
+ deltaX,
12400
+ x0
12401
+ );
12402
+ return amountInBinsBidSide.concat(amountInBinsAskSide);
12403
+ }
12404
+ function getLiquidity(x, y, price) {
12405
+ const px = price.mul(x);
12406
+ const shly = y.shln(SCALE_OFFSET);
12407
+ return px.add(shly);
12408
+ }
12409
+ function computeCompositionFee(binStep, sParameters3, vParameters3, outAmountX, inAmountX, outAmountY, inAmountY) {
12410
+ if (outAmountX.gt(inAmountX)) {
12411
+ const delta = inAmountY.sub(outAmountY);
12412
+ const totalFeeRate = getTotalFee(
12413
+ binStep.toNumber(),
12414
+ sParameters3,
12415
+ vParameters3
12782
12416
  );
12783
- const totalAmountX = amountInBins.reduce((acc, { amountX: amountX2 }) => {
12784
- return acc.add(amountX2);
12785
- }, new BN13(0));
12786
- if (totalAmountX.gt(amountX)) {
12787
- baseX0 = baseX0.sub(new BN13(1));
12788
- } else {
12789
- return {
12790
- base: baseX0,
12791
- delta: deltaX
12792
- };
12793
- }
12417
+ const feeAmount = delta.mul(totalFeeRate);
12418
+ return feeAmount.mul(FEE_PRECISION.add(totalFeeRate)).div(FEE_PRECISION.pow(new BN14(2)));
12794
12419
  }
12420
+ return new BN14(0);
12795
12421
  }
12796
- var CurveStrategyParameterBuilder = class {
12797
- findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12798
- return findX0AndDeltaX2(amountX, minDeltaId, maxDeltaId, binStep, activeId);
12799
- }
12800
- findYParameters(amountY, minDeltaId, maxDeltaId, activeId) {
12801
- return findY0AndDeltaY2(amountY, minDeltaId, maxDeltaId, activeId);
12802
- }
12803
- suggestBalancedXParametersFromY(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountY) {
12804
- const x0 = amountY.muln(2).div(maxDeltaId.addn(1));
12805
- const deltaX = x0.neg().div(maxDeltaId);
12806
- const totalAmountX = toAmountIntoBins(
12807
- activeId,
12808
- minDeltaId,
12809
- maxDeltaId,
12810
- deltaX,
12811
- new BN13(0),
12812
- x0,
12813
- new BN13(0),
12814
- binStep,
12815
- favorXInActiveBin
12816
- ).reduce((acc, bin) => {
12817
- return acc.add(bin.amountX);
12818
- }, new BN13(0));
12422
+ function simulateDepositBin(binId, binStep, amountX, amountY, bin) {
12423
+ if (!bin) {
12819
12424
  return {
12820
- base: x0,
12821
- delta: deltaX,
12822
- amountX: totalAmountX
12425
+ amountXIntoBin: amountX,
12426
+ amountYIntoBin: amountY
12823
12427
  };
12824
12428
  }
12825
- suggestBalancedYParametersFromX(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountXInQuoteValue) {
12826
- const m1 = minDeltaId.neg();
12827
- const m2 = maxDeltaId.neg();
12828
- const a1 = m1.sub(m2).addn(1);
12829
- const a2 = m1.mul(m1.addn(1)).divn(2);
12830
- const a3 = m2.mul(m2.subn(1)).divn(2);
12831
- const a = m1.sub(a3.sub(a2)).div(m1);
12832
- const y0 = amountXInQuoteValue.div(a);
12833
- const deltaY = y0.neg().div(m1);
12834
- const amountY = toAmountIntoBins(
12835
- activeId,
12836
- minDeltaId,
12837
- maxDeltaId,
12838
- new BN13(0),
12839
- deltaY,
12840
- new BN13(0),
12841
- y0,
12842
- binStep,
12843
- favorXInActiveBin
12844
- ).reduce((acc, bin) => {
12845
- return acc.add(bin.amountY);
12846
- }, new BN13(0));
12429
+ const price = getQPriceFromId(binId, binStep);
12430
+ const inLiquidity = getLiquidity(amountX, amountY, price);
12431
+ const binLiquidity = getLiquidity(bin.amountX, bin.amountY, price);
12432
+ if (bin.liquiditySupply.isZero()) {
12847
12433
  return {
12848
- base: y0,
12849
- delta: deltaY,
12850
- amountY
12434
+ amountXIntoBin: amountX,
12435
+ amountYIntoBin: amountY
12851
12436
  };
12852
12437
  }
12853
- };
12854
-
12855
- // src/dlmm/helpers/rebalance/liquidity_strategy/spot.ts
12856
- import BN14 from "bn.js";
12857
- function findY0(amountY, minDeltaId, maxDeltaId) {
12858
- if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN14(0)) || amountY.isZero()) {
12859
- return new BN14(0);
12438
+ const liquidityShare = inLiquidity.mul(bin.liquiditySupply).div(binLiquidity);
12439
+ const updatedBinXAmount = bin.amountX.add(amountX);
12440
+ const updatedBinYAmount = bin.amountY.add(amountY);
12441
+ const updatedBinSupply = bin.liquiditySupply.add(liquidityShare);
12442
+ let amountXIntoBin = liquidityShare.mul(
12443
+ updatedBinXAmount.div(updatedBinSupply)
12444
+ );
12445
+ let amountYIntoBin = liquidityShare.mul(
12446
+ updatedBinYAmount.div(updatedBinSupply)
12447
+ );
12448
+ if (amountXIntoBin.gt(amountX)) {
12860
12449
  }
12861
- const m1 = minDeltaId.neg();
12862
- const m2 = maxDeltaId.neg();
12863
- const delta = m1.sub(m2).addn(1);
12864
- return amountY.div(delta);
12450
+ return {
12451
+ amountXIntoBin,
12452
+ amountYIntoBin
12453
+ };
12865
12454
  }
12866
- function findBaseX02(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12867
- let totalWeight = new BN14(0);
12868
- const minBinId = activeId.add(minDeltaId);
12869
- const maxBinId = activeId.add(maxDeltaId);
12870
- let baseFactor = getQPriceBaseFactor(binStep);
12871
- let basePrice = getQPriceFromId(maxBinId.neg(), binStep);
12872
- for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
12873
- totalWeight = totalWeight.add(basePrice);
12874
- basePrice = basePrice.mul(baseFactor).shrn(SCALE_OFFSET);
12455
+ var RebalancePosition = class {
12456
+ address;
12457
+ lowerBinId;
12458
+ upperBinId;
12459
+ lbPair;
12460
+ owner;
12461
+ shouldClaimFee;
12462
+ shouldClaimReward;
12463
+ rebalancePositionBinData;
12464
+ activeBin;
12465
+ currentTimestamp;
12466
+ constructor(positionAddress, positionData, lbPair, activeBin, shouldClaimFee, shouldClaimReward, currentTimestamp) {
12467
+ this.address = positionAddress;
12468
+ this.rebalancePositionBinData = toRebalancePositionBinData(positionData);
12469
+ this.lowerBinId = new BN14(positionData.lowerBinId);
12470
+ this.upperBinId = new BN14(positionData.upperBinId);
12471
+ this.lbPair = lbPair;
12472
+ this.shouldClaimFee = shouldClaimFee;
12473
+ this.shouldClaimReward = shouldClaimReward;
12474
+ this.owner = positionData.owner;
12475
+ this.activeBin = activeBin;
12476
+ this.currentTimestamp = currentTimestamp;
12875
12477
  }
12876
- return amountX.shln(SCALE_OFFSET).div(totalWeight);
12877
- }
12878
- function findX0(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12879
- if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN14(0)) || amountX.isZero()) {
12880
- return new BN14(0);
12478
+ static async create(params) {
12479
+ const {
12480
+ program,
12481
+ positionAddress,
12482
+ pairAddress,
12483
+ positionData,
12484
+ shouldClaimFee,
12485
+ shouldClaimReward
12486
+ } = params;
12487
+ const [lbPairAccount, clockAccount] = await program.provider.connection.getMultipleAccountsInfo([
12488
+ pairAddress,
12489
+ SYSVAR_CLOCK_PUBKEY
12490
+ ]);
12491
+ const lbPair = decodeAccount(program, "lbPair", lbPairAccount.data);
12492
+ const clock = ClockLayout.decode(clockAccount.data);
12493
+ const activeBinArrayIdx = binIdToBinArrayIndex(new BN14(lbPair.activeId));
12494
+ const [activeBinArrayPubkey] = deriveBinArray(
12495
+ pairAddress,
12496
+ activeBinArrayIdx,
12497
+ program.programId
12498
+ );
12499
+ const activeBinArrayState = await program.account.binArray.fetch(
12500
+ activeBinArrayPubkey
12501
+ );
12502
+ const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(activeBinArrayIdx);
12503
+ const idx = getBinIdIndexInBinArray(
12504
+ new BN14(lbPair.activeId),
12505
+ lowerBinId,
12506
+ upperBinId
12507
+ );
12508
+ const activeBin = activeBinArrayState[idx.toNumber()];
12509
+ return new RebalancePosition(
12510
+ positionAddress,
12511
+ positionData,
12512
+ lbPair,
12513
+ activeBin,
12514
+ shouldClaimFee,
12515
+ shouldClaimReward,
12516
+ clock.unixTimestamp
12517
+ );
12881
12518
  }
12882
- let x0 = findBaseX02(amountX, minDeltaId, maxDeltaId, binStep, activeId);
12883
- while (true) {
12884
- const amountInBins = getAmountInBinsAskSide(
12885
- activeId,
12886
- binStep,
12519
+ _simulateDeposit(binStep, tokenXDecimal, tokenYDecimal, deposits, simulatedWithdrawResult) {
12520
+ const { liquidityAndFeeXWithdrawn, liquidityAndFeeYWithdrawn } = simulatedWithdrawResult;
12521
+ const activeId = new BN14(this.lbPair.activeId);
12522
+ const depositBinIds = getDepositBinIds(activeId, deposits);
12523
+ if (depositBinIds.length > 0) {
12524
+ const depositMinBinId = depositBinIds[0];
12525
+ const depositMaxBinId = depositBinIds[depositBinIds.length - 1];
12526
+ this._simulateResize(
12527
+ new BN14(depositMinBinId),
12528
+ new BN14(depositMaxBinId),
12529
+ binStep,
12530
+ tokenXDecimal,
12531
+ tokenYDecimal
12532
+ );
12533
+ }
12534
+ let totalAmountXDeposited = new BN14(0);
12535
+ let totalAmountYDeposited = new BN14(0);
12536
+ const addLiquidityParam = [];
12537
+ for (const {
12538
+ x0,
12539
+ y0,
12540
+ favorXInActiveBin,
12541
+ deltaX,
12542
+ deltaY,
12887
12543
  minDeltaId,
12888
- maxDeltaId,
12889
- new BN14(0),
12890
- x0
12891
- );
12892
- const totalAmountX = amountInBins.reduce((acc, bin) => {
12893
- return acc.add(bin.amountX);
12894
- }, new BN14(0));
12895
- if (totalAmountX.lt(amountX)) {
12896
- x0 = x0.add(new BN14(1));
12544
+ maxDeltaId
12545
+ } of deposits) {
12546
+ const params = buildBitFlagAndNegateStrategyParameters(
12547
+ x0,
12548
+ y0,
12549
+ deltaX,
12550
+ deltaY
12551
+ );
12552
+ addLiquidityParam.push({
12553
+ minDeltaId: minDeltaId.toNumber(),
12554
+ maxDeltaId: maxDeltaId.toNumber(),
12555
+ x0: params.x0,
12556
+ y0: params.y0,
12557
+ deltaX: params.deltaX,
12558
+ deltaY: params.deltaY,
12559
+ bitFlag: params.bitFlag,
12560
+ padding: Array(16).fill(0),
12561
+ favorXInActiveId: favorXInActiveBin
12562
+ });
12563
+ const amountIntoBins = toAmountIntoBins(
12564
+ activeId,
12565
+ minDeltaId,
12566
+ maxDeltaId,
12567
+ deltaX,
12568
+ deltaY,
12569
+ x0,
12570
+ y0,
12571
+ binStep,
12572
+ favorXInActiveBin
12573
+ );
12574
+ for (const { binId, amountX, amountY } of amountIntoBins) {
12575
+ totalAmountXDeposited = totalAmountXDeposited.add(amountX);
12576
+ totalAmountYDeposited = totalAmountYDeposited.add(amountY);
12577
+ const idx = this.rebalancePositionBinData.findIndex(
12578
+ (data) => data.binId == binId.toNumber()
12579
+ );
12580
+ if (binId.eq(activeId)) {
12581
+ const vParameters3 = Object.assign({}, this.lbPair.vParameters);
12582
+ const sParameters3 = Object.assign({}, this.lbPair.parameters);
12583
+ DLMM.updateReference(
12584
+ activeId.toNumber(),
12585
+ vParameters3,
12586
+ sParameters3,
12587
+ this.currentTimestamp.toNumber()
12588
+ );
12589
+ DLMM.updateVolatilityAccumulator(
12590
+ vParameters3,
12591
+ sParameters3,
12592
+ activeId.toNumber()
12593
+ );
12594
+ const { amountXIntoBin, amountYIntoBin } = simulateDepositBin(
12595
+ binId,
12596
+ binStep,
12597
+ amountX,
12598
+ amountY,
12599
+ this.activeBin
12600
+ );
12601
+ const feeY = computeCompositionFee(
12602
+ binStep,
12603
+ sParameters3,
12604
+ vParameters3,
12605
+ amountXIntoBin,
12606
+ amountX,
12607
+ amountYIntoBin,
12608
+ amountY
12609
+ );
12610
+ const feeX = computeCompositionFee(
12611
+ binStep,
12612
+ sParameters3,
12613
+ vParameters3,
12614
+ amountYIntoBin,
12615
+ amountY,
12616
+ amountXIntoBin,
12617
+ amountX
12618
+ );
12619
+ const amountXIntoBinExcludeFee = amountXIntoBin.sub(feeX);
12620
+ const amountYIntoBinExcludeFee = amountYIntoBin.sub(feeY);
12621
+ this.rebalancePositionBinData[idx].amountX = this.rebalancePositionBinData[idx].amountX.add(
12622
+ amountXIntoBinExcludeFee
12623
+ );
12624
+ this.rebalancePositionBinData[idx].amountY = this.rebalancePositionBinData[idx].amountY.add(
12625
+ amountYIntoBinExcludeFee
12626
+ );
12627
+ } else {
12628
+ this.rebalancePositionBinData[idx].amountX = this.rebalancePositionBinData[idx].amountX.add(amountX);
12629
+ this.rebalancePositionBinData[idx].amountY = this.rebalancePositionBinData[idx].amountY.add(amountY);
12630
+ }
12631
+ }
12632
+ }
12633
+ let actualTotalAmountXDeposited = totalAmountXDeposited;
12634
+ let actualTotalAmountYDeposited = totalAmountYDeposited;
12635
+ let actualLiquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn;
12636
+ let actualLiquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn;
12637
+ if (actualTotalAmountXDeposited.gt(actualLiquidityAndFeeXWithdrawn)) {
12638
+ actualTotalAmountXDeposited = actualTotalAmountXDeposited.sub(
12639
+ actualLiquidityAndFeeXWithdrawn
12640
+ );
12641
+ actualLiquidityAndFeeXWithdrawn = new BN14(0);
12897
12642
  } else {
12898
- x0 = x0.sub(new BN14(1));
12899
- return x0;
12643
+ actualLiquidityAndFeeXWithdrawn = actualLiquidityAndFeeXWithdrawn.sub(
12644
+ actualTotalAmountXDeposited
12645
+ );
12646
+ actualTotalAmountXDeposited = new BN14(0);
12647
+ }
12648
+ if (actualTotalAmountYDeposited.gt(actualLiquidityAndFeeYWithdrawn)) {
12649
+ actualTotalAmountYDeposited = actualTotalAmountYDeposited.sub(
12650
+ actualLiquidityAndFeeYWithdrawn
12651
+ );
12652
+ actualLiquidityAndFeeYWithdrawn = new BN14(0);
12653
+ } else {
12654
+ actualLiquidityAndFeeYWithdrawn = actualLiquidityAndFeeYWithdrawn.sub(
12655
+ actualTotalAmountYDeposited
12656
+ );
12657
+ actualTotalAmountYDeposited = new BN14(0);
12900
12658
  }
12901
- }
12902
- }
12903
- var SpotStrategyParameterBuilder = class {
12904
- findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
12905
- return {
12906
- base: findX0(amountX, minDeltaId, maxDeltaId, binStep, activeId),
12907
- delta: new BN14(0)
12908
- };
12909
- }
12910
- findYParameters(amountY, minDeltaId, maxDeltaId, _activeId) {
12911
- return {
12912
- base: findY0(amountY, minDeltaId, maxDeltaId),
12913
- delta: new BN14(0)
12914
- };
12915
- }
12916
- suggestBalancedXParametersFromY(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountY) {
12917
- const x0 = amountY.div(maxDeltaId.addn(1));
12918
- const totalAmountX = toAmountIntoBins(
12919
- activeId,
12920
- minDeltaId,
12921
- maxDeltaId,
12922
- new BN14(0),
12923
- new BN14(0),
12924
- x0,
12925
- new BN14(0),
12926
- binStep,
12927
- favorXInActiveBin
12928
- ).reduce((acc, bin) => {
12929
- return acc.add(bin.amountX);
12930
- }, new BN14(0));
12931
- return {
12932
- base: new BN14(x0.toString()),
12933
- delta: new BN14(0),
12934
- amountX: totalAmountX
12935
- };
12936
- }
12937
- suggestBalancedYParametersFromX(activeId, binStep, favorXInActiveBin, minDeltaId, maxDeltaId, amountXInQuoteValue) {
12938
- const y0 = amountXInQuoteValue.div(maxDeltaId.sub(minDeltaId).addn(1));
12939
- const amountY = toAmountIntoBins(
12940
- activeId,
12941
- minDeltaId,
12942
- maxDeltaId,
12943
- new BN14(0),
12944
- new BN14(0),
12945
- new BN14(0),
12946
- y0,
12947
- binStep,
12948
- favorXInActiveBin
12949
- ).reduce((acc, bin) => {
12950
- return acc.add(bin.amountY);
12951
- }, new BN14(0));
12952
- return {
12953
- base: y0,
12954
- delta: new BN14(0),
12955
- amountY
12956
- };
12957
- }
12958
- };
12959
-
12960
- // src/dlmm/helpers/rebalance/liquidity_strategy/index.ts
12961
- import Decimal7 from "decimal.js";
12962
- function getLiquidityStrategyParameterBuilder(strategyType) {
12963
- switch (strategyType) {
12964
- case 0 /* Spot */:
12965
- return new SpotStrategyParameterBuilder();
12966
- case 1 /* Curve */:
12967
- return new CurveStrategyParameterBuilder();
12968
- case 2 /* BidAsk */:
12969
- return new BidAskStrategyParameterBuilder();
12970
- default:
12971
- throw new Error("Strategy not supported");
12972
- }
12973
- }
12974
- function suggestBalancedXParametersFromY(y0, deltaY, minDeltaId, maxDeltaId, activeId, binStep, favorXInActiveBin, builder) {
12975
- const endDeltaIdBidSide = favorXInActiveBin ? new BN15(-1) : new BN15(0);
12976
- if (maxDeltaId.lte(endDeltaIdBidSide)) {
12977
12659
  return {
12978
- base: new BN15(0),
12979
- delta: new BN15(0),
12980
- amountX: new BN15(0)
12660
+ result: {
12661
+ totalAmountXDeposited,
12662
+ totalAmountYDeposited,
12663
+ actualLiquidityAndFeeXWithdrawn,
12664
+ actualLiquidityAndFeeYWithdrawn,
12665
+ actualTotalAmountXDeposited,
12666
+ actualTotalAmountYDeposited
12667
+ },
12668
+ depositParams: addLiquidityParam
12981
12669
  };
12982
12670
  }
12983
- const minYDeltaId = minDeltaId;
12984
- const maxYDeltaId = endDeltaIdBidSide;
12985
- const totalAmountY = toAmountIntoBins(
12986
- activeId,
12987
- minYDeltaId,
12988
- maxYDeltaId,
12989
- new BN15(0),
12990
- deltaY,
12991
- new BN15(0),
12992
- y0,
12993
- binStep,
12994
- favorXInActiveBin
12995
- ).reduce((acc, bin) => {
12996
- return acc.add(bin.amountY);
12997
- }, new BN15(0));
12998
- const minXDeltaId = maxYDeltaId.addn(1);
12999
- const maxXDeltaId = maxDeltaId;
13000
- return builder.suggestBalancedXParametersFromY(
13001
- activeId,
13002
- binStep,
13003
- favorXInActiveBin,
13004
- minXDeltaId,
13005
- maxXDeltaId,
13006
- totalAmountY
13007
- );
13008
- }
13009
- function getAutoFillAmountByRebalancedPosition(rebalancePosition, strategyType) {
13010
- let liquidityInBidSide = new BN15(0);
13011
- let liquidityInAskSide = new BN15(0);
13012
- const builder = getLiquidityStrategyParameterBuilder(strategyType);
13013
- const { lbPair } = rebalancePosition;
13014
- let favorXInActiveBin = false;
13015
- let activeIdIndex = -1;
13016
- for (const [
13017
- idx,
13018
- binData
13019
- ] of rebalancePosition.rebalancePositionBinData.entries()) {
13020
- const liquidityBid = binData.amountY;
13021
- const liquidityAsk = new Decimal7(binData.price).mul(new Decimal7(binData.amountX.toString())).floor().toString();
13022
- liquidityInBidSide = liquidityInBidSide.add(liquidityBid);
13023
- liquidityInAskSide = liquidityInAskSide.add(new BN15(liquidityAsk));
13024
- if (binData.binId == lbPair.activeId) {
13025
- favorXInActiveBin = binData.amountX.gt(binData.amountY);
13026
- activeIdIndex = idx;
13027
- }
13028
- }
13029
- if (liquidityInAskSide.gt(liquidityInBidSide)) {
13030
- const minBinId = rebalancePosition.rebalancePositionBinData[0].binId;
13031
- let maxBinId;
13032
- if (activeIdIndex == -1) {
13033
- maxBinId = rebalancePosition.rebalancePositionBinData[rebalancePosition.rebalancePositionBinData.length - 1].binId;
12671
+ _simulateResize(depositMinBinId, depositMaxBinId, binStep, tokenXDecimal, tokenYDecimal) {
12672
+ const tokenXMultiplier = new Decimal6(10 ** tokenXDecimal.toNumber());
12673
+ const tokenYMultiplier = new Decimal6(10 ** tokenYDecimal.toNumber());
12674
+ const [minBinId, maxBinId] = findMinMaxBinIdWithLiquidity(
12675
+ this.rebalancePositionBinData
12676
+ );
12677
+ const newMinBinId = new BN14(
12678
+ Math.min(depositMinBinId.toNumber(), minBinId ?? Number.MAX_SAFE_INTEGER)
12679
+ );
12680
+ const newMaxBinId = new BN14(
12681
+ Math.max(depositMaxBinId.toNumber(), maxBinId ?? Number.MIN_SAFE_INTEGER)
12682
+ );
12683
+ if (newMinBinId.lt(this.lowerBinId)) {
12684
+ const binCountToExpand = this.lowerBinId.sub(depositMinBinId);
12685
+ for (let i = 1; i <= binCountToExpand.toNumber(); i++) {
12686
+ const binId = this.lowerBinId.subn(i);
12687
+ const price = getPriceOfBinByBinId(
12688
+ binId.toNumber(),
12689
+ binStep.toNumber()
12690
+ );
12691
+ const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);
12692
+ this.rebalancePositionBinData.unshift({
12693
+ binId: binId.toNumber(),
12694
+ price: adjustedPrice.toString(),
12695
+ pricePerToken: adjustedPrice.toString(),
12696
+ amountX: new BN14(0),
12697
+ amountY: new BN14(0),
12698
+ claimableRewardAmount: [new BN14(0), new BN14(0)],
12699
+ claimableFeeXAmount: new BN14(0),
12700
+ claimableFeeYAmount: new BN14(0)
12701
+ });
12702
+ }
13034
12703
  } else {
13035
- maxBinId = rebalancePosition.rebalancePositionBinData[favorXInActiveBin ? activeIdIndex - 1 : activeIdIndex].binId;
12704
+ const binCountToShrink = newMinBinId.sub(this.lowerBinId);
12705
+ for (let i = 1; i <= binCountToShrink.toNumber(); i++) {
12706
+ this.rebalancePositionBinData.shift();
12707
+ }
13036
12708
  }
13037
- const minDeltaId = minBinId - lbPair.activeId;
13038
- const maxDeltaId = maxBinId - lbPair.activeId;
13039
- const { amountY } = builder.suggestBalancedYParametersFromX(
13040
- new BN15(lbPair.activeId),
13041
- new BN15(lbPair.binStep),
13042
- favorXInActiveBin,
13043
- new BN15(minDeltaId),
13044
- new BN15(maxDeltaId),
13045
- liquidityInAskSide
13046
- );
13047
- const [_, positionAmountY] = rebalancePosition.totalAmounts();
13048
- return {
13049
- amount: BN15.max(amountY.sub(positionAmountY), new BN15(0)),
13050
- isBidSide: true
13051
- };
13052
- } else if (liquidityInAskSide.lt(liquidityInBidSide)) {
13053
- const maxBinId = rebalancePosition.rebalancePositionBinData[rebalancePosition.rebalancePositionBinData.length - 1].binId;
13054
- let minBinId;
13055
- if (activeIdIndex == -1) {
13056
- minBinId = rebalancePosition.rebalancePositionBinData[0].binId;
12709
+ if (newMaxBinId.gt(this.upperBinId)) {
12710
+ const binCountToExpand = newMaxBinId.sub(this.upperBinId);
12711
+ for (let i = 1; i <= binCountToExpand.toNumber(); i++) {
12712
+ const binId = this.upperBinId.addn(i);
12713
+ const price = getPriceOfBinByBinId(
12714
+ binId.toNumber(),
12715
+ binStep.toNumber()
12716
+ );
12717
+ const adjustedPrice = price.mul(tokenXMultiplier).div(tokenYMultiplier);
12718
+ this.rebalancePositionBinData.push({
12719
+ binId: binId.toNumber(),
12720
+ price: adjustedPrice.toString(),
12721
+ pricePerToken: adjustedPrice.toString(),
12722
+ amountX: new BN14(0),
12723
+ amountY: new BN14(0),
12724
+ claimableRewardAmount: [new BN14(0), new BN14(0)],
12725
+ claimableFeeXAmount: new BN14(0),
12726
+ claimableFeeYAmount: new BN14(0)
12727
+ });
12728
+ }
13057
12729
  } else {
13058
- minBinId = rebalancePosition.rebalancePositionBinData[favorXInActiveBin ? activeIdIndex - 1 : activeIdIndex].binId;
12730
+ const binCountToShrink = this.upperBinId.sub(newMaxBinId);
12731
+ for (let i = 1; i <= binCountToShrink.toNumber(); i++) {
12732
+ this.rebalancePositionBinData.pop();
12733
+ }
13059
12734
  }
13060
- const minDeltaId = minBinId - lbPair.activeId;
13061
- const maxDeltaId = maxBinId - lbPair.activeId;
13062
- const { amountX } = builder.suggestBalancedXParametersFromY(
13063
- new BN15(lbPair.activeId),
13064
- new BN15(lbPair.binStep),
13065
- favorXInActiveBin,
13066
- new BN15(minDeltaId),
13067
- new BN15(maxDeltaId),
13068
- liquidityInBidSide
13069
- );
13070
- const [positionAmountX] = rebalancePosition.totalAmounts();
13071
- return {
13072
- amount: BN15.max(amountX.sub(positionAmountX), new BN15(0)),
13073
- isBidSide: false
13074
- };
13075
- } else {
13076
- return {
13077
- amount: new BN15(0),
13078
- isBidSide: false
13079
- };
13080
- }
13081
- }
13082
- function suggestBalancedYParametersFromX(x0, deltaX, minDeltaId, maxDeltaId, activeId, binStep, favorXInActiveBin, builder) {
13083
- const startDeltaIdAskSide = favorXInActiveBin ? new BN15(0) : new BN15(1);
13084
- if (minDeltaId.gte(startDeltaIdAskSide)) {
13085
- return {
13086
- base: new BN15(0),
13087
- delta: new BN15(0),
13088
- amountY: new BN15(0)
13089
- };
12735
+ this.lowerBinId = newMinBinId;
12736
+ this.upperBinId = newMaxBinId;
13090
12737
  }
13091
- const minXDeltaId = startDeltaIdAskSide;
13092
- const maxXDeltaId = maxDeltaId;
13093
- const amountXInBins = toAmountIntoBins(
13094
- activeId,
13095
- minXDeltaId,
13096
- maxXDeltaId,
13097
- deltaX,
13098
- new BN15(0),
13099
- x0,
13100
- new BN15(0),
13101
- binStep,
13102
- favorXInActiveBin
13103
- );
13104
- const totalAmountXInQuote = amountXInBins.reduce((acc, bin) => {
13105
- const price = getPriceOfBinByBinId(
13106
- bin.binId.toNumber(),
13107
- binStep.toNumber()
12738
+ _simulateWithdraw(withdraws) {
12739
+ let liquidityAndFeeXWithdrawn = new BN14(0);
12740
+ let liquidityAndFeeYWithdrawn = new BN14(0);
12741
+ let rewardsAmountClaimed = [new BN14(0), new BN14(0)];
12742
+ const activeId = new BN14(this.lbPair.activeId);
12743
+ for (const { minBinId, maxBinId, bps } of withdraws) {
12744
+ const fromBinId = minBinId ?? activeId;
12745
+ const toBinId = maxBinId ?? activeId;
12746
+ const binIds = binRangeToBinIdArray(fromBinId, toBinId).filter(
12747
+ (binId) => binId.gte(this.lowerBinId) && binId.lte(this.upperBinId)
12748
+ );
12749
+ for (const binId of binIds) {
12750
+ const idx = this.rebalancePositionBinData.findIndex(
12751
+ (b) => b.binId === binId.toNumber()
12752
+ );
12753
+ const binData = this.rebalancePositionBinData[idx];
12754
+ const amountXWithdrawn = binData.amountX.mul(bps).divn(BASIS_POINT_MAX);
12755
+ const amountYWithdrawn = binData.amountY.mul(bps).divn(BASIS_POINT_MAX);
12756
+ liquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn.add(amountXWithdrawn);
12757
+ liquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn.add(amountYWithdrawn);
12758
+ binData.amountX = binData.amountX.sub(amountXWithdrawn);
12759
+ binData.amountY = binData.amountY.sub(amountYWithdrawn);
12760
+ if (this.shouldClaimFee) {
12761
+ liquidityAndFeeXWithdrawn = liquidityAndFeeXWithdrawn.add(
12762
+ binData.claimableFeeXAmount
12763
+ );
12764
+ liquidityAndFeeYWithdrawn = liquidityAndFeeYWithdrawn.add(
12765
+ binData.claimableFeeYAmount
12766
+ );
12767
+ binData.claimableFeeXAmount = new BN14(0);
12768
+ binData.claimableFeeYAmount = new BN14(0);
12769
+ }
12770
+ if (this.shouldClaimReward) {
12771
+ for (const [idx2, amount] of binData.claimableRewardAmount.entries()) {
12772
+ rewardsAmountClaimed[idx2] = rewardsAmountClaimed[idx2].add(amount);
12773
+ binData.claimableRewardAmount[idx2] = new BN14(0);
12774
+ }
12775
+ }
12776
+ this.rebalancePositionBinData[idx] = binData;
12777
+ }
12778
+ }
12779
+ const withdrawParams = withdraws.map(
12780
+ ({ minBinId, maxBinId, bps }) => {
12781
+ return {
12782
+ minBinId: minBinId ? minBinId.toNumber() : null,
12783
+ maxBinId: maxBinId ? maxBinId.toNumber() : null,
12784
+ bps: bps.toNumber(),
12785
+ padding: Array(16).fill(0)
12786
+ };
12787
+ }
13108
12788
  );
13109
- return acc.add(price.mul(new Decimal7(bin.amountX.toString())));
13110
- }, new Decimal7(0));
13111
- const totalAmountXInQuoteBN = new BN15(totalAmountXInQuote.floor().toString());
13112
- const minYDeltaId = minDeltaId;
13113
- const maxYDeltaId = startDeltaIdAskSide.subn(1);
13114
- return builder.suggestBalancedYParametersFromX(
13115
- activeId,
13116
- binStep,
13117
- favorXInActiveBin,
13118
- minYDeltaId,
13119
- maxYDeltaId,
13120
- totalAmountXInQuoteBN
13121
- );
13122
- }
13123
- function buildLiquidityStrategyParameters(amountX, amountY, minDeltaId, maxDeltaId, binStep, favorXInActiveId, activeId, strategyParameterBuilder) {
13124
- if (minDeltaId.gt(maxDeltaId)) {
13125
12789
  return {
13126
- x0: new BN15(0),
13127
- y0: new BN15(0),
13128
- deltaX: new BN15(0),
13129
- deltaY: new BN15(0)
12790
+ result: {
12791
+ liquidityAndFeeXWithdrawn,
12792
+ liquidityAndFeeYWithdrawn,
12793
+ rewardsAmountClaimed
12794
+ },
12795
+ withdrawParams
13130
12796
  };
13131
12797
  }
13132
- const depositOnlyY = maxDeltaId.lt(new BN15(0)) || maxDeltaId.isZero() && !favorXInActiveId;
13133
- const depositOnlyX = minDeltaId.gt(new BN15(0)) || minDeltaId.isZero() && favorXInActiveId;
13134
- if (depositOnlyY) {
13135
- const { base, delta } = strategyParameterBuilder.findYParameters(
13136
- amountY,
13137
- minDeltaId,
13138
- maxDeltaId,
13139
- activeId
12798
+ async simulateRebalance(connection, binStep, tokenXDecimal, tokenYDecimal, withdraws, deposits) {
12799
+ if (withdraws.length == 0 && deposits.length == 0) {
12800
+ throw "No rebalance action";
12801
+ }
12802
+ const activeId = new BN14(this.lbPair.activeId);
12803
+ withdraws = validateAndSortRebalanceWithdraw(withdraws, activeId);
12804
+ deposits = validateAndSortRebalanceDeposit(deposits);
12805
+ const beforeWidth = getPositionWidthWithMinWidth(
12806
+ this.lowerBinId.toNumber(),
12807
+ this.upperBinId.toNumber()
12808
+ );
12809
+ const { withdrawParams, result: withdrawResult } = this._simulateWithdraw(withdraws);
12810
+ const { depositParams, result: depositResult } = this._simulateDeposit(
12811
+ binStep,
12812
+ tokenXDecimal,
12813
+ tokenYDecimal,
12814
+ deposits,
12815
+ withdrawResult
12816
+ );
12817
+ const afterWidth = getPositionWidthWithMinWidth(
12818
+ this.lowerBinId.toNumber(),
12819
+ this.upperBinId.toNumber()
13140
12820
  );
12821
+ const widthDelta = afterWidth - beforeWidth;
12822
+ let rentalCostLamports = new BN14(0);
12823
+ if (widthDelta != 0) {
12824
+ const sizeChanges = Math.abs(widthDelta) * POSITION_BIN_DATA_SIZE;
12825
+ const [minimumLamports, rentExemptionLamports] = await Promise.all([
12826
+ connection.getMinimumBalanceForRentExemption(0),
12827
+ connection.getMinimumBalanceForRentExemption(sizeChanges)
12828
+ ]);
12829
+ const lamportChanges = new BN14(rentExemptionLamports).sub(
12830
+ new BN14(minimumLamports)
12831
+ );
12832
+ if (widthDelta > 0) {
12833
+ rentalCostLamports = rentalCostLamports.add(lamportChanges);
12834
+ } else {
12835
+ rentalCostLamports = rentalCostLamports.sub(lamportChanges);
12836
+ }
12837
+ }
13141
12838
  return {
13142
- x0: new BN15(0),
13143
- deltaX: new BN15(0),
13144
- y0: base,
13145
- deltaY: delta
12839
+ amountXDeposited: depositResult.totalAmountXDeposited,
12840
+ amountYDeposited: depositResult.totalAmountYDeposited,
12841
+ actualAmountXDeposited: depositResult.actualTotalAmountXDeposited,
12842
+ actualAmountYDeposited: depositResult.actualTotalAmountYDeposited,
12843
+ actualAmountXWithdrawn: depositResult.actualLiquidityAndFeeXWithdrawn,
12844
+ actualAmountYWithdrawn: depositResult.actualLiquidityAndFeeYWithdrawn,
12845
+ rewardAmountsClaimed: withdrawResult.rewardsAmountClaimed,
12846
+ withdrawParams,
12847
+ depositParams,
12848
+ rentalCostLamports
13146
12849
  };
13147
12850
  }
13148
- if (depositOnlyX) {
13149
- const { base, delta } = strategyParameterBuilder.findXParameters(
13150
- amountX,
13151
- minDeltaId,
13152
- maxDeltaId,
13153
- binStep,
13154
- activeId
13155
- );
13156
- return {
13157
- x0: base,
13158
- deltaX: delta,
13159
- y0: new BN15(0),
13160
- deltaY: new BN15(0)
13161
- };
12851
+ totalAmounts() {
12852
+ let totalAmountX = new BN14(0);
12853
+ let totalAmountY = new BN14(0);
12854
+ for (const binData of this.rebalancePositionBinData) {
12855
+ totalAmountX = totalAmountX.add(binData.amountX);
12856
+ totalAmountY = totalAmountY.add(binData.amountY);
12857
+ }
12858
+ return [totalAmountX, totalAmountY];
13162
12859
  }
13163
- const maxDeltaIdBidSide = favorXInActiveId ? new BN15(-1) : new BN15(0);
13164
- const minDeltaIdAskSide = favorXInActiveId ? new BN15(0) : new BN15(1);
13165
- const { base: y0, delta: deltaY } = strategyParameterBuilder.findYParameters(
13166
- amountY,
13167
- minDeltaId,
13168
- maxDeltaIdBidSide,
13169
- activeId
13170
- );
13171
- const { base: x0, delta: deltaX } = strategyParameterBuilder.findXParameters(
13172
- amountX,
13173
- minDeltaIdAskSide,
13174
- maxDeltaId,
13175
- binStep,
13176
- activeId
13177
- );
13178
- return {
13179
- x0,
13180
- deltaX,
13181
- y0,
13182
- deltaY
13183
- };
13184
- }
13185
-
13186
- // src/dlmm/helpers/index.ts
13187
- function chunks(array, size) {
13188
- return Array.apply(0, new Array(Math.ceil(array.length / size))).map(
13189
- (_, index) => array.slice(index * size, (index + 1) * size)
13190
- );
13191
- }
13192
- function range(min, max, mapfn) {
13193
- const length = max - min + 1;
13194
- return Array.from({ length }, (_, i) => mapfn(min + i));
13195
- }
13196
- async function chunkedFetchMultiplePoolAccount(program, pks, chunkSize = 100) {
13197
- const accounts = (await Promise.all(
13198
- chunks(pks, chunkSize).map(
13199
- (chunk) => program.account.lbPair.fetchMultiple(chunk)
13200
- )
13201
- )).flat();
13202
- return accounts.filter(Boolean);
13203
- }
13204
- async function chunkedFetchMultipleBinArrayBitmapExtensionAccount(program, pks, chunkSize = 100) {
13205
- const accounts = (await Promise.all(
13206
- chunks(pks, chunkSize).map(
13207
- (chunk) => program.account.binArrayBitmapExtension.fetchMultiple(chunk)
13208
- )
13209
- )).flat();
13210
- return accounts;
13211
- }
13212
- function getOutAmount(bin, inAmount, swapForY) {
13213
- return swapForY ? mulShr(inAmount, bin.price, SCALE_OFFSET, 1 /* Down */) : shlDiv(inAmount, bin.price, SCALE_OFFSET, 1 /* Down */);
13214
- }
13215
- async function getTokenDecimals(conn, mint) {
13216
- const token = await getMint(conn, mint);
13217
- return await token.decimals;
13218
- }
13219
- var getOrCreateATAInstruction = async (connection, tokenMint, owner, programId, payer = owner, allowOwnerOffCurve = true) => {
13220
- programId = programId ?? TOKEN_PROGRAM_ID3;
13221
- const toAccount = getAssociatedTokenAddressSync(
13222
- tokenMint,
13223
- owner,
13224
- allowOwnerOffCurve,
13225
- programId,
13226
- ASSOCIATED_TOKEN_PROGRAM_ID
13227
- );
13228
- try {
13229
- await getAccount(connection, toAccount, connection.commitment, programId);
13230
- return { ataPubKey: toAccount, ix: void 0 };
13231
- } catch (e) {
13232
- if (e instanceof TokenAccountNotFoundError || e instanceof TokenInvalidAccountOwnerError) {
13233
- const ix = createAssociatedTokenAccountIdempotentInstruction(
13234
- payer,
13235
- toAccount,
13236
- owner,
13237
- tokenMint,
13238
- programId,
13239
- ASSOCIATED_TOKEN_PROGRAM_ID
12860
+ totalFeeAmounts() {
12861
+ let totalFeeXAmount = new BN14(0);
12862
+ let totalFeeYAmount = new BN14(0);
12863
+ for (const binData of this.rebalancePositionBinData) {
12864
+ totalFeeXAmount = totalFeeXAmount.add(binData.claimableFeeXAmount);
12865
+ totalFeeYAmount = totalFeeYAmount.add(binData.claimableFeeYAmount);
12866
+ }
12867
+ return [totalFeeXAmount, totalFeeYAmount];
12868
+ }
12869
+ totalRewardAmounts() {
12870
+ let totalRewardAmounts = [new BN14(0), new BN14(0)];
12871
+ for (const binData of this.rebalancePositionBinData) {
12872
+ totalRewardAmounts[0] = totalRewardAmounts[0].add(
12873
+ binData.claimableRewardAmount[0]
12874
+ );
12875
+ totalRewardAmounts[1] = totalRewardAmounts[1].add(
12876
+ binData.claimableRewardAmount[1]
13240
12877
  );
13241
- return { ataPubKey: toAccount, ix };
13242
- } else {
13243
- console.error("Error::getOrCreateATAInstruction", e);
13244
- throw e;
13245
12878
  }
12879
+ return totalRewardAmounts;
13246
12880
  }
13247
12881
  };
13248
- async function getTokenBalance(conn, tokenAccount) {
13249
- const acc = await getAccount(conn, tokenAccount);
13250
- return acc.amount;
12882
+ function getPositionWidthWithMinWidth(lowerBinId, upperBinId) {
12883
+ const width = upperBinId - lowerBinId + 1;
12884
+ return Math.max(width, DEFAULT_BIN_PER_POSITION.toNumber());
13251
12885
  }
13252
- var parseLogs = (eventParser, logs) => {
13253
- if (!logs.length)
13254
- throw new Error("No logs found");
13255
- for (const event of eventParser?.parseLogs(logs)) {
13256
- return event.data;
13257
- }
13258
- throw new Error("No events found");
13259
- };
13260
- var wrapSOLInstruction = (from, to, amount) => {
13261
- return [
13262
- SystemProgram.transfer({
13263
- fromPubkey: from,
13264
- toPubkey: to,
13265
- lamports: amount
13266
- }),
13267
- new TransactionInstruction3({
13268
- keys: [
13269
- {
13270
- pubkey: to,
13271
- isSigner: false,
13272
- isWritable: true
13273
- }
13274
- ],
13275
- data: Buffer.from(new Uint8Array([17])),
13276
- programId: TOKEN_PROGRAM_ID3
13277
- })
13278
- ];
13279
- };
13280
- var unwrapSOLInstruction = async (owner, allowOwnerOffCurve = true) => {
13281
- const wSolATAAccount = getAssociatedTokenAddressSync(
13282
- NATIVE_MINT,
13283
- owner,
13284
- allowOwnerOffCurve
12886
+ function validateAndSortRebalanceDeposit(deposits) {
12887
+ const sortedDeposits = deposits.sort(
12888
+ (a, b) => a.minDeltaId.sub(b.minDeltaId).toNumber()
13285
12889
  );
13286
- if (wSolATAAccount) {
13287
- const closedWrappedSolInstruction = createCloseAccountInstruction(
13288
- wSolATAAccount,
13289
- owner,
13290
- owner,
13291
- [],
13292
- TOKEN_PROGRAM_ID3
13293
- );
13294
- return closedWrappedSolInstruction;
13295
- }
13296
- return null;
13297
- };
13298
- async function chunkedGetMultipleAccountInfos(connection, pks, chunkSize = 100) {
13299
- const accountInfos = (await Promise.all(
13300
- chunks(pks, chunkSize).map(
13301
- (chunk) => connection.getMultipleAccountsInfo(chunk)
13302
- )
13303
- )).flat();
13304
- return accountInfos;
13305
- }
13306
- var getEstimatedComputeUnitUsageWithBuffer = async (connection, instructions, feePayer, buffer) => {
13307
- if (!buffer) {
13308
- buffer = 0.1;
12890
+ for (const deposit of deposits) {
12891
+ if (deposit.minDeltaId.gte(deposit.maxDeltaId)) {
12892
+ throw "Invalid minDeltaId or maxDeltaId";
12893
+ }
13309
12894
  }
13310
- buffer = Math.max(0, buffer);
13311
- buffer = Math.min(1, buffer);
13312
- const estimatedComputeUnitUsage = await getSimulationComputeUnits(
13313
- connection,
13314
- instructions,
13315
- feePayer,
13316
- []
13317
- );
13318
- let extraComputeUnitBuffer = estimatedComputeUnitUsage * buffer;
13319
- if (extraComputeUnitBuffer > MAX_CU_BUFFER) {
13320
- extraComputeUnitBuffer = MAX_CU_BUFFER;
13321
- } else if (extraComputeUnitBuffer < MIN_CU_BUFFER) {
13322
- extraComputeUnitBuffer = MIN_CU_BUFFER;
12895
+ for (let i = 1; i < sortedDeposits.length; i++) {
12896
+ const prevDeposit = sortedDeposits[i - 1];
12897
+ const currDeposit = sortedDeposits[i];
12898
+ if (prevDeposit.maxDeltaId.gte(currDeposit.minDeltaId)) {
12899
+ throw "Overlap deposit bin range";
12900
+ }
13323
12901
  }
13324
- return estimatedComputeUnitUsage + extraComputeUnitBuffer;
13325
- };
13326
- var getEstimatedComputeUnitIxWithBuffer = async (connection, instructions, feePayer, buffer) => {
13327
- const units = await getEstimatedComputeUnitUsageWithBuffer(
13328
- connection,
13329
- instructions,
13330
- feePayer,
13331
- buffer
13332
- ).catch((error) => {
13333
- console.error("Error::getEstimatedComputeUnitUsageWithBuffer", error);
13334
- return 14e5;
13335
- });
13336
- return ComputeBudgetProgram2.setComputeUnitLimit({ units });
13337
- };
13338
- function createProgram(connection, opt) {
13339
- const cluster = opt?.cluster || "mainnet-beta";
13340
- const provider = new AnchorProvider(
13341
- connection,
13342
- {},
13343
- AnchorProvider.defaultOptions()
13344
- );
13345
- return new Program2(
13346
- { ...dlmm_default, address: LBCLMM_PROGRAM_IDS[cluster] },
13347
- provider
13348
- );
13349
- }
13350
- function decodeAccount(program, accountName, buffer) {
13351
- return program.coder.accounts.decode(accountName, buffer);
13352
- }
13353
- function getAccountDiscriminator(accountName) {
13354
- return dlmm_default.accounts.find(
13355
- (acc) => acc.name.toLowerCase() === accountName.toLowerCase()
13356
- )?.discriminator;
12902
+ return sortedDeposits;
13357
12903
  }
13358
- function capSlippagePercentage(slippage) {
13359
- if (slippage > 100) {
13360
- slippage = 100;
12904
+ function validateAndSortRebalanceWithdraw(withdraws, activeId) {
12905
+ const filledWithdraws = [];
12906
+ for (const { minBinId, maxBinId, bps } of withdraws) {
12907
+ if (bps.toNumber() < 0 || bps.toNumber() > BASIS_POINT_MAX) {
12908
+ throw "Invalid bps";
12909
+ }
12910
+ const filledMinBinId = minBinId ?? activeId;
12911
+ const filledMaxBinId = maxBinId ?? activeId;
12912
+ if (filledMinBinId.gt(filledMaxBinId)) {
12913
+ throw "Invalid minBinId or maxBinId";
12914
+ }
12915
+ filledWithdraws.push({
12916
+ minBinId: filledMinBinId,
12917
+ maxBinId: filledMaxBinId,
12918
+ bps
12919
+ });
13361
12920
  }
13362
- if (slippage < 0) {
13363
- slippage = 0;
12921
+ filledWithdraws.sort((a, b) => {
12922
+ return a.minBinId.sub(b.minBinId).toNumber();
12923
+ });
12924
+ for (let i = 1; i < filledWithdraws.length; i++) {
12925
+ const prev = filledWithdraws[i - 1];
12926
+ const curr = filledWithdraws[i];
12927
+ if (curr.minBinId.lte(prev.maxBinId)) {
12928
+ throw "Overlap withdraw bin range";
12929
+ }
13364
12930
  }
13365
- return slippage;
12931
+ return filledWithdraws;
13366
12932
  }
13367
-
13368
- // src/dlmm/helpers/accountFilters.ts
13369
- import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes";
13370
- var presetParameter2BinStepFilter = (binStep) => {
13371
- return {
13372
- memcmp: {
13373
- bytes: bs58.encode(binStep.toArrayLike(Buffer, "le", 2)),
13374
- offset: 8
13375
- }
13376
- };
13377
- };
13378
- var presetParameter2BaseFactorFilter = (baseFactor) => {
13379
- return {
13380
- memcmp: {
13381
- bytes: bs58.encode(baseFactor.toArrayLike(Buffer, "le", 2)),
13382
- offset: 8 + 2
13383
- }
13384
- };
13385
- };
13386
- var presetParameter2BaseFeePowerFactor = (baseFeePowerFactor) => {
13387
- return {
13388
- memcmp: {
13389
- bytes: bs58.encode(baseFeePowerFactor.toArrayLike(Buffer, "le", 1)),
13390
- offset: 8 + 22
12933
+ function binRangeToBinIdArray(minBinId, maxBinId) {
12934
+ const binIdArray = [];
12935
+ const fromBinId = minBinId.toNumber();
12936
+ const toBinId = maxBinId.toNumber();
12937
+ for (let binId = fromBinId; binId <= toBinId; binId++) {
12938
+ binIdArray.push(new BN14(binId));
12939
+ }
12940
+ return binIdArray;
12941
+ }
12942
+ function getRebalanceBinArrayIndexesAndBitmapCoverage(adds, removes, activeId, pairAddress, programId) {
12943
+ let indexMap = /* @__PURE__ */ new Map();
12944
+ removes.forEach((value) => {
12945
+ let minBinId = value.minBinId;
12946
+ if (minBinId == null) {
12947
+ minBinId = activeId;
13391
12948
  }
13392
- };
13393
- };
13394
- var binArrayLbPairFilter = (lbPair) => {
13395
- return {
13396
- memcmp: {
13397
- bytes: lbPair.toBase58(),
13398
- offset: 8 + 16
12949
+ let maxBinId = value.maxBinId;
12950
+ if (maxBinId == null) {
12951
+ maxBinId = activeId;
13399
12952
  }
13400
- };
13401
- };
13402
- var positionOwnerFilter = (owner) => {
13403
- return {
13404
- memcmp: {
13405
- bytes: owner.toBase58(),
13406
- offset: 8 + 32
12953
+ let binArrayIndex = binIdToBinArrayIndex(new BN14(minBinId));
12954
+ const upperBinId = new BN14(maxBinId);
12955
+ while (true) {
12956
+ indexMap.set(binArrayIndex.toNumber(), true);
12957
+ const [binArrayLowerBinId, binArrayUpperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
12958
+ if (upperBinId.gte(binArrayLowerBinId) && upperBinId.lte(binArrayUpperBinId)) {
12959
+ break;
12960
+ } else {
12961
+ binArrayIndex = binArrayIndex.add(new BN14(1));
12962
+ }
13407
12963
  }
13408
- };
13409
- };
13410
- var positionLbPairFilter = (lbPair) => {
13411
- return {
13412
- memcmp: {
13413
- bytes: bs58.encode(lbPair.toBuffer()),
13414
- offset: 8
12964
+ });
12965
+ adds.forEach((value) => {
12966
+ const minBinId = activeId + value.minDeltaId;
12967
+ const maxBinId = activeId + value.maxDeltaId;
12968
+ let binArrayIndex = binIdToBinArrayIndex(new BN14(minBinId));
12969
+ const upperBinId = new BN14(maxBinId);
12970
+ while (true) {
12971
+ indexMap.set(binArrayIndex.toNumber(), true);
12972
+ const [binArrayLowerBinId, binArrayUpperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
12973
+ if (upperBinId.gte(binArrayLowerBinId) && upperBinId.lte(binArrayUpperBinId)) {
12974
+ break;
12975
+ } else {
12976
+ binArrayIndex = binArrayIndex.add(new BN14(1));
12977
+ }
13415
12978
  }
13416
- };
13417
- };
13418
- var positionV2Filter = () => {
12979
+ });
12980
+ const binArrayIndexes = Array.from(indexMap.keys()).map((idx) => new BN14(idx));
12981
+ const requireBitmapExtension = binArrayIndexes.some(
12982
+ (index) => isOverflowDefaultBinArrayBitmap(new BN14(index))
12983
+ );
13419
12984
  return {
13420
- memcmp: {
13421
- bytes: bs58.encode(Buffer.from(getAccountDiscriminator("positionV2"))),
13422
- offset: 0
13423
- }
12985
+ binArrayIndexes,
12986
+ binArrayBitmap: requireBitmapExtension ? deriveBinArrayBitmapExtension(pairAddress, programId)[0] : programId
13424
12987
  };
13425
- };
12988
+ }
13426
12989
 
13427
- // src/dlmm/helpers/positions/index.ts
12990
+ // src/dlmm/helpers/rebalance/liquidity_strategy/index.ts
13428
12991
  import BN18 from "bn.js";
13429
12992
 
13430
- // src/dlmm/helpers/positions/wrapper.ts
13431
- import BN17 from "bn.js";
13432
- function combineBaseAndExtendedPositionBinData(base, extended) {
13433
- const combinedLiquidityShares = base.liquidityShares;
13434
- const combinedRewardInfos = base.rewardInfos;
13435
- const combinedFeeInfos = base.feeInfos;
13436
- for (const binData of extended) {
13437
- combinedLiquidityShares.push(binData.liquidityShare);
13438
- combinedRewardInfos.push(binData.rewardInfo);
13439
- combinedFeeInfos.push(binData.feeInfo);
12993
+ // src/dlmm/helpers/rebalance/liquidity_strategy/bidAsk.ts
12994
+ import BN15 from "bn.js";
12995
+ function findMinY0(amountY, minDeltaId, maxDeltaId) {
12996
+ const binCount = maxDeltaId.sub(minDeltaId).addn(1);
12997
+ const totalWeight = binCount.mul(binCount.addn(1)).divn(2);
12998
+ return amountY.div(totalWeight);
12999
+ }
13000
+ function findBaseDeltaY(amountY, minDeltaId, maxDeltaId, minY0) {
13001
+ if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN15(0))) {
13002
+ return new BN15(0);
13440
13003
  }
13441
- return {
13442
- liquidityShares: combinedLiquidityShares,
13443
- rewardInfos: combinedRewardInfos,
13444
- feeInfos: combinedFeeInfos
13445
- };
13004
+ if (minDeltaId.eq(maxDeltaId)) {
13005
+ return amountY;
13006
+ }
13007
+ const m1 = minDeltaId.neg();
13008
+ const m2 = maxDeltaId.neg();
13009
+ const b = m2.neg().mul(m1.sub(m2).addn(1));
13010
+ const c = m1.mul(m1.addn(1)).divn(2);
13011
+ const d = m2.mul(m2.subn(1)).divn(2);
13012
+ const a = b.add(c.sub(d));
13013
+ const e = minY0;
13014
+ return amountY.sub(e).div(a);
13446
13015
  }
13447
- function wrapPosition(program, key, account) {
13448
- const disc = account.data.subarray(0, 8);
13449
- if (disc.equals(Buffer.from(getAccountDiscriminator("positionV2")))) {
13450
- const state = decodeAccount(
13451
- program,
13452
- "positionV2",
13453
- account.data
13454
- );
13455
- const extended = decodeExtendedPosition(
13456
- state,
13457
- program,
13458
- account.data.subarray(8 + POSITION_MIN_SIZE)
13459
- );
13460
- const combinedPositionBinData = combineBaseAndExtendedPositionBinData(
13461
- state,
13462
- extended
13016
+ function findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId) {
13017
+ if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {
13018
+ return {
13019
+ base: new BN15(0),
13020
+ delta: new BN15(0)
13021
+ };
13022
+ }
13023
+ const minY0 = findMinY0(amountY, minDeltaId, maxDeltaId);
13024
+ let baseDeltaY = findBaseDeltaY(amountY, minDeltaId, maxDeltaId, minY0);
13025
+ const y0 = baseDeltaY.neg().mul(maxDeltaId).add(minY0);
13026
+ while (true) {
13027
+ const amountInBins = getAmountInBinsBidSide(
13028
+ activeId,
13029
+ minDeltaId,
13030
+ maxDeltaId,
13031
+ baseDeltaY,
13032
+ y0
13463
13033
  );
13464
- return new PositionV2Wrapper(key, state, extended, combinedPositionBinData);
13465
- } else {
13466
- throw new Error("Unknown position account");
13034
+ const totalAmountY = amountInBins.reduce((acc, { amountY: amountY2 }) => {
13035
+ return acc.add(amountY2);
13036
+ }, new BN15(0));
13037
+ if (totalAmountY.gt(amountY)) {
13038
+ baseDeltaY = baseDeltaY.sub(new BN15(1));
13039
+ } else {
13040
+ return {
13041
+ base: y0,
13042
+ delta: baseDeltaY
13043
+ };
13044
+ }
13467
13045
  }
13468
13046
  }
13469
- var PositionV2Wrapper = class {
13470
- constructor(positionAddress, inner, extended, combinedPositionBinData) {
13471
- this.positionAddress = positionAddress;
13472
- this.inner = inner;
13473
- this.extended = extended;
13474
- this.combinedPositionBinData = combinedPositionBinData;
13475
- }
13476
- address() {
13477
- return this.positionAddress;
13047
+ function findMinX0(amountX, minDeltaId, maxDeltaId, activeId, binStep) {
13048
+ const minBinId = activeId.add(minDeltaId);
13049
+ const maxBinId = activeId.add(maxDeltaId);
13050
+ let totalWeight = new BN15(0);
13051
+ for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
13052
+ const binDelta = binId - minBinId.toNumber() + 1;
13053
+ const binPrice = getQPriceFromId(new BN15(binId), binStep);
13054
+ const weight = new BN15(binDelta).mul(binPrice);
13055
+ totalWeight = totalWeight.add(weight);
13478
13056
  }
13479
- totalClaimedRewards() {
13480
- return this.inner.totalClaimedRewards;
13057
+ return amountX.shln(SCALE_OFFSET).div(totalWeight);
13058
+ }
13059
+ function findBaseDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId, minX0) {
13060
+ if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN15(0))) {
13061
+ return new BN15(0);
13481
13062
  }
13482
- feeOwner() {
13483
- return this.inner.feeOwner;
13063
+ let b = new BN15(0);
13064
+ let c = new BN15(0);
13065
+ let m1 = minDeltaId;
13066
+ let m2 = maxDeltaId;
13067
+ for (let m = m1.toNumber(); m <= m2.toNumber(); m++) {
13068
+ const binId = activeId.addn(m);
13069
+ const pm = getQPriceFromId(binId.neg(), binStep);
13070
+ const bDelta = m1.mul(pm);
13071
+ b = b.add(bDelta);
13072
+ const cDelta = new BN15(m).mul(pm);
13073
+ c = c.add(cDelta);
13484
13074
  }
13485
- lockReleasePoint() {
13486
- return this.inner.lockReleasePoint;
13075
+ return amountX.sub(minX0).shln(SCALE_OFFSET).div(c.sub(b));
13076
+ }
13077
+ function findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13078
+ if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN15(0)) || amountX.isZero()) {
13079
+ return {
13080
+ base: new BN15(0),
13081
+ delta: new BN15(0)
13082
+ };
13487
13083
  }
13488
- operator() {
13489
- return this.inner.operator;
13084
+ const minX0 = findMinX0(amountX, minDeltaId, maxDeltaId, activeId, binStep);
13085
+ let baseDeltaX = findBaseDeltaX(
13086
+ amountX,
13087
+ minDeltaId,
13088
+ maxDeltaId,
13089
+ binStep,
13090
+ activeId,
13091
+ minX0
13092
+ );
13093
+ const x0 = minDeltaId.neg().mul(baseDeltaX).add(minX0);
13094
+ while (true) {
13095
+ const amountInBins = getAmountInBinsAskSide(
13096
+ activeId,
13097
+ binStep,
13098
+ minDeltaId,
13099
+ maxDeltaId,
13100
+ baseDeltaX,
13101
+ x0
13102
+ );
13103
+ const totalAmountX = amountInBins.reduce((acc, { amountX: amountX2 }) => {
13104
+ return acc.add(amountX2);
13105
+ }, new BN15(0));
13106
+ if (totalAmountX.gt(amountX)) {
13107
+ baseDeltaX = baseDeltaX.sub(new BN15(1));
13108
+ } else {
13109
+ return {
13110
+ base: x0,
13111
+ delta: baseDeltaX
13112
+ };
13113
+ }
13490
13114
  }
13491
- totalClaimedFeeYAmount() {
13492
- return this.inner.totalClaimedFeeYAmount;
13115
+ }
13116
+ var BidAskStrategyParameterBuilder = class {
13117
+ findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13118
+ return findX0AndDeltaX(amountX, minDeltaId, maxDeltaId, binStep, activeId);
13493
13119
  }
13494
- totalClaimedFeeXAmount() {
13495
- return this.inner.totalClaimedFeeXAmount;
13120
+ findYParameters(amountY, minDeltaId, maxDeltaId, activeId) {
13121
+ return findY0AndDeltaY(amountY, minDeltaId, maxDeltaId, activeId);
13496
13122
  }
13497
- lbPair() {
13498
- return this.inner.lbPair;
13123
+ };
13124
+
13125
+ // src/dlmm/helpers/rebalance/liquidity_strategy/curve.ts
13126
+ import BN16 from "bn.js";
13127
+ function findBaseY0(amountY, minDeltaId, maxDeltaId) {
13128
+ if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN16(0))) {
13129
+ return new BN16(0);
13499
13130
  }
13500
- lowerBinId() {
13501
- return new BN17(this.inner.lowerBinId);
13131
+ if (minDeltaId.eq(maxDeltaId)) {
13132
+ return amountY;
13502
13133
  }
13503
- upperBinId() {
13504
- return new BN17(this.inner.upperBinId);
13134
+ const m1 = minDeltaId.neg();
13135
+ const m2 = maxDeltaId.neg();
13136
+ const b = m1.sub(m2).addn(1);
13137
+ const c = m1.mul(m1.addn(1)).divn(2);
13138
+ const d = m2.mul(m2.subn(1)).divn(2);
13139
+ const a = b.sub(c.sub(d).div(m1.addn(1)));
13140
+ return amountY.div(a);
13141
+ }
13142
+ function findY0AndDeltaY2(amountY, minDeltaId, maxDeltaId, activeId) {
13143
+ if (minDeltaId.gt(maxDeltaId) || amountY.isZero()) {
13144
+ return {
13145
+ base: new BN16(0),
13146
+ delta: new BN16(0)
13147
+ };
13505
13148
  }
13506
- liquidityShares() {
13507
- return this.combinedPositionBinData.liquidityShares;
13149
+ let baseY0 = findBaseY0(amountY, minDeltaId, maxDeltaId);
13150
+ while (true) {
13151
+ const deltaY = baseY0.neg().div(minDeltaId.neg().addn(1));
13152
+ const amountInBins = getAmountInBinsBidSide(
13153
+ activeId,
13154
+ minDeltaId,
13155
+ maxDeltaId,
13156
+ deltaY,
13157
+ baseY0
13158
+ );
13159
+ const totalAmountY = amountInBins.reduce((acc, { amountY: amountY2 }) => {
13160
+ return acc.add(amountY2);
13161
+ }, new BN16(0));
13162
+ if (totalAmountY.gt(amountY)) {
13163
+ baseY0 = baseY0.sub(new BN16(1));
13164
+ } else {
13165
+ return {
13166
+ base: baseY0,
13167
+ delta: deltaY
13168
+ };
13169
+ }
13508
13170
  }
13509
- rewardInfos() {
13510
- return this.combinedPositionBinData.rewardInfos;
13171
+ }
13172
+ function findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13173
+ if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN16(0))) {
13174
+ return new BN16(0);
13511
13175
  }
13512
- feeInfos() {
13513
- return this.combinedPositionBinData.feeInfos;
13176
+ let b = new BN16(0);
13177
+ let c = new BN16(0);
13178
+ let m1 = minDeltaId;
13179
+ let m2 = maxDeltaId;
13180
+ for (let m = m1.toNumber(); m <= m2.toNumber(); m++) {
13181
+ const binId = activeId.addn(m);
13182
+ const pm = getQPriceFromId(binId.neg(), binStep);
13183
+ b = b.add(pm);
13184
+ const cDelta = new BN16(m).mul(pm).div(m2);
13185
+ c = c.add(cDelta);
13514
13186
  }
13515
- lastUpdatedAt() {
13516
- return this.inner.lastUpdatedAt;
13187
+ return amountX.shln(SCALE_OFFSET).div(b.sub(c));
13188
+ }
13189
+ function findX0AndDeltaX2(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13190
+ if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN16(0)) || amountX.isZero()) {
13191
+ return {
13192
+ base: new BN16(0),
13193
+ delta: new BN16(0)
13194
+ };
13517
13195
  }
13518
- getBinArrayIndexesCoverage() {
13519
- const isExtended = this.extended.length > 0;
13520
- if (isExtended) {
13521
- return getBinArrayIndexesCoverage(this.lowerBinId(), this.upperBinId());
13196
+ let baseX0 = findBaseX0(amountX, minDeltaId, maxDeltaId, binStep, activeId);
13197
+ const deltaX = baseX0.neg().div(maxDeltaId);
13198
+ while (true) {
13199
+ const amountInBins = getAmountInBinsAskSide(
13200
+ activeId,
13201
+ binStep,
13202
+ minDeltaId,
13203
+ maxDeltaId,
13204
+ deltaX,
13205
+ baseX0
13206
+ );
13207
+ const totalAmountX = amountInBins.reduce((acc, { amountX: amountX2 }) => {
13208
+ return acc.add(amountX2);
13209
+ }, new BN16(0));
13210
+ if (totalAmountX.gt(amountX)) {
13211
+ baseX0 = baseX0.sub(new BN16(1));
13522
13212
  } else {
13523
- const lowerBinArrayIndex = binIdToBinArrayIndex(this.lowerBinId());
13524
- const upperBinArrayIndex = lowerBinArrayIndex.add(new BN17(1));
13525
- return [lowerBinArrayIndex, upperBinArrayIndex];
13213
+ return {
13214
+ base: baseX0,
13215
+ delta: deltaX
13216
+ };
13526
13217
  }
13527
13218
  }
13528
- getBinArrayKeysCoverage(programId) {
13529
- return this.getBinArrayIndexesCoverage().map(
13530
- (index) => deriveBinArray(this.lbPair(), index, programId)[0]
13531
- );
13532
- }
13533
- version() {
13534
- return 1 /* V2 */;
13535
- }
13536
- owner() {
13537
- return this.inner.owner;
13219
+ }
13220
+ var CurveStrategyParameterBuilder = class {
13221
+ findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13222
+ return findX0AndDeltaX2(amountX, minDeltaId, maxDeltaId, binStep, activeId);
13538
13223
  }
13539
- width() {
13540
- return this.upperBinId().sub(this.lowerBinId()).add(new BN17(1));
13224
+ findYParameters(amountY, minDeltaId, maxDeltaId, activeId) {
13225
+ return findY0AndDeltaY2(amountY, minDeltaId, maxDeltaId, activeId);
13541
13226
  }
13542
13227
  };
13543
13228
 
13544
- // src/dlmm/helpers/positions/index.ts
13545
- function getBinArrayIndexesCoverage(lowerBinId, upperBinId) {
13546
- const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);
13547
- const upperBinArrayIndex = binIdToBinArrayIndex(upperBinId);
13548
- const binArrayIndexes = [];
13549
- for (let i = lowerBinArrayIndex.toNumber(); i <= upperBinArrayIndex.toNumber(); i++) {
13550
- binArrayIndexes.push(new BN18(i));
13229
+ // src/dlmm/helpers/rebalance/liquidity_strategy/spot.ts
13230
+ import BN17 from "bn.js";
13231
+ function findY0(amountY, minDeltaId, maxDeltaId) {
13232
+ if (minDeltaId.gt(maxDeltaId) || amountY.lte(new BN17(0)) || amountY.isZero()) {
13233
+ return new BN17(0);
13551
13234
  }
13552
- return binArrayIndexes;
13553
- }
13554
- function getBinArrayKeysCoverage2(lowerBinId, upperBinId, lbPair, programId) {
13555
- const binArrayIndexes = getBinArrayIndexesCoverage(lowerBinId, upperBinId);
13556
- return binArrayIndexes.map((index) => {
13557
- return deriveBinArray(lbPair, index, programId)[0];
13558
- });
13559
- }
13560
- function getBinArrayAccountMetasCoverage(lowerBinId, upperBinId, lbPair, programId) {
13561
- return getBinArrayKeysCoverage2(lowerBinId, upperBinId, lbPair, programId).map(
13562
- (key) => {
13563
- return {
13564
- pubkey: key,
13565
- isSigner: false,
13566
- isWritable: true
13567
- };
13568
- }
13569
- );
13570
- }
13571
- function getPositionLowerUpperBinIdWithLiquidity(position) {
13572
- const binWithLiquidity = position.positionBinData.filter(
13573
- (b) => !new BN18(b.binLiquidity).isZero() || !new BN18(b.positionFeeXAmount.toString()).isZero() || !new BN18(b.positionFeeYAmount.toString()).isZero() || !new BN18(b.positionRewardAmount[0].toString()).isZero() || !new BN18(b.positionRewardAmount[1].toString()).isZero()
13574
- );
13575
- return binWithLiquidity.length > 0 ? {
13576
- lowerBinId: new BN18(binWithLiquidity[0].binId),
13577
- upperBinId: new BN18(binWithLiquidity[binWithLiquidity.length - 1].binId)
13578
- } : null;
13579
- }
13580
- function isPositionNoFee(position) {
13581
- return position.feeX.isZero() && position.feeY.isZero();
13582
- }
13583
- function isPositionNoReward(position) {
13584
- return position.rewardOne.isZero() && position.rewardTwo.isZero();
13235
+ const m1 = minDeltaId.neg();
13236
+ const m2 = maxDeltaId.neg();
13237
+ const delta = m1.sub(m2).addn(1);
13238
+ return amountY.div(delta);
13585
13239
  }
13586
- function chunkBinRange(minBinId, maxBinId) {
13587
- const chunkedBinRange = [];
13588
- let startBinId = minBinId;
13589
- while (startBinId <= maxBinId) {
13590
- const endBinId = Math.min(
13591
- startBinId + DEFAULT_BIN_PER_POSITION.toNumber() - 1,
13592
- maxBinId
13593
- );
13594
- chunkedBinRange.push({
13595
- lowerBinId: startBinId,
13596
- upperBinId: endBinId
13597
- });
13598
- startBinId += DEFAULT_BIN_PER_POSITION.toNumber();
13240
+ function findBaseX02(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13241
+ let totalWeight = new BN17(0);
13242
+ const minBinId = activeId.add(minDeltaId);
13243
+ const maxBinId = activeId.add(maxDeltaId);
13244
+ let baseFactor = getQPriceBaseFactor(binStep);
13245
+ let basePrice = getQPriceFromId(maxBinId.neg(), binStep);
13246
+ for (let binId = minBinId.toNumber(); binId <= maxBinId.toNumber(); binId++) {
13247
+ totalWeight = totalWeight.add(basePrice);
13248
+ basePrice = basePrice.mul(baseFactor).shrn(SCALE_OFFSET);
13599
13249
  }
13600
- return chunkedBinRange;
13250
+ return amountX.shln(SCALE_OFFSET).div(totalWeight);
13601
13251
  }
13602
- async function getPositionExpandRentExemption(currentMinBinId, currentMaxBinId, connection, binCountToExpand) {
13603
- const currentPositionWidth = currentMaxBinId.sub(currentMinBinId).addn(1);
13604
- const positionWidthAfterExpand = currentPositionWidth.add(binCountToExpand);
13605
- if (positionWidthAfterExpand.lte(DEFAULT_BIN_PER_POSITION)) {
13606
- return 0;
13607
- } else {
13608
- const binCountInExpandedBytes = positionWidthAfterExpand.sub(
13609
- DEFAULT_BIN_PER_POSITION
13252
+ function findX0(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13253
+ if (minDeltaId.gt(maxDeltaId) || amountX.lte(new BN17(0)) || amountX.isZero()) {
13254
+ return new BN17(0);
13255
+ }
13256
+ let x0 = findBaseX02(amountX, minDeltaId, maxDeltaId, binStep, activeId);
13257
+ while (true) {
13258
+ const amountInBins = getAmountInBinsAskSide(
13259
+ activeId,
13260
+ binStep,
13261
+ minDeltaId,
13262
+ maxDeltaId,
13263
+ new BN17(0),
13264
+ x0
13610
13265
  );
13611
- const expandSize = binCountInExpandedBytes.toNumber() * POSITION_BIN_DATA_SIZE;
13612
- const [minimumLamports, rentExemptionLamports] = await Promise.all([
13613
- connection.getMinimumBalanceForRentExemption(0),
13614
- connection.getMinimumBalanceForRentExemption(expandSize)
13615
- ]);
13616
- return rentExemptionLamports - minimumLamports;
13266
+ const totalAmountX = amountInBins.reduce((acc, bin) => {
13267
+ return acc.add(bin.amountX);
13268
+ }, new BN17(0));
13269
+ if (totalAmountX.lt(amountX)) {
13270
+ x0 = x0.add(new BN17(1));
13271
+ } else {
13272
+ x0 = x0.sub(new BN17(1));
13273
+ return x0;
13274
+ }
13617
13275
  }
13618
13276
  }
13619
- function getExtendedPositionBinCount(minBinId, maxBinId) {
13620
- const width = maxBinId.sub(minBinId).addn(1);
13621
- const extended = width.sub(DEFAULT_BIN_PER_POSITION);
13622
- return extended.lte(new BN18(0)) ? new BN18(0) : extended;
13277
+ var SpotStrategyParameterBuilder = class {
13278
+ findXParameters(amountX, minDeltaId, maxDeltaId, binStep, activeId) {
13279
+ return {
13280
+ base: findX0(amountX, minDeltaId, maxDeltaId, binStep, activeId),
13281
+ delta: new BN17(0)
13282
+ };
13283
+ }
13284
+ findYParameters(amountY, minDeltaId, maxDeltaId, _activeId) {
13285
+ return {
13286
+ base: findY0(amountY, minDeltaId, maxDeltaId),
13287
+ delta: new BN17(0)
13288
+ };
13289
+ }
13290
+ };
13291
+
13292
+ // src/dlmm/helpers/rebalance/liquidity_strategy/index.ts
13293
+ function getLiquidityStrategyParameterBuilder(strategyType) {
13294
+ switch (strategyType) {
13295
+ case 0 /* Spot */:
13296
+ return new SpotStrategyParameterBuilder();
13297
+ case 1 /* Curve */:
13298
+ return new CurveStrategyParameterBuilder();
13299
+ case 2 /* BidAsk */:
13300
+ return new BidAskStrategyParameterBuilder();
13301
+ default:
13302
+ throw new Error("Strategy not supported");
13303
+ }
13623
13304
  }
13624
- function decodeExtendedPosition(base, program, bytes) {
13625
- const width = base.upperBinId - base.lowerBinId + 1;
13626
- const extendedWidth = width - DEFAULT_BIN_PER_POSITION.toNumber();
13627
- const extendedPosition = [];
13628
- for (let i = 0; i < extendedWidth; i++) {
13629
- const offset = i * POSITION_BIN_DATA_SIZE;
13630
- const data = bytes.subarray(offset, offset + POSITION_BIN_DATA_SIZE);
13631
- const decodedPositionBinData = program.coder.types.decode(
13632
- // TODO: Find a type safe way
13633
- "positionBinData",
13634
- data
13305
+ function buildLiquidityStrategyParameters(amountX, amountY, minDeltaId, maxDeltaId, binStep, favorXInActiveId, activeId, strategyParameterBuilder) {
13306
+ if (minDeltaId.gt(maxDeltaId)) {
13307
+ return {
13308
+ x0: new BN18(0),
13309
+ y0: new BN18(0),
13310
+ deltaX: new BN18(0),
13311
+ deltaY: new BN18(0)
13312
+ };
13313
+ }
13314
+ const depositOnlyY = maxDeltaId.lt(new BN18(0)) || maxDeltaId.isZero() && !favorXInActiveId;
13315
+ const depositOnlyX = minDeltaId.gt(new BN18(0)) || minDeltaId.isZero() && favorXInActiveId;
13316
+ if (depositOnlyY) {
13317
+ const { base, delta } = strategyParameterBuilder.findYParameters(
13318
+ amountY,
13319
+ minDeltaId,
13320
+ maxDeltaId,
13321
+ activeId
13322
+ );
13323
+ return {
13324
+ x0: new BN18(0),
13325
+ deltaX: new BN18(0),
13326
+ y0: base,
13327
+ deltaY: delta
13328
+ };
13329
+ }
13330
+ if (depositOnlyX) {
13331
+ const { base, delta } = strategyParameterBuilder.findXParameters(
13332
+ amountX,
13333
+ minDeltaId,
13334
+ maxDeltaId,
13335
+ binStep,
13336
+ activeId
13635
13337
  );
13636
- extendedPosition.push(decodedPositionBinData);
13338
+ return {
13339
+ x0: base,
13340
+ deltaX: delta,
13341
+ y0: new BN18(0),
13342
+ deltaY: new BN18(0)
13343
+ };
13637
13344
  }
13638
- return extendedPosition;
13345
+ const maxDeltaIdBidSide = favorXInActiveId ? new BN18(-1) : new BN18(0);
13346
+ const minDeltaIdAskSide = favorXInActiveId ? new BN18(0) : new BN18(1);
13347
+ const { base: y0, delta: deltaY } = strategyParameterBuilder.findYParameters(
13348
+ amountY,
13349
+ minDeltaId,
13350
+ maxDeltaIdBidSide,
13351
+ activeId
13352
+ );
13353
+ const { base: x0, delta: deltaX } = strategyParameterBuilder.findXParameters(
13354
+ amountX,
13355
+ minDeltaIdAskSide,
13356
+ maxDeltaId,
13357
+ binStep,
13358
+ activeId
13359
+ );
13360
+ return {
13361
+ x0,
13362
+ deltaX,
13363
+ y0,
13364
+ deltaY
13365
+ };
13639
13366
  }
13640
13367
 
13641
13368
  // src/dlmm/helpers/rebalance/strategy/balanced.ts
@@ -14429,11 +14156,11 @@ var DLMM = class {
14429
14156
  return positionsMap;
14430
14157
  }
14431
14158
  static getPricePerLamport(tokenXDecimal, tokenYDecimal, price) {
14432
- return new Decimal8(price).mul(new Decimal8(10 ** (tokenYDecimal - tokenXDecimal))).toString();
14159
+ return new Decimal7(price).mul(new Decimal7(10 ** (tokenYDecimal - tokenXDecimal))).toString();
14433
14160
  }
14434
14161
  static getBinIdFromPrice(price, binStep, min) {
14435
- const binStepNum = new Decimal8(binStep).div(new Decimal8(BASIS_POINT_MAX));
14436
- const binId = new Decimal8(price).log().dividedBy(new Decimal8(1).add(binStepNum).log());
14162
+ const binStepNum = new Decimal7(binStep).div(new Decimal7(BASIS_POINT_MAX));
14163
+ const binId = new Decimal7(price).log().dividedBy(new Decimal7(1).add(binStepNum).log());
14437
14164
  return (min ? binId.floor() : binId.ceil()).toNumber();
14438
14165
  }
14439
14166
  /**
@@ -15045,8 +14772,8 @@ var DLMM = class {
15045
14772
  */
15046
14773
  static calculateFeeInfo(baseFactor, binStep, baseFeePowerFactor) {
15047
14774
  const baseFeeRate = new BN21(baseFactor).mul(new BN21(binStep)).mul(new BN21(10)).mul(new BN21(10).pow(new BN21(baseFeePowerFactor ?? 0)));
15048
- const baseFeeRatePercentage = new Decimal8(baseFeeRate.toString()).mul(new Decimal8(100)).div(new Decimal8(FEE_PRECISION.toString()));
15049
- const maxFeeRatePercentage = new Decimal8(MAX_FEE_RATE.toString()).mul(new Decimal8(100)).div(new Decimal8(FEE_PRECISION.toString()));
14775
+ const baseFeeRatePercentage = new Decimal7(baseFeeRate.toString()).mul(new Decimal7(100)).div(new Decimal7(FEE_PRECISION.toString()));
14776
+ const maxFeeRatePercentage = new Decimal7(MAX_FEE_RATE.toString()).mul(new Decimal7(100)).div(new Decimal7(FEE_PRECISION.toString()));
15050
14777
  return {
15051
14778
  baseFeeRatePercentage,
15052
14779
  maxFeeRatePercentage
@@ -15064,7 +14791,7 @@ var DLMM = class {
15064
14791
  this.lbPair.binStep,
15065
14792
  this.lbPair.parameters.baseFeePowerFactor
15066
14793
  );
15067
- const protocolFeePercentage = new Decimal8(protocolShare.toString()).mul(new Decimal8(100)).div(new Decimal8(BASIS_POINT_MAX));
14794
+ const protocolFeePercentage = new Decimal7(protocolShare.toString()).mul(new Decimal7(100)).div(new Decimal7(BASIS_POINT_MAX));
15068
14795
  return {
15069
14796
  baseFeeRatePercentage,
15070
14797
  maxFeeRatePercentage,
@@ -15096,7 +14823,7 @@ var DLMM = class {
15096
14823
  sParameters3,
15097
14824
  vParameterClone
15098
14825
  );
15099
- return new Decimal8(totalFee.toString()).div(new Decimal8(FEE_PRECISION.toString())).mul(100);
14826
+ return new Decimal7(totalFee.toString()).div(new Decimal7(FEE_PRECISION.toString())).mul(100);
15100
14827
  }
15101
14828
  /**
15102
14829
  * The function `getEmissionRate` returns the emission rates for two rewards.
@@ -15109,8 +14836,8 @@ var DLMM = class {
15109
14836
  ({ rewardRate, rewardDurationEnd }) => now > rewardDurationEnd.toNumber() ? void 0 : rewardRate
15110
14837
  );
15111
14838
  return {
15112
- rewardOne: rewardOneEmissionRate ? new Decimal8(rewardOneEmissionRate.toString()).div(PRECISION) : void 0,
15113
- rewardTwo: rewardTwoEmissionRate ? new Decimal8(rewardTwoEmissionRate.toString()).div(PRECISION) : void 0
14839
+ rewardOne: rewardOneEmissionRate ? new Decimal7(rewardOneEmissionRate.toString()).div(PRECISION) : void 0,
14840
+ rewardTwo: rewardTwoEmissionRate ? new Decimal7(rewardTwoEmissionRate.toString()).div(PRECISION) : void 0
15114
14841
  };
15115
14842
  }
15116
14843
  /**
@@ -15203,8 +14930,8 @@ var DLMM = class {
15203
14930
  * @returns {string} real price of bin
15204
14931
  */
15205
14932
  fromPricePerLamport(pricePerLamport) {
15206
- return new Decimal8(pricePerLamport).div(
15207
- new Decimal8(
14933
+ return new Decimal7(pricePerLamport).div(
14934
+ new Decimal7(
15208
14935
  10 ** (this.tokenY.mint.decimals - this.tokenX.mint.decimals)
15209
14936
  )
15210
14937
  ).toString();
@@ -15362,12 +15089,12 @@ var DLMM = class {
15362
15089
  const lowerBinArrayIndex = binIdToBinArrayIndex(currentMinBinId);
15363
15090
  const upperBinArrayIndex = binIdToBinArrayIndex(currentMaxBinId);
15364
15091
  const binArraysCount = (await this.binArraysToBeCreate(lowerBinArrayIndex, upperBinArrayIndex)).length;
15365
- const binArrayCost = new Decimal8(binArraysCount).mul(
15366
- new Decimal8(BIN_ARRAY_FEE)
15092
+ const binArrayCost = new Decimal7(binArraysCount).mul(
15093
+ new Decimal7(BIN_ARRAY_FEE)
15367
15094
  );
15368
15095
  return {
15369
- positionExtendCost: new Decimal8(positionExtendCost).div(
15370
- new Decimal8(LAMPORTS_PER_SOL2)
15096
+ positionExtendCost: new Decimal7(positionExtendCost).div(
15097
+ new Decimal7(LAMPORTS_PER_SOL2)
15371
15098
  ),
15372
15099
  binArrayCost
15373
15100
  };
@@ -15380,14 +15107,16 @@ var DLMM = class {
15380
15107
  lowerBinArrayIndex.add(new BN21(1))
15381
15108
  );
15382
15109
  const binArraysCount = (await this.binArraysToBeCreate(lowerBinArrayIndex, upperBinArrayIndex)).length;
15383
- const transactionCount = Math.ceil(
15384
- (maxBinId - minBinId + 1) / DEFAULT_BIN_PER_POSITION.toNumber()
15110
+ const positionCount = Math.ceil(
15111
+ (maxBinId - minBinId + 1) / Number(MAX_BINS_PER_POSITION)
15385
15112
  );
15386
15113
  const binArrayCost = binArraysCount * BIN_ARRAY_FEE;
15114
+ const positionCost = positionCount * POSITION_FEE;
15387
15115
  return {
15388
15116
  binArraysCount,
15389
15117
  binArrayCost,
15390
- transactionCount
15118
+ positionCount,
15119
+ positionCost
15391
15120
  };
15392
15121
  }
15393
15122
  /**
@@ -16636,7 +16365,7 @@ var DLMM = class {
16636
16365
  activeId.toNumber(),
16637
16366
  this.lbPair.binStep
16638
16367
  );
16639
- const priceImpact = startPrice.sub(endPrice).abs().div(startPrice).mul(new Decimal8(100));
16368
+ const priceImpact = startPrice.sub(endPrice).abs().div(startPrice).mul(new Decimal7(100));
16640
16369
  actualInAmount = calculateTransferFeeIncludedAmount(
16641
16370
  actualInAmount.add(feeAmount),
16642
16371
  inMint,
@@ -16823,7 +16552,7 @@ var DLMM = class {
16823
16552
  ),
16824
16553
  swapForY
16825
16554
  );
16826
- const priceImpact = new Decimal8(totalOutAmount.toString()).sub(new Decimal8(outAmountWithoutSlippage.toString())).div(new Decimal8(outAmountWithoutSlippage.toString())).mul(new Decimal8(100)).abs();
16555
+ const priceImpact = new Decimal7(totalOutAmount.toString()).sub(new Decimal7(outAmountWithoutSlippage.toString())).div(new Decimal7(outAmountWithoutSlippage.toString())).mul(new Decimal7(100)).abs();
16827
16556
  const endPrice = getPriceOfBinByBinId(
16828
16557
  lastFilledActiveBinId.toNumber(),
16829
16558
  this.lbPair.binStep
@@ -17432,11 +17161,11 @@ var DLMM = class {
17432
17161
  let totalBinArraysCount = new BN21(0);
17433
17162
  let totalBinArraysLamports = new BN21(0);
17434
17163
  let binArrayBitmapLamports = new BN21(0);
17435
- const toLamportMultiplier = new Decimal8(
17164
+ const toLamportMultiplier = new Decimal7(
17436
17165
  10 ** (this.tokenY.mint.decimals - this.tokenX.mint.decimals)
17437
17166
  );
17438
- const minPricePerLamport = new Decimal8(minPrice).mul(toLamportMultiplier);
17439
- const maxPricePerLamport = new Decimal8(maxPrice).mul(toLamportMultiplier);
17167
+ const minPricePerLamport = new Decimal7(minPrice).mul(toLamportMultiplier);
17168
+ const maxPricePerLamport = new Decimal7(maxPrice).mul(toLamportMultiplier);
17440
17169
  const minBinId = new BN21(
17441
17170
  DLMM.getBinIdFromPrice(minPricePerLamport, this.lbPair.binStep, false)
17442
17171
  );
@@ -18452,65 +18181,9 @@ var DLMM = class {
18452
18181
  withdraws,
18453
18182
  deposits
18454
18183
  );
18455
- const binArrayQuoteResult = await this.quoteBinArrayAccountsRentalCost(
18456
- simulationResult.depositParams,
18457
- simulationResult.withdrawParams,
18458
- new BN21(rebalancePosition.lbPair.activeId)
18459
- );
18460
18184
  return {
18461
18185
  rebalancePosition,
18462
- simulationResult,
18463
- ...binArrayQuoteResult
18464
- };
18465
- }
18466
- async quoteBinArrayAccountsRentalCost(deposits, withdraws, activeId) {
18467
- const { binArrayBitmap, binArrayIndexes } = getRebalanceBinArrayIndexesAndBitmapCoverage(
18468
- deposits,
18469
- withdraws,
18470
- activeId.toNumber(),
18471
- this.pubkey,
18472
- this.program.programId
18473
- );
18474
- const binArrayPublicKeys = binArrayIndexes.map((index) => {
18475
- const [binArrayPubkey] = deriveBinArray(
18476
- this.pubkey,
18477
- index,
18478
- this.program.programId
18479
- );
18480
- return binArrayPubkey;
18481
- });
18482
- const accountPublicKeys = [...binArrayPublicKeys];
18483
- if (!binArrayBitmap.equals(PublicKey10.default)) {
18484
- accountPublicKeys.push(binArrayBitmap);
18485
- }
18486
- const accounts = await chunkedGetMultipleAccountInfos(
18487
- this.program.provider.connection,
18488
- binArrayPublicKeys
18489
- );
18490
- const binArrayAccounts = accounts.splice(0, binArrayPublicKeys.length);
18491
- let binArrayCount = 0;
18492
- let bitmapExtensionCost = 0;
18493
- const binArraySet = /* @__PURE__ */ new Set();
18494
- for (let i = 0; i < binArrayAccounts.length; i++) {
18495
- const binArrayAccount = binArrayAccounts[i];
18496
- const binArrayPubkey = binArrayPublicKeys[i];
18497
- if (!binArrayAccount) {
18498
- binArrayCount++;
18499
- } else {
18500
- binArraySet.add(binArrayPubkey.toBase58());
18501
- }
18502
- }
18503
- if (!binArrayBitmap.equals(PublicKey10.default)) {
18504
- const bitmapAccount = accounts.pop();
18505
- if (!bitmapAccount) {
18506
- bitmapExtensionCost = BIN_ARRAY_BITMAP_FEE;
18507
- }
18508
- }
18509
- return {
18510
- binArrayCost: binArrayCount * BIN_ARRAY_FEE,
18511
- binArrayCount,
18512
- binArrayExistence: binArraySet,
18513
- bitmapExtensionCost
18186
+ simulationResult
18514
18187
  };
18515
18188
  }
18516
18189
  /**
@@ -18540,15 +18213,9 @@ var DLMM = class {
18540
18213
  withdraws,
18541
18214
  deposits
18542
18215
  );
18543
- const binArrayQuoteResult = await this.quoteBinArrayAccountsRentalCost(
18544
- simulationResult.depositParams,
18545
- simulationResult.withdrawParams,
18546
- new BN21(rebalancePosition.lbPair.activeId)
18547
- );
18548
18216
  return {
18549
18217
  rebalancePosition,
18550
- simulationResult,
18551
- ...binArrayQuoteResult
18218
+ simulationResult
18552
18219
  };
18553
18220
  }
18554
18221
  /**
@@ -18565,302 +18232,213 @@ var DLMM = class {
18565
18232
  const { lbPair, shouldClaimFee, shouldClaimReward, owner, address } = rebalancePosition;
18566
18233
  const { depositParams, withdrawParams } = simulationResult;
18567
18234
  const activeId = new BN21(lbPair.activeId);
18568
- let minBinId = Number.POSITIVE_INFINITY;
18569
- let maxBinId = Number.NEGATIVE_INFINITY;
18570
- for (const param of depositParams) {
18571
- const min = activeId.toNumber() + param.minDeltaId;
18572
- const max = activeId.toNumber() + param.maxDeltaId;
18573
- if (min < minBinId)
18574
- minBinId = min;
18575
- if (max > maxBinId)
18576
- maxBinId = max;
18577
- }
18578
- for (const param of withdrawParams) {
18579
- if (param.minBinId !== null && param.minBinId < minBinId)
18580
- minBinId = param.minBinId;
18581
- if (param.maxBinId !== null && param.maxBinId > maxBinId)
18582
- maxBinId = param.maxBinId;
18583
- }
18584
- if (!Number.isFinite(minBinId) || !Number.isFinite(maxBinId)) {
18585
- throw new Error("Unable to determine min/max binId for chunking");
18586
- }
18587
- const binChunks = chunkBinRange(minBinId, maxBinId);
18588
- function splitDepositParamsForChunk(params, chunk, activeId2) {
18589
- const res = [];
18590
- for (const param of params) {
18591
- const absMin = activeId2.toNumber() + param.minDeltaId;
18592
- const absMax = activeId2.toNumber() + param.maxDeltaId;
18593
- if (absMax < chunk.lowerBinId || absMin > chunk.upperBinId)
18594
- continue;
18595
- const newMin = Math.max(absMin, chunk.lowerBinId);
18596
- const newMax = Math.min(absMax, chunk.upperBinId);
18597
- res.push({
18598
- ...param,
18599
- minDeltaId: newMin - activeId2.toNumber(),
18600
- maxDeltaId: newMax - activeId2.toNumber()
18601
- });
18602
- }
18603
- return res;
18604
- }
18605
- function splitWithdrawParamsForChunk(params, chunk) {
18606
- const res = [];
18607
- for (const param of params) {
18608
- const absMin = param.minBinId !== null ? param.minBinId : activeId.toNumber();
18609
- const absMax = param.maxBinId !== null ? param.maxBinId : activeId.toNumber();
18610
- if (absMax < chunk.lowerBinId || absMin > chunk.upperBinId)
18611
- continue;
18612
- const newMin = Math.max(absMin, chunk.lowerBinId);
18613
- const newMax = Math.min(absMax, chunk.upperBinId);
18614
- res.push({
18615
- ...param,
18616
- minBinId: newMin,
18617
- maxBinId: newMax
18618
- });
18619
- }
18620
- return res;
18621
- }
18622
- const allInstructions = [];
18623
- for (const chunk of binChunks) {
18624
- const chunkedDepositParams = splitDepositParamsForChunk(
18625
- depositParams,
18626
- chunk,
18627
- activeId
18628
- );
18629
- const chunkedWithdrawParams = splitWithdrawParamsForChunk(
18630
- withdrawParams,
18631
- chunk
18632
- );
18633
- if (chunkedDepositParams.length === 0 && chunkedWithdrawParams.length === 0)
18634
- continue;
18635
- const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
18636
- const preInstructions = [];
18637
- const harvestRewardRemainingAccountMetas = [];
18638
- if (shouldClaimReward) {
18639
- for (const [idx, reward] of this.lbPair.rewardInfos.entries()) {
18640
- if (!reward.mint.equals(PublicKey10.default)) {
18641
- const rewardTokenInfo = this.rewards[idx];
18642
- slices.push({
18643
- accountsType: {
18644
- transferHookMultiReward: {
18645
- 0: idx
18646
- }
18647
- },
18648
- length: rewardTokenInfo.transferHookAccountMetas.length
18649
- });
18650
- transferHookAccounts.push(
18651
- ...rewardTokenInfo.transferHookAccountMetas
18652
- );
18653
- const userTokenRewardAddress = getAssociatedTokenAddressSync2(
18654
- reward.mint,
18235
+ const { slices, accounts: transferHookAccounts } = this.getPotentialToken2022IxDataAndAccounts(0 /* Liquidity */);
18236
+ const preInstructions = [];
18237
+ const harvestRewardRemainingAccountMetas = [];
18238
+ if (shouldClaimReward) {
18239
+ for (const [idx, reward] of this.lbPair.rewardInfos.entries()) {
18240
+ if (!reward.mint.equals(PublicKey10.default)) {
18241
+ const rewardTokenInfo = this.rewards[idx];
18242
+ slices.push({
18243
+ accountsType: {
18244
+ transferHookMultiReward: {
18245
+ 0: idx
18246
+ }
18247
+ },
18248
+ length: rewardTokenInfo.transferHookAccountMetas.length
18249
+ });
18250
+ transferHookAccounts.push(
18251
+ ...rewardTokenInfo.transferHookAccountMetas
18252
+ );
18253
+ const userTokenRewardAddress = getAssociatedTokenAddressSync2(
18254
+ reward.mint,
18255
+ owner,
18256
+ true,
18257
+ rewardTokenInfo.owner
18258
+ );
18259
+ preInstructions.push(
18260
+ createAssociatedTokenAccountIdempotentInstruction2(
18655
18261
  owner,
18656
- true,
18262
+ userTokenRewardAddress,
18263
+ owner,
18264
+ reward.mint,
18657
18265
  rewardTokenInfo.owner
18658
- );
18659
- preInstructions.push(
18660
- createAssociatedTokenAccountIdempotentInstruction2(
18661
- owner,
18662
- userTokenRewardAddress,
18663
- owner,
18664
- reward.mint,
18665
- rewardTokenInfo.owner
18666
- )
18667
- );
18668
- const rewardVault = {
18669
- pubkey: reward.vault,
18670
- isSigner: false,
18671
- isWritable: true
18672
- };
18673
- const userTokenReward = {
18674
- pubkey: userTokenRewardAddress,
18675
- isSigner: false,
18676
- isWritable: true
18677
- };
18678
- const rewardMint = {
18679
- pubkey: reward.mint,
18680
- isSigner: false,
18681
- isWritable: false
18682
- };
18683
- const rewardTokenProgram = {
18684
- pubkey: rewardTokenInfo.owner,
18685
- isSigner: false,
18686
- isWritable: false
18687
- };
18688
- harvestRewardRemainingAccountMetas.push(
18689
- rewardVault,
18690
- userTokenReward,
18691
- rewardMint,
18692
- rewardTokenProgram
18693
- );
18694
- }
18266
+ )
18267
+ );
18268
+ const rewardVault = {
18269
+ pubkey: reward.vault,
18270
+ isSigner: false,
18271
+ isWritable: true
18272
+ };
18273
+ const userTokenReward = {
18274
+ pubkey: userTokenRewardAddress,
18275
+ isSigner: false,
18276
+ isWritable: true
18277
+ };
18278
+ const rewardMint = {
18279
+ pubkey: reward.mint,
18280
+ isSigner: false,
18281
+ isWritable: false
18282
+ };
18283
+ const rewardTokenProgram = {
18284
+ pubkey: rewardTokenInfo.owner,
18285
+ isSigner: false,
18286
+ isWritable: false
18287
+ };
18288
+ harvestRewardRemainingAccountMetas.push(
18289
+ rewardVault,
18290
+ userTokenReward,
18291
+ rewardMint,
18292
+ rewardTokenProgram
18293
+ );
18695
18294
  }
18696
18295
  }
18697
- const initBinArrayInstructions = [];
18698
- const { binArrayBitmap, binArrayIndexes } = getRebalanceBinArrayIndexesAndBitmapCoverage(
18699
- chunkedDepositParams,
18700
- chunkedWithdrawParams,
18701
- activeId.toNumber(),
18296
+ }
18297
+ const initBinArrayInstructions = [];
18298
+ const { binArrayBitmap, binArrayIndexes } = getRebalanceBinArrayIndexesAndBitmapCoverage(
18299
+ depositParams,
18300
+ withdrawParams,
18301
+ activeId.toNumber(),
18302
+ this.pubkey,
18303
+ this.program.programId
18304
+ );
18305
+ const binArrayPublicKeys = binArrayIndexes.map((index) => {
18306
+ const [binArrayPubkey] = deriveBinArray(
18702
18307
  this.pubkey,
18308
+ index,
18703
18309
  this.program.programId
18704
18310
  );
18705
- const binArrayPublicKeys = binArrayIndexes.map((index) => {
18706
- const [binArrayPubkey] = deriveBinArray(
18707
- this.pubkey,
18708
- index,
18709
- this.program.programId
18710
- );
18711
- return binArrayPubkey;
18712
- });
18713
- const binArrayAccounts = await chunkedGetMultipleAccountInfos(
18714
- this.program.provider.connection,
18715
- binArrayPublicKeys
18716
- );
18717
- for (let i = 0; i < binArrayAccounts.length; i++) {
18718
- const binArrayAccount = binArrayAccounts[i];
18719
- if (!binArrayAccount) {
18720
- const binArrayPubkey = binArrayPublicKeys[i];
18721
- const binArrayIndex = binArrayIndexes[i];
18722
- const initBinArrayIx = await this.program.methods.initializeBinArray(binArrayIndex).accountsPartial({
18723
- binArray: binArrayPubkey,
18724
- funder: owner,
18725
- lbPair: this.pubkey
18726
- }).instruction();
18727
- initBinArrayInstructions.push(initBinArrayIx);
18728
- }
18729
- }
18730
- if (!binArrayBitmap.equals(PublicKey10.default)) {
18731
- const bitmapAccount = await this.program.provider.connection.getAccountInfo(binArrayBitmap);
18732
- if (!bitmapAccount) {
18733
- const initBitmapExtensionIx = await this.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
18734
- binArrayBitmapExtension: binArrayBitmap,
18735
- funder: owner,
18736
- lbPair: this.pubkey
18737
- }).preInstructions([
18738
- ComputeBudgetProgram3.setComputeUnitLimit({
18739
- units: DEFAULT_INIT_BIN_ARRAY_CU
18740
- })
18741
- ]).instruction();
18742
- preInstructions.push(initBitmapExtensionIx);
18743
- }
18744
- }
18745
- const [
18746
- { ataPubKey: userTokenX, ix: createUserTokenXIx },
18747
- { ataPubKey: userTokenY, ix: createUserTokenYIx }
18748
- ] = await Promise.all([
18749
- getOrCreateATAInstruction(
18750
- this.program.provider.connection,
18751
- this.tokenX.publicKey,
18752
- owner,
18753
- this.tokenX.owner
18754
- ),
18755
- getOrCreateATAInstruction(
18756
- this.program.provider.connection,
18757
- this.tokenY.publicKey,
18758
- owner,
18759
- this.tokenY.owner
18760
- )
18761
- ]);
18762
- createUserTokenXIx && preInstructions.push(createUserTokenXIx);
18763
- createUserTokenYIx && preInstructions.push(createUserTokenYIx);
18764
- slippage = capSlippagePercentage(slippage);
18765
- const applySlippageMaxAmount = (amount, slippage2) => {
18766
- return slippage2 == 100 ? U64_MAX : amount.muln(100 + slippage2).divn(100);
18767
- };
18768
- const applySlippageMinAmount = (amount, slippage2) => {
18769
- return amount.muln(100 - slippage2).divn(100);
18770
- };
18771
- const maxDepositXAmount = applySlippageMaxAmount(
18772
- simulationResult.actualAmountXDeposited,
18773
- slippage
18774
- );
18775
- const maxDepositYAmount = applySlippageMaxAmount(
18776
- simulationResult.actualAmountYDeposited,
18777
- slippage
18778
- );
18779
- const minWithdrawXAmount = applySlippageMinAmount(
18780
- simulationResult.actualAmountXWithdrawn,
18781
- slippage
18782
- );
18783
- const minWithdrawYAmount = applySlippageMinAmount(
18784
- simulationResult.actualAmountYWithdrawn,
18785
- slippage
18786
- );
18787
- const postInstructions = [];
18788
- if (this.tokenX.publicKey.equals(NATIVE_MINT2) && simulationResult.actualAmountXDeposited.gtn(0)) {
18789
- const wrapSOLIx = wrapSOLInstruction(
18790
- owner,
18791
- userTokenX,
18792
- BigInt(simulationResult.actualAmountXDeposited.toString())
18793
- );
18794
- preInstructions.push(...wrapSOLIx);
18795
- }
18796
- if (this.tokenY.publicKey.equals(NATIVE_MINT2) && simulationResult.actualAmountYDeposited.gtn(0)) {
18797
- const wrapSOLIx = wrapSOLInstruction(
18798
- owner,
18799
- userTokenY,
18800
- BigInt(simulationResult.actualAmountYDeposited.toString())
18801
- );
18802
- preInstructions.push(...wrapSOLIx);
18311
+ return binArrayPubkey;
18312
+ });
18313
+ const binArrayAccounts = await chunkedGetMultipleAccountInfos(
18314
+ this.program.provider.connection,
18315
+ binArrayPublicKeys
18316
+ );
18317
+ for (let i = 0; i < binArrayAccounts.length; i++) {
18318
+ const binArrayAccount = binArrayAccounts[i];
18319
+ if (!binArrayAccount) {
18320
+ const binArrayPubkey = binArrayPublicKeys[i];
18321
+ const binArrayIndex = binArrayIndexes[i];
18322
+ const initBinArrayIx = await this.program.methods.initializeBinArray(binArrayIndex).accountsPartial({
18323
+ binArray: binArrayPubkey,
18324
+ funder: owner,
18325
+ lbPair: this.pubkey
18326
+ }).instruction();
18327
+ initBinArrayInstructions.push(initBinArrayIx);
18803
18328
  }
18804
- if (this.tokenX.publicKey.equals(NATIVE_MINT2) || this.tokenY.publicKey.equals(NATIVE_MINT2)) {
18805
- const closeWrappedSOLIx = await unwrapSOLInstruction(owner);
18806
- closeWrappedSOLIx && postInstructions.push(closeWrappedSOLIx);
18329
+ }
18330
+ if (!binArrayBitmap.equals(PublicKey10.default)) {
18331
+ const bitmapAccount = await this.program.provider.connection.getAccountInfo(binArrayBitmap);
18332
+ if (!bitmapAccount) {
18333
+ const initBitmapExtensionIx = await this.program.methods.initializeBinArrayBitmapExtension().accountsPartial({
18334
+ binArrayBitmapExtension: binArrayBitmap,
18335
+ funder: owner,
18336
+ lbPair: this.pubkey
18337
+ }).preInstructions([
18338
+ ComputeBudgetProgram3.setComputeUnitLimit({
18339
+ units: DEFAULT_INIT_BIN_ARRAY_CU
18340
+ })
18341
+ ]).instruction();
18342
+ preInstructions.push(initBitmapExtensionIx);
18807
18343
  }
18808
- const instruction = await this.program.methods.rebalanceLiquidity(
18809
- {
18810
- adds: chunkedDepositParams,
18811
- removes: chunkedWithdrawParams,
18812
- activeId: activeId.toNumber(),
18813
- shouldClaimFee,
18814
- shouldClaimReward,
18815
- maxActiveBinSlippage: maxActiveBinSlippage.toNumber(),
18816
- maxDepositXAmount,
18817
- maxDepositYAmount,
18818
- minWithdrawXAmount,
18819
- minWithdrawYAmount,
18820
- padding: Array(32).fill(0)
18821
- },
18822
- {
18823
- slices
18824
- }
18825
- ).accountsPartial({
18826
- lbPair: this.pubkey,
18827
- binArrayBitmapExtension: binArrayBitmap,
18828
- position: address,
18344
+ }
18345
+ const [
18346
+ { ataPubKey: userTokenX, ix: createUserTokenXIx },
18347
+ { ataPubKey: userTokenY, ix: createUserTokenYIx }
18348
+ ] = await Promise.all([
18349
+ getOrCreateATAInstruction(
18350
+ this.program.provider.connection,
18351
+ this.tokenX.publicKey,
18829
18352
  owner,
18830
- userTokenX,
18831
- userTokenY,
18832
- reserveX: this.lbPair.reserveX,
18833
- reserveY: this.lbPair.reserveY,
18834
- tokenXMint: this.tokenX.publicKey,
18835
- tokenYMint: this.tokenY.publicKey,
18836
- tokenXProgram: this.tokenX.owner,
18837
- tokenYProgram: this.tokenY.owner,
18838
- memoProgram: MEMO_PROGRAM_ID,
18839
- rentPayer: rentPayer ?? owner
18840
- }).remainingAccounts(transferHookAccounts).remainingAccounts(
18841
- binArrayPublicKeys.map((pubkey) => {
18842
- return {
18843
- pubkey,
18844
- isSigner: false,
18845
- isWritable: true
18846
- };
18847
- })
18848
- ).instruction();
18849
- const setCUIX = await getEstimatedComputeUnitIxWithBuffer(
18353
+ this.tokenX.owner
18354
+ ),
18355
+ getOrCreateATAInstruction(
18850
18356
  this.program.provider.connection,
18851
- [instruction],
18852
- owner
18853
- );
18854
- const rebalancePositionInstruction = [
18855
- setCUIX,
18856
- ...initBinArrayInstructions,
18857
- ...preInstructions,
18858
- instruction,
18859
- ...postInstructions
18860
- ];
18861
- allInstructions.push(rebalancePositionInstruction);
18862
- }
18863
- return allInstructions;
18357
+ this.tokenY.publicKey,
18358
+ owner,
18359
+ this.tokenY.owner
18360
+ )
18361
+ ]);
18362
+ createUserTokenXIx && preInstructions.push(createUserTokenXIx);
18363
+ createUserTokenYIx && preInstructions.push(createUserTokenYIx);
18364
+ slippage = capSlippagePercentage(slippage);
18365
+ const applySlippageMaxAmount = (amount, slippage2) => {
18366
+ return slippage2 == 100 ? U64_MAX : amount.muln(100 + slippage2).divn(100);
18367
+ };
18368
+ const applySlippageMinAmount = (amount, slippage2) => {
18369
+ return amount.muln(100 - slippage2).divn(100);
18370
+ };
18371
+ const maxDepositXAmount = applySlippageMaxAmount(
18372
+ simulationResult.actualAmountXDeposited,
18373
+ slippage
18374
+ );
18375
+ const maxDepositYAmount = applySlippageMaxAmount(
18376
+ simulationResult.actualAmountYDeposited,
18377
+ slippage
18378
+ );
18379
+ const minWithdrawXAmount = applySlippageMinAmount(
18380
+ simulationResult.actualAmountXWithdrawn,
18381
+ slippage
18382
+ );
18383
+ const minWithdrawYAmount = applySlippageMinAmount(
18384
+ simulationResult.actualAmountYWithdrawn,
18385
+ slippage
18386
+ );
18387
+ const instruction = await this.program.methods.rebalanceLiquidity(
18388
+ {
18389
+ adds: depositParams,
18390
+ removes: withdrawParams,
18391
+ activeId: activeId.toNumber(),
18392
+ shouldClaimFee,
18393
+ shouldClaimReward,
18394
+ maxActiveBinSlippage: maxActiveBinSlippage.toNumber(),
18395
+ maxDepositXAmount,
18396
+ maxDepositYAmount,
18397
+ minWithdrawXAmount,
18398
+ minWithdrawYAmount,
18399
+ padding: Array(32).fill(0)
18400
+ },
18401
+ {
18402
+ slices
18403
+ }
18404
+ ).accountsPartial({
18405
+ lbPair: this.pubkey,
18406
+ binArrayBitmapExtension: binArrayBitmap,
18407
+ position: address,
18408
+ owner,
18409
+ userTokenX,
18410
+ userTokenY,
18411
+ reserveX: this.lbPair.reserveX,
18412
+ reserveY: this.lbPair.reserveY,
18413
+ tokenXMint: this.tokenX.publicKey,
18414
+ tokenYMint: this.tokenY.publicKey,
18415
+ tokenXProgram: this.tokenX.owner,
18416
+ tokenYProgram: this.tokenY.owner,
18417
+ memoProgram: MEMO_PROGRAM_ID,
18418
+ rentPayer: rentPayer ?? owner
18419
+ }).remainingAccounts(transferHookAccounts).remainingAccounts(
18420
+ binArrayPublicKeys.map((pubkey) => {
18421
+ return {
18422
+ pubkey,
18423
+ isSigner: false,
18424
+ isWritable: true
18425
+ };
18426
+ })
18427
+ ).instruction();
18428
+ const setCUIX = await getEstimatedComputeUnitIxWithBuffer(
18429
+ this.program.provider.connection,
18430
+ [instruction],
18431
+ owner
18432
+ );
18433
+ const rebalancePositionInstruction = [
18434
+ setCUIX,
18435
+ ...preInstructions,
18436
+ instruction
18437
+ ];
18438
+ return {
18439
+ initBinArrayInstructions,
18440
+ rebalancePositionInstruction
18441
+ };
18864
18442
  }
18865
18443
  /**
18866
18444
  * Create an extended empty position.
@@ -18886,8 +18464,7 @@ var DLMM = class {
18886
18464
  );
18887
18465
  const latestBlockhashInfo = await this.program.provider.connection.getLatestBlockhash();
18888
18466
  const tx = new Transaction({
18889
- ...latestBlockhashInfo,
18890
- feePayer: owner
18467
+ ...latestBlockhashInfo
18891
18468
  }).add(...ixs);
18892
18469
  return tx;
18893
18470
  }
@@ -18995,8 +18572,8 @@ var DLMM = class {
18995
18572
  if (!bins.length)
18996
18573
  return null;
18997
18574
  const positionData = [];
18998
- let totalXAmount = new Decimal8(0);
18999
- let totalYAmount = new Decimal8(0);
18575
+ let totalXAmount = new Decimal7(0);
18576
+ let totalYAmount = new Decimal7(0);
19000
18577
  const ZERO = new BN21(0);
19001
18578
  let feeX = ZERO;
19002
18579
  let feeY = ZERO;
@@ -19007,8 +18584,8 @@ var DLMM = class {
19007
18584
  const posBinRewardInfo = positionRewardInfos[idx];
19008
18585
  const positionXAmount = binSupply.eq(ZERO) ? ZERO : posShare.mul(bin.xAmount).div(binSupply);
19009
18586
  const positionYAmount = binSupply.eq(ZERO) ? ZERO : posShare.mul(bin.yAmount).div(binSupply);
19010
- totalXAmount = totalXAmount.add(new Decimal8(positionXAmount.toString()));
19011
- totalYAmount = totalYAmount.add(new Decimal8(positionYAmount.toString()));
18587
+ totalXAmount = totalXAmount.add(new Decimal7(positionXAmount.toString()));
18588
+ totalYAmount = totalYAmount.add(new Decimal7(positionYAmount.toString()));
19012
18589
  const feeInfo = feeInfos[idx];
19013
18590
  const newFeeX = mulShr(
19014
18591
  posShares[idx].shrn(SCALE_OFFSET),
@@ -19172,7 +18749,7 @@ var DLMM = class {
19172
18749
  rewardPerTokenStored: [ZERO, ZERO],
19173
18750
  price: pricePerLamport,
19174
18751
  version: 2,
19175
- pricePerToken: new Decimal8(pricePerLamport).mul(new Decimal8(10 ** (baseTokenDecimal - quoteTokenDecimal))).toString()
18752
+ pricePerToken: new Decimal7(pricePerLamport).mul(new Decimal7(10 ** (baseTokenDecimal - quoteTokenDecimal))).toString()
19176
18753
  });
19177
18754
  } else {
19178
18755
  const bin = binArray.bins[i];
@@ -19186,7 +18763,7 @@ var DLMM = class {
19186
18763
  rewardPerTokenStored: bin.rewardPerTokenStored,
19187
18764
  price: pricePerLamport,
19188
18765
  version: binArray.version,
19189
- pricePerToken: new Decimal8(pricePerLamport).mul(new Decimal8(10 ** (baseTokenDecimal - quoteTokenDecimal))).toString()
18766
+ pricePerToken: new Decimal7(pricePerLamport).mul(new Decimal7(10 ** (baseTokenDecimal - quoteTokenDecimal))).toString()
19190
18767
  });
19191
18768
  }
19192
18769
  }
@@ -19545,7 +19122,6 @@ export {
19545
19122
  PairStatus,
19546
19123
  PairType,
19547
19124
  PositionVersion,
19548
- RebalancePosition,
19549
19125
  ResizeSide,
19550
19126
  SCALE,
19551
19127
  SCALE_OFFSET,
@@ -19560,7 +19136,6 @@ export {
19560
19136
  autoFillYByStrategy,
19561
19137
  autoFillYByWeight,
19562
19138
  binIdToBinArrayIndex,
19563
- buildLiquidityStrategyParameters,
19564
19139
  calculateBidAskDistribution,
19565
19140
  calculateNormalDistribution,
19566
19141
  calculateSpotDistribution,
@@ -19597,9 +19172,6 @@ export {
19597
19172
  fromWeightDistributionToAmount,
19598
19173
  fromWeightDistributionToAmountOneSide,
19599
19174
  getAccountDiscriminator,
19600
- getAmountInBinsAskSide,
19601
- getAmountInBinsBidSide,
19602
- getAutoFillAmountByRebalancedPosition,
19603
19175
  getBaseFee,
19604
19176
  getBinArrayLowerUpperBinId,
19605
19177
  getBinArraysRequiredByPositionRange,
@@ -19607,11 +19179,9 @@ export {
19607
19179
  getBinIdIndexInBinArray,
19608
19180
  getEstimatedComputeUnitIxWithBuffer,
19609
19181
  getEstimatedComputeUnitUsageWithBuffer,
19610
- getLiquidityStrategyParameterBuilder,
19611
19182
  getOrCreateATAInstruction,
19612
19183
  getOutAmount,
19613
19184
  getPriceOfBinByBinId,
19614
- getRebalanceBinArrayIndexesAndBitmapCoverage,
19615
19185
  getTokenBalance,
19616
19186
  getTokenDecimals,
19617
19187
  getTokenProgramId,
@@ -19622,14 +19192,11 @@ export {
19622
19192
  isOverflowDefaultBinArrayBitmap,
19623
19193
  parseLogs,
19624
19194
  range,
19625
- suggestBalancedXParametersFromY,
19626
- suggestBalancedYParametersFromX,
19627
19195
  swapExactInQuoteAtBin,
19628
19196
  swapExactOutQuoteAtBin,
19629
19197
  toAmountAskSide,
19630
19198
  toAmountBidSide,
19631
19199
  toAmountBothSide,
19632
- toAmountIntoBins,
19633
19200
  toAmountsBothSideByStrategy,
19634
19201
  toStrategyParameters,
19635
19202
  toWeightDistribution,