@meteora-ag/dlmm 1.9.12 → 1.9.14

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
@@ -10448,7 +10448,7 @@ var LimitOrderStatus = /* @__PURE__ */ ((LimitOrderStatus2) => {
10448
10448
  })(LimitOrderStatus || {});
10449
10449
 
10450
10450
  // src/dlmm/helpers/binArray.ts
10451
- import { BN as BN8 } from "@coral-xyz/anchor";
10451
+ import { BN as BN10 } from "@coral-xyz/anchor";
10452
10452
  import { PublicKey as PublicKey5 } from "@solana/web3.js";
10453
10453
 
10454
10454
  // src/dlmm/helpers/derive.ts
@@ -11811,137 +11811,422 @@ function generateBinAmount(amount, binStep, binId, tokenXDecimal, tokenYDecimal,
11811
11811
  return new BN7(c1.sub(c0).floor().toString());
11812
11812
  }
11813
11813
 
11814
- // src/dlmm/helpers/binArray.ts
11815
- function internalBitmapRange() {
11816
- const lowerBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.neg();
11817
- const upperBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new BN8(1));
11818
- return [lowerBinArrayIndex, upperBinArrayIndex];
11819
- }
11820
- function buildBitmapFromU64Arrays(u64Arrays, type) {
11821
- const buffer = Buffer.concat(
11822
- u64Arrays.map((b) => {
11823
- return b.toArrayLike(Buffer, "le", 8);
11824
- })
11825
- );
11826
- return new BN8(buffer, "le");
11814
+ // src/dlmm/helpers/positions/index.ts
11815
+ import BN9 from "bn.js";
11816
+
11817
+ // src/dlmm/helpers/positions/wrapper.ts
11818
+ import BN8 from "bn.js";
11819
+ function combineBaseAndExtendedPositionBinData(base, extended) {
11820
+ const combinedLiquidityShares = base.liquidityShares;
11821
+ const combinedRewardInfos = base.rewardInfos;
11822
+ const combinedFeeInfos = base.feeInfos;
11823
+ for (const binData of extended) {
11824
+ combinedLiquidityShares.push(binData.liquidityShare);
11825
+ combinedRewardInfos.push(binData.rewardInfo);
11826
+ combinedFeeInfos.push(binData.feeInfo);
11827
+ }
11828
+ return {
11829
+ liquidityShares: combinedLiquidityShares,
11830
+ rewardInfos: combinedRewardInfos,
11831
+ feeInfos: combinedFeeInfos
11832
+ };
11827
11833
  }
11828
- function bitmapTypeDetail(type) {
11829
- if (type == 0 /* U1024 */) {
11830
- return {
11831
- bits: 1024,
11832
- bytes: 1024 / 8
11833
- };
11834
+ function wrapPosition(program, key, account) {
11835
+ const disc = account.data.subarray(0, 8);
11836
+ if (disc.equals(Buffer.from(getAccountDiscriminator("positionV2")))) {
11837
+ const state = decodeAccount(
11838
+ program,
11839
+ "positionV2",
11840
+ account.data
11841
+ );
11842
+ const extended = decodeExtendedPosition(
11843
+ state,
11844
+ program,
11845
+ account.data.subarray(8 + POSITION_MIN_SIZE)
11846
+ );
11847
+ const combinedPositionBinData = combineBaseAndExtendedPositionBinData(
11848
+ state,
11849
+ extended
11850
+ );
11851
+ return new PositionV2Wrapper(key, state, extended, combinedPositionBinData);
11834
11852
  } else {
11835
- return {
11836
- bits: 512,
11837
- bytes: 512 / 8
11838
- };
11853
+ throw new Error("Unknown position account");
11839
11854
  }
11840
11855
  }
11841
- function mostSignificantBit(number, bitLength) {
11842
- const highestIndex = bitLength - 1;
11843
- if (number.isZero()) {
11844
- return null;
11856
+ var PositionV2Wrapper = class {
11857
+ constructor(positionAddress, inner, extended, combinedPositionBinData) {
11858
+ this.positionAddress = positionAddress;
11859
+ this.inner = inner;
11860
+ this.extended = extended;
11861
+ this.combinedPositionBinData = combinedPositionBinData;
11845
11862
  }
11846
- for (let i = highestIndex; i >= 0; i--) {
11847
- if (number.testn(i)) {
11848
- return highestIndex - i;
11849
- }
11863
+ address() {
11864
+ return this.positionAddress;
11850
11865
  }
11851
- return null;
11852
- }
11853
- function leastSignificantBit(number, bitLength) {
11854
- if (number.isZero()) {
11855
- return null;
11866
+ totalClaimedRewards() {
11867
+ return this.inner.totalClaimedRewards;
11856
11868
  }
11857
- for (let i = 0; i < bitLength; i++) {
11858
- if (number.testn(i)) {
11859
- return i;
11869
+ feeOwner() {
11870
+ return this.inner.feeOwner;
11871
+ }
11872
+ lockReleasePoint() {
11873
+ return this.inner.lockReleasePoint;
11874
+ }
11875
+ operator() {
11876
+ return this.inner.operator;
11877
+ }
11878
+ totalClaimedFeeYAmount() {
11879
+ return this.inner.totalClaimedFeeYAmount;
11880
+ }
11881
+ totalClaimedFeeXAmount() {
11882
+ return this.inner.totalClaimedFeeXAmount;
11883
+ }
11884
+ lbPair() {
11885
+ return this.inner.lbPair;
11886
+ }
11887
+ lowerBinId() {
11888
+ return new BN8(this.inner.lowerBinId);
11889
+ }
11890
+ upperBinId() {
11891
+ return new BN8(this.inner.upperBinId);
11892
+ }
11893
+ liquidityShares() {
11894
+ return this.combinedPositionBinData.liquidityShares;
11895
+ }
11896
+ rewardInfos() {
11897
+ return this.combinedPositionBinData.rewardInfos;
11898
+ }
11899
+ feeInfos() {
11900
+ return this.combinedPositionBinData.feeInfos;
11901
+ }
11902
+ lastUpdatedAt() {
11903
+ return this.inner.lastUpdatedAt;
11904
+ }
11905
+ getBinArrayIndexesCoverage() {
11906
+ const isExtended = this.extended.length > 0;
11907
+ if (isExtended) {
11908
+ return getBinArrayIndexesCoverage(this.lowerBinId(), this.upperBinId());
11909
+ } else {
11910
+ const lowerBinArrayIndex = binIdToBinArrayIndex(this.lowerBinId());
11911
+ const upperBinArrayIndex = lowerBinArrayIndex.add(new BN8(1));
11912
+ return [lowerBinArrayIndex, upperBinArrayIndex];
11860
11913
  }
11861
11914
  }
11862
- return null;
11915
+ getBinArrayKeysCoverage(programId) {
11916
+ return this.getBinArrayIndexesCoverage().map(
11917
+ (index) => deriveBinArray(this.lbPair(), index, programId)[0]
11918
+ );
11919
+ }
11920
+ version() {
11921
+ return 1 /* V2 */;
11922
+ }
11923
+ owner() {
11924
+ return this.inner.owner;
11925
+ }
11926
+ width() {
11927
+ return this.upperBinId().sub(this.lowerBinId()).add(new BN8(1));
11928
+ }
11929
+ };
11930
+
11931
+ // src/dlmm/helpers/positions/index.ts
11932
+ function getBinArrayIndexesCoverage(lowerBinId, upperBinId) {
11933
+ const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);
11934
+ const upperBinArrayIndex = binIdToBinArrayIndex(upperBinId);
11935
+ const binArrayIndexes = [];
11936
+ for (let i = lowerBinArrayIndex.toNumber(); i <= upperBinArrayIndex.toNumber(); i++) {
11937
+ binArrayIndexes.push(new BN9(i));
11938
+ }
11939
+ return binArrayIndexes;
11863
11940
  }
11864
- function extensionBitmapRange() {
11865
- return [
11866
- BIN_ARRAY_BITMAP_SIZE.neg().mul(
11867
- EXTENSION_BINARRAY_BITMAP_SIZE.add(new BN8(1))
11868
- ),
11869
- BIN_ARRAY_BITMAP_SIZE.mul(
11870
- EXTENSION_BINARRAY_BITMAP_SIZE.add(new BN8(1))
11871
- ).sub(new BN8(1))
11872
- ];
11941
+ function getBinArrayKeysCoverage(lowerBinId, upperBinId, lbPair, programId) {
11942
+ const binArrayIndexes = getBinArrayIndexesCoverage(lowerBinId, upperBinId);
11943
+ return binArrayIndexes.map((index) => {
11944
+ return deriveBinArray(lbPair, index, programId)[0];
11945
+ });
11873
11946
  }
11874
- function findSetBit(startIndex, endIndex, binArrayBitmapExtension) {
11875
- const getBinArrayOffset = (binArrayIndex) => {
11876
- return binArrayIndex.gt(new BN8(0)) ? binArrayIndex.mod(BIN_ARRAY_BITMAP_SIZE) : binArrayIndex.add(new BN8(1)).neg().mod(BIN_ARRAY_BITMAP_SIZE);
11877
- };
11878
- const getBitmapOffset = (binArrayIndex) => {
11879
- return binArrayIndex.gt(new BN8(0)) ? binArrayIndex.div(BIN_ARRAY_BITMAP_SIZE).sub(new BN8(1)) : binArrayIndex.add(new BN8(1)).neg().div(BIN_ARRAY_BITMAP_SIZE).sub(new BN8(1));
11880
- };
11881
- if (startIndex <= endIndex) {
11882
- for (let i = startIndex; i <= endIndex; i++) {
11883
- const binArrayOffset = getBinArrayOffset(new BN8(i)).toNumber();
11884
- const bitmapOffset = getBitmapOffset(new BN8(i)).toNumber();
11885
- const bitmapChunks = i > 0 ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset] : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];
11886
- const bitmap = buildBitmapFromU64Arrays(bitmapChunks, 1 /* U512 */);
11887
- if (bitmap.testn(binArrayOffset)) {
11888
- return i;
11889
- }
11890
- }
11891
- } else {
11892
- for (let i = startIndex; i >= endIndex; i--) {
11893
- const binArrayOffset = getBinArrayOffset(new BN8(i)).toNumber();
11894
- const bitmapOffset = getBitmapOffset(new BN8(i)).toNumber();
11895
- const bitmapChunks = i > 0 ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset] : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];
11896
- const bitmap = buildBitmapFromU64Arrays(bitmapChunks, 1 /* U512 */);
11897
- if (bitmap.testn(binArrayOffset)) {
11898
- return i;
11899
- }
11947
+ function getBinArrayAccountMetasCoverage(lowerBinId, upperBinId, lbPair, programId) {
11948
+ return getBinArrayKeysCoverage(lowerBinId, upperBinId, lbPair, programId).map(
11949
+ (key) => {
11950
+ return {
11951
+ pubkey: key,
11952
+ isSigner: false,
11953
+ isWritable: true
11954
+ };
11900
11955
  }
11901
- }
11902
- return null;
11903
- }
11904
- function isOverflowDefaultBinArrayBitmap(binArrayIndex) {
11905
- const [minBinArrayIndex, maxBinArrayIndex] = internalBitmapRange();
11906
- return binArrayIndex.gt(maxBinArrayIndex) || binArrayIndex.lt(minBinArrayIndex);
11956
+ );
11907
11957
  }
11908
- function deriveBinArrayBitmapExtension(lbPair, programId) {
11909
- return PublicKey5.findProgramAddressSync(
11910
- [Buffer.from("bitmap"), lbPair.toBytes()],
11911
- programId
11958
+ function getPositionLowerUpperBinIdWithLiquidity(position) {
11959
+ const binWithLiquidity = position.positionBinData.filter(
11960
+ (b) => !new BN9(b.binLiquidity).isZero() || !new BN9(b.positionFeeXAmount.toString()).isZero() || !new BN9(b.positionFeeYAmount.toString()).isZero() || !new BN9(b.positionRewardAmount[0].toString()).isZero() || !new BN9(b.positionRewardAmount[1].toString()).isZero()
11912
11961
  );
11962
+ return binWithLiquidity.length > 0 ? {
11963
+ lowerBinId: new BN9(binWithLiquidity[0].binId),
11964
+ upperBinId: new BN9(binWithLiquidity[binWithLiquidity.length - 1].binId)
11965
+ } : null;
11913
11966
  }
11914
- function binIdToBinArrayIndex(binId) {
11915
- const { div: idx, mod } = binId.divmod(MAX_BIN_ARRAY_SIZE);
11916
- return binId.isNeg() && !mod.isZero() ? idx.sub(new BN8(1)) : idx;
11967
+ function isPositionNoFee(position) {
11968
+ return position.feeX.isZero() && position.feeY.isZero();
11917
11969
  }
11918
- function getBinArrayLowerUpperBinId(binArrayIndex) {
11919
- const lowerBinId = binArrayIndex.mul(MAX_BIN_ARRAY_SIZE);
11920
- const upperBinId = lowerBinId.add(MAX_BIN_ARRAY_SIZE).sub(new BN8(1));
11921
- return [lowerBinId, upperBinId];
11970
+ function isPositionNoReward(position) {
11971
+ return position.rewardOne.isZero() && position.rewardTwo.isZero();
11922
11972
  }
11923
- function isBinIdWithinBinArray(activeId, binArrayIndex) {
11924
- const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
11925
- return activeId.gte(lowerBinId) && activeId.lte(upperBinId);
11973
+ function chunkBinRangeIntoExtendedPositions(minBinId, maxBinId) {
11974
+ const chunkedBinRange = [];
11975
+ for (let currentMinBinId = minBinId; currentMinBinId <= maxBinId; currentMinBinId += POSITION_MAX_LENGTH.toNumber()) {
11976
+ const currentMaxBinId = Math.min(
11977
+ currentMinBinId + POSITION_MAX_LENGTH.toNumber() - 1,
11978
+ maxBinId
11979
+ );
11980
+ chunkedBinRange.push({
11981
+ lowerBinId: currentMinBinId,
11982
+ upperBinId: currentMaxBinId
11983
+ });
11984
+ }
11985
+ return chunkedBinRange;
11926
11986
  }
11927
- function getBinFromBinArray(binId, binArray) {
11928
- const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArray.index);
11929
- let index = 0;
11930
- if (binId > 0) {
11931
- index = binId - lowerBinId.toNumber();
11932
- } else {
11933
- const delta = upperBinId.toNumber() - binId;
11934
- index = MAX_BIN_ARRAY_SIZE.toNumber() - delta - 1;
11987
+ function chunkBinRange(minBinId, maxBinId, binPerChunk) {
11988
+ const chunkedBinRange = [];
11989
+ let startBinId = minBinId;
11990
+ binPerChunk = binPerChunk ?? DEFAULT_BIN_PER_POSITION.toNumber();
11991
+ while (startBinId <= maxBinId) {
11992
+ const endBinId = Math.min(startBinId + binPerChunk - 1, maxBinId);
11993
+ chunkedBinRange.push({
11994
+ lowerBinId: startBinId,
11995
+ upperBinId: endBinId
11996
+ });
11997
+ startBinId += binPerChunk;
11935
11998
  }
11936
- return binArray.bins[index];
11999
+ return chunkedBinRange;
11937
12000
  }
11938
- function findNextBinArrayIndexWithLiquidity(swapForY, activeId, lbPairState, binArrayBitmapExtension) {
11939
- const [lowerBinArrayIndex, upperBinArrayIndex] = internalBitmapRange();
11940
- let startBinArrayIndex = binIdToBinArrayIndex(activeId);
11941
- while (true) {
11942
- if (isOverflowDefaultBinArrayBitmap(startBinArrayIndex)) {
11943
- if (binArrayBitmapExtension === null) {
11944
- return null;
12001
+ function chunkPositionBinRange(position, minBinId, maxBinId) {
12002
+ const chunkedFeesAndRewards = [];
12003
+ let totalAmountX = new BN9(0);
12004
+ let totalAmountY = new BN9(0);
12005
+ let totalFeeXAmount = new BN9(0);
12006
+ let totalFeeYAmount = new BN9(0);
12007
+ let totalRewardAmounts = [new BN9(0), new BN9(0)];
12008
+ let count = 0;
12009
+ for (let i = 0; i < position.positionData.positionBinData.length; i++) {
12010
+ const positionBinData = position.positionData.positionBinData[i];
12011
+ if (positionBinData.binId >= minBinId && positionBinData.binId <= maxBinId) {
12012
+ totalFeeXAmount = totalFeeXAmount.add(
12013
+ new BN9(positionBinData.positionFeeXAmount)
12014
+ );
12015
+ totalFeeYAmount = totalFeeYAmount.add(
12016
+ new BN9(positionBinData.positionFeeYAmount)
12017
+ );
12018
+ totalAmountX = totalAmountX.add(new BN9(positionBinData.positionXAmount));
12019
+ totalAmountY = totalAmountY.add(new BN9(positionBinData.positionYAmount));
12020
+ for (const [
12021
+ index,
12022
+ reward
12023
+ ] of positionBinData.positionRewardAmount.entries()) {
12024
+ totalRewardAmounts[index] = totalRewardAmounts[index].add(
12025
+ new BN9(reward)
12026
+ );
12027
+ }
12028
+ count++;
12029
+ }
12030
+ if (count === DEFAULT_BIN_PER_POSITION.toNumber() || positionBinData.binId == maxBinId) {
12031
+ chunkedFeesAndRewards.push({
12032
+ minBinId: positionBinData.binId - count + 1,
12033
+ maxBinId: positionBinData.binId,
12034
+ feeXAmount: totalFeeXAmount,
12035
+ feeYAmount: totalFeeYAmount,
12036
+ rewardAmounts: totalRewardAmounts,
12037
+ amountX: totalAmountX,
12038
+ amountY: totalAmountY
12039
+ });
12040
+ totalFeeXAmount = new BN9(0);
12041
+ totalFeeYAmount = new BN9(0);
12042
+ totalAmountX = new BN9(0);
12043
+ totalAmountY = new BN9(0);
12044
+ totalRewardAmounts = [new BN9(0), new BN9(0)];
12045
+ count = 0;
12046
+ }
12047
+ }
12048
+ return chunkedFeesAndRewards;
12049
+ }
12050
+ function calculatePositionSize(binCount) {
12051
+ const extraBinCount = binCount.gt(DEFAULT_BIN_PER_POSITION) ? binCount.sub(DEFAULT_BIN_PER_POSITION) : new BN9(0);
12052
+ return new BN9(POSITION_MIN_SIZE).add(
12053
+ extraBinCount.mul(new BN9(POSITION_BIN_DATA_SIZE))
12054
+ );
12055
+ }
12056
+ function getPositionRentExemption(connection, binCount) {
12057
+ const size = calculatePositionSize(binCount);
12058
+ return connection.getMinimumBalanceForRentExemption(size.toNumber());
12059
+ }
12060
+ async function getPositionExpandRentExemption(currentMinBinId, currentMaxBinId, connection, binCountToExpand) {
12061
+ const currentPositionWidth = currentMaxBinId.sub(currentMinBinId).addn(1);
12062
+ const positionWidthAfterExpand = currentPositionWidth.add(binCountToExpand);
12063
+ if (positionWidthAfterExpand.lte(DEFAULT_BIN_PER_POSITION)) {
12064
+ return 0;
12065
+ } else {
12066
+ const binCountInExpandedBytes = positionWidthAfterExpand.sub(
12067
+ DEFAULT_BIN_PER_POSITION
12068
+ );
12069
+ const expandSize = binCountInExpandedBytes.toNumber() * POSITION_BIN_DATA_SIZE;
12070
+ const [minimumLamports, rentExemptionLamports] = await Promise.all([
12071
+ connection.getMinimumBalanceForRentExemption(0),
12072
+ connection.getMinimumBalanceForRentExemption(expandSize)
12073
+ ]);
12074
+ return rentExemptionLamports - minimumLamports;
12075
+ }
12076
+ }
12077
+ function getExtendedPositionBinCount(minBinId, maxBinId) {
12078
+ const width = maxBinId.sub(minBinId).addn(1);
12079
+ const extended = width.sub(DEFAULT_BIN_PER_POSITION);
12080
+ return extended.lte(new BN9(0)) ? new BN9(0) : extended;
12081
+ }
12082
+ function decodeExtendedPosition(base, program, bytes) {
12083
+ const width = base.upperBinId - base.lowerBinId + 1;
12084
+ const extendedWidth = width - DEFAULT_BIN_PER_POSITION.toNumber();
12085
+ const extendedPosition = [];
12086
+ for (let i = 0; i < extendedWidth; i++) {
12087
+ const offset = i * POSITION_BIN_DATA_SIZE;
12088
+ const data = bytes.subarray(offset, offset + POSITION_BIN_DATA_SIZE);
12089
+ const decodedPositionBinData = program.coder.types.decode(
12090
+ // TODO: Find a type safe way
12091
+ "positionBinData",
12092
+ data
12093
+ );
12094
+ extendedPosition.push(decodedPositionBinData);
12095
+ }
12096
+ return extendedPosition;
12097
+ }
12098
+
12099
+ // src/dlmm/helpers/binArray.ts
12100
+ function internalBitmapRange() {
12101
+ const lowerBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.neg();
12102
+ const upperBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new BN10(1));
12103
+ return [lowerBinArrayIndex, upperBinArrayIndex];
12104
+ }
12105
+ function buildBitmapFromU64Arrays(u64Arrays, type) {
12106
+ const buffer = Buffer.concat(
12107
+ u64Arrays.map((b) => {
12108
+ return b.toArrayLike(Buffer, "le", 8);
12109
+ })
12110
+ );
12111
+ return new BN10(buffer, "le");
12112
+ }
12113
+ function bitmapTypeDetail(type) {
12114
+ if (type == 0 /* U1024 */) {
12115
+ return {
12116
+ bits: 1024,
12117
+ bytes: 1024 / 8
12118
+ };
12119
+ } else {
12120
+ return {
12121
+ bits: 512,
12122
+ bytes: 512 / 8
12123
+ };
12124
+ }
12125
+ }
12126
+ function mostSignificantBit(number, bitLength) {
12127
+ const highestIndex = bitLength - 1;
12128
+ if (number.isZero()) {
12129
+ return null;
12130
+ }
12131
+ for (let i = highestIndex; i >= 0; i--) {
12132
+ if (number.testn(i)) {
12133
+ return highestIndex - i;
12134
+ }
12135
+ }
12136
+ return null;
12137
+ }
12138
+ function leastSignificantBit(number, bitLength) {
12139
+ if (number.isZero()) {
12140
+ return null;
12141
+ }
12142
+ for (let i = 0; i < bitLength; i++) {
12143
+ if (number.testn(i)) {
12144
+ return i;
12145
+ }
12146
+ }
12147
+ return null;
12148
+ }
12149
+ function extensionBitmapRange() {
12150
+ return [
12151
+ BIN_ARRAY_BITMAP_SIZE.neg().mul(
12152
+ EXTENSION_BINARRAY_BITMAP_SIZE.add(new BN10(1))
12153
+ ),
12154
+ BIN_ARRAY_BITMAP_SIZE.mul(
12155
+ EXTENSION_BINARRAY_BITMAP_SIZE.add(new BN10(1))
12156
+ ).sub(new BN10(1))
12157
+ ];
12158
+ }
12159
+ function findSetBit(startIndex, endIndex, binArrayBitmapExtension) {
12160
+ const getBinArrayOffset = (binArrayIndex) => {
12161
+ return binArrayIndex.gt(new BN10(0)) ? binArrayIndex.mod(BIN_ARRAY_BITMAP_SIZE) : binArrayIndex.add(new BN10(1)).neg().mod(BIN_ARRAY_BITMAP_SIZE);
12162
+ };
12163
+ const getBitmapOffset = (binArrayIndex) => {
12164
+ return binArrayIndex.gt(new BN10(0)) ? binArrayIndex.div(BIN_ARRAY_BITMAP_SIZE).sub(new BN10(1)) : binArrayIndex.add(new BN10(1)).neg().div(BIN_ARRAY_BITMAP_SIZE).sub(new BN10(1));
12165
+ };
12166
+ if (startIndex <= endIndex) {
12167
+ for (let i = startIndex; i <= endIndex; i++) {
12168
+ const binArrayOffset = getBinArrayOffset(new BN10(i)).toNumber();
12169
+ const bitmapOffset = getBitmapOffset(new BN10(i)).toNumber();
12170
+ const bitmapChunks = i > 0 ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset] : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];
12171
+ const bitmap = buildBitmapFromU64Arrays(bitmapChunks, 1 /* U512 */);
12172
+ if (bitmap.testn(binArrayOffset)) {
12173
+ return i;
12174
+ }
12175
+ }
12176
+ } else {
12177
+ for (let i = startIndex; i >= endIndex; i--) {
12178
+ const binArrayOffset = getBinArrayOffset(new BN10(i)).toNumber();
12179
+ const bitmapOffset = getBitmapOffset(new BN10(i)).toNumber();
12180
+ const bitmapChunks = i > 0 ? binArrayBitmapExtension.positiveBinArrayBitmap[bitmapOffset] : binArrayBitmapExtension.negativeBinArrayBitmap[bitmapOffset];
12181
+ const bitmap = buildBitmapFromU64Arrays(bitmapChunks, 1 /* U512 */);
12182
+ if (bitmap.testn(binArrayOffset)) {
12183
+ return i;
12184
+ }
12185
+ }
12186
+ }
12187
+ return null;
12188
+ }
12189
+ function isOverflowDefaultBinArrayBitmap(binArrayIndex) {
12190
+ const [minBinArrayIndex, maxBinArrayIndex] = internalBitmapRange();
12191
+ return binArrayIndex.gt(maxBinArrayIndex) || binArrayIndex.lt(minBinArrayIndex);
12192
+ }
12193
+ function deriveBinArrayBitmapExtension(lbPair, programId) {
12194
+ return PublicKey5.findProgramAddressSync(
12195
+ [Buffer.from("bitmap"), lbPair.toBytes()],
12196
+ programId
12197
+ );
12198
+ }
12199
+ function binIdToBinArrayIndex(binId) {
12200
+ const { div: idx, mod } = binId.divmod(MAX_BIN_ARRAY_SIZE);
12201
+ return binId.isNeg() && !mod.isZero() ? idx.sub(new BN10(1)) : idx;
12202
+ }
12203
+ function getBinArrayLowerUpperBinId(binArrayIndex) {
12204
+ const lowerBinId = binArrayIndex.mul(MAX_BIN_ARRAY_SIZE);
12205
+ const upperBinId = lowerBinId.add(MAX_BIN_ARRAY_SIZE).sub(new BN10(1));
12206
+ return [lowerBinId, upperBinId];
12207
+ }
12208
+ function isBinIdWithinBinArray(activeId, binArrayIndex) {
12209
+ const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArrayIndex);
12210
+ return activeId.gte(lowerBinId) && activeId.lte(upperBinId);
12211
+ }
12212
+ function getBinFromBinArray(binId, binArray) {
12213
+ const [lowerBinId, upperBinId] = getBinArrayLowerUpperBinId(binArray.index);
12214
+ let index = 0;
12215
+ if (binId > 0) {
12216
+ index = binId - lowerBinId.toNumber();
12217
+ } else {
12218
+ const delta = upperBinId.toNumber() - binId;
12219
+ index = MAX_BIN_ARRAY_SIZE.toNumber() - delta - 1;
12220
+ }
12221
+ return binArray.bins[index];
12222
+ }
12223
+ function findNextBinArrayIndexWithLiquidity(swapForY, activeId, lbPairState, binArrayBitmapExtension) {
12224
+ const [lowerBinArrayIndex, upperBinArrayIndex] = internalBitmapRange();
12225
+ let startBinArrayIndex = binIdToBinArrayIndex(activeId);
12226
+ while (true) {
12227
+ if (isOverflowDefaultBinArrayBitmap(startBinArrayIndex)) {
12228
+ if (binArrayBitmapExtension === null) {
12229
+ return null;
11945
12230
  }
11946
12231
  const [minBinArrayIndex, maxBinArrayIndex] = extensionBitmapRange();
11947
12232
  if (startBinArrayIndex.isNeg()) {
@@ -11952,18 +12237,18 @@ function findNextBinArrayIndexWithLiquidity(swapForY, activeId, lbPairState, bin
11952
12237
  binArrayBitmapExtension
11953
12238
  );
11954
12239
  if (binArrayIndex !== null) {
11955
- return new BN8(binArrayIndex);
12240
+ return new BN10(binArrayIndex);
11956
12241
  } else {
11957
12242
  return null;
11958
12243
  }
11959
12244
  } else {
11960
12245
  const binArrayIndex = findSetBit(
11961
12246
  startBinArrayIndex.toNumber(),
11962
- BIN_ARRAY_BITMAP_SIZE.neg().sub(new BN8(1)).toNumber(),
12247
+ BIN_ARRAY_BITMAP_SIZE.neg().sub(new BN10(1)).toNumber(),
11963
12248
  binArrayBitmapExtension
11964
12249
  );
11965
12250
  if (binArrayIndex !== null) {
11966
- return new BN8(binArrayIndex);
12251
+ return new BN10(binArrayIndex);
11967
12252
  } else {
11968
12253
  startBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.neg();
11969
12254
  }
@@ -11976,9 +12261,9 @@ function findNextBinArrayIndexWithLiquidity(swapForY, activeId, lbPairState, bin
11976
12261
  binArrayBitmapExtension
11977
12262
  );
11978
12263
  if (binArrayIndex !== null) {
11979
- return new BN8(binArrayIndex);
12264
+ return new BN10(binArrayIndex);
11980
12265
  } else {
11981
- startBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new BN8(1));
12266
+ startBinArrayIndex = BIN_ARRAY_BITMAP_SIZE.sub(new BN10(1));
11982
12267
  }
11983
12268
  } else {
11984
12269
  const binArrayIndex = findSetBit(
@@ -11987,7 +12272,7 @@ function findNextBinArrayIndexWithLiquidity(swapForY, activeId, lbPairState, bin
11987
12272
  binArrayBitmapExtension
11988
12273
  );
11989
12274
  if (binArrayIndex !== null) {
11990
- return new BN8(binArrayIndex);
12275
+ return new BN10(binArrayIndex);
11991
12276
  } else {
11992
12277
  return null;
11993
12278
  }
@@ -12002,22 +12287,22 @@ function findNextBinArrayIndexWithLiquidity(swapForY, activeId, lbPairState, bin
12002
12287
  bitmapType
12003
12288
  );
12004
12289
  if (swapForY) {
12005
- const upperBitRange = new BN8(bitmapDetail.bits - 1).sub(offset);
12290
+ const upperBitRange = new BN10(bitmapDetail.bits - 1).sub(offset);
12006
12291
  const croppedBitmap = bitmap.shln(upperBitRange.toNumber());
12007
12292
  const msb = mostSignificantBit(croppedBitmap, bitmapDetail.bits);
12008
12293
  if (msb !== null) {
12009
- return startBinArrayIndex.sub(new BN8(msb));
12294
+ return startBinArrayIndex.sub(new BN10(msb));
12010
12295
  } else {
12011
- startBinArrayIndex = lowerBinArrayIndex.sub(new BN8(1));
12296
+ startBinArrayIndex = lowerBinArrayIndex.sub(new BN10(1));
12012
12297
  }
12013
12298
  } else {
12014
12299
  const lowerBitRange = offset;
12015
12300
  const croppedBitmap = bitmap.shrn(lowerBitRange.toNumber());
12016
12301
  const lsb = leastSignificantBit(croppedBitmap, bitmapDetail.bits);
12017
12302
  if (lsb !== null) {
12018
- return startBinArrayIndex.add(new BN8(lsb));
12303
+ return startBinArrayIndex.add(new BN10(lsb));
12019
12304
  } else {
12020
- startBinArrayIndex = upperBinArrayIndex.add(new BN8(1));
12305
+ startBinArrayIndex = upperBinArrayIndex.add(new BN10(1));
12021
12306
  }
12022
12307
  }
12023
12308
  }
@@ -12046,9 +12331,9 @@ function getBinArraysRequiredByPositionRange(pair, fromBinId, toBinId, programId
12046
12331
  const positionCount = getPositionCount(minBinId, maxBinId);
12047
12332
  const binArrays = /* @__PURE__ */ new Map();
12048
12333
  for (let i = 0; i < positionCount.toNumber(); i++) {
12049
- const lowerBinId = minBinId.add(DEFAULT_BIN_PER_POSITION.mul(new BN8(i)));
12334
+ const lowerBinId = minBinId.add(DEFAULT_BIN_PER_POSITION.mul(new BN10(i)));
12050
12335
  const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);
12051
- const upperBinArrayIndex = lowerBinArrayIndex.add(new BN8(1));
12336
+ const upperBinArrayIndex = lowerBinArrayIndex.add(new BN10(1));
12052
12337
  const [lowerBinArray] = deriveBinArray(pair, lowerBinArrayIndex, programId);
12053
12338
  const [upperBinArray] = deriveBinArray(pair, upperBinArrayIndex, programId);
12054
12339
  binArrays.set(lowerBinArray.toBase58(), lowerBinArrayIndex);
@@ -12059,6 +12344,17 @@ function getBinArraysRequiredByPositionRange(pair, fromBinId, toBinId, programId
12059
12344
  index
12060
12345
  }));
12061
12346
  }
12347
+ function getBinArraysRequiredByPositionRange2(pair, fromBinId, toBinId, programId) {
12348
+ const [minBinId, maxBinId] = fromBinId.lt(toBinId) ? [fromBinId, toBinId] : [toBinId, fromBinId];
12349
+ const binArrayIndexes = getBinArrayIndexesCoverage(minBinId, maxBinId);
12350
+ return Array.from(binArrayIndexes, (index) => {
12351
+ const [binArrayPubkey] = deriveBinArray(pair, index, programId);
12352
+ return {
12353
+ key: binArrayPubkey,
12354
+ index
12355
+ };
12356
+ });
12357
+ }
12062
12358
  function* enumerateBins(binsById, lowerBinId, upperBinId, binStep, baseTokenDecimal, quoteTokenDecimal, version, lbPair) {
12063
12359
  for (let currentBinId = lowerBinId; currentBinId <= upperBinId; currentBinId++) {
12064
12360
  const bin = binsById.get(currentBinId);
@@ -12108,7 +12404,7 @@ function decodeRewardPerTokenStored(bin) {
12108
12404
  "le",
12109
12405
  8
12110
12406
  );
12111
- const rewardPerTokenStored0 = new BN8(
12407
+ const rewardPerTokenStored0 = new BN10(
12112
12408
  Buffer.concat([rewardPerTokenStored0Buf0, rewardPerTokenStored0Buf1]),
12113
12409
  "le"
12114
12410
  );
@@ -12122,381 +12418,96 @@ function decodeRewardPerTokenStored(bin) {
12122
12418
  "le",
12123
12419
  8
12124
12420
  );
12125
- const rewardPerTokenStored1 = new BN8(
12421
+ const rewardPerTokenStored1 = new BN10(
12126
12422
  Buffer.concat([rewardPerTokenStored1Buf0, rewardPerTokenStored1Buf1]),
12127
12423
  "le"
12128
- );
12129
- return [rewardPerTokenStored0, rewardPerTokenStored1];
12130
- }
12131
- function getBinArrayInfoForNonContiguousBinIds(binIds, programId, lbPair) {
12132
- let binArrayBitmapExtension = programId;
12133
- const binArrayIndexes = /* @__PURE__ */ new Set();
12134
- for (const binId of binIds) {
12135
- const binArrayIndex = binIdToBinArrayIndex(new BN8(binId));
12136
- if (isOverflowDefaultBinArrayBitmap(binArrayIndex) && binArrayBitmapExtension.equals(programId)) {
12137
- binArrayBitmapExtension = deriveBinArrayBitmapExtension(
12138
- lbPair,
12139
- programId
12140
- )[0];
12141
- }
12142
- binArrayIndexes.add(binArrayIndex.toNumber());
12143
- }
12144
- const binArrayPubkeys = [...binArrayIndexes].map(
12145
- (idx) => deriveBinArray(lbPair, new BN8(idx), programId)[0]
12146
- );
12147
- const binArrayAccountMetas = binArrayPubkeys.map((pubkey) => {
12148
- return {
12149
- pubkey,
12150
- isSigner: false,
12151
- isWritable: true
12152
- };
12153
- });
12154
- return {
12155
- binArrayAccountMetas,
12156
- binArrayBitmapExtension,
12157
- binArrayIndexes: [...binArrayIndexes].map((idx) => new BN8(idx))
12158
- };
12159
- }
12160
-
12161
- // src/dlmm/helpers/computeUnit.ts
12162
- import {
12163
- ComputeBudgetProgram,
12164
- PublicKey as PublicKey6,
12165
- TransactionMessage,
12166
- VersionedTransaction
12167
- } from "@solana/web3.js";
12168
- var DEFAULT_ADD_LIQUIDITY_CU = 1e6;
12169
- var DEFAULT_EXTEND_POSITION_HIGH_CU = 1e6;
12170
- var DEFAULT_EXTEND_POSITION_LOW_CU = 3e4;
12171
- var DEFAULT_INIT_POSITION_CU = 3e4;
12172
- var DEFAULT_INIT_BIN_ARRAY_CU = 35e4;
12173
- var MIN_CU_BUFFER = 5e4;
12174
- var MAX_CU_BUFFER = 2e5;
12175
- var MAX_CU = 14e5;
12176
- var getDefaultExtendPositionCU = (side) => {
12177
- switch (side) {
12178
- case 0 /* Lower */:
12179
- return DEFAULT_EXTEND_POSITION_HIGH_CU;
12180
- case 1 /* Upper */:
12181
- return DEFAULT_EXTEND_POSITION_LOW_CU;
12182
- }
12183
- };
12184
- var getSimulationComputeUnits = async (connection, instructions, payer, lookupTables, commitment = "confirmed") => {
12185
- const testInstructions = [
12186
- // Set an arbitrarily high number in simulation
12187
- // so we can be sure the transaction will succeed
12188
- // and get the real compute units used
12189
- ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 }),
12190
- ...instructions
12191
- ];
12192
- const testTransaction = new VersionedTransaction(
12193
- new TransactionMessage({
12194
- instructions: testInstructions,
12195
- payerKey: payer,
12196
- // RecentBlockhash can by any public key during simulation
12197
- // since 'replaceRecentBlockhash' is set to 'true' below
12198
- recentBlockhash: PublicKey6.default.toString()
12199
- }).compileToV0Message(lookupTables)
12200
- );
12201
- const rpcResponse = await connection.simulateTransaction(testTransaction, {
12202
- replaceRecentBlockhash: true,
12203
- sigVerify: false,
12204
- commitment
12205
- });
12206
- if (rpcResponse?.value?.err) {
12207
- const logs = rpcResponse.value.logs?.join("\n \u2022 ") || "No logs available";
12208
- throw new Error(
12209
- `Transaction simulation failed:
12210
- \u2022${logs}` + JSON.stringify(rpcResponse?.value?.err)
12211
- );
12212
- }
12213
- return rpcResponse.value.unitsConsumed || null;
12214
- };
12215
-
12216
- // src/dlmm/helpers/positions/index.ts
12217
- import BN10 from "bn.js";
12218
-
12219
- // src/dlmm/helpers/positions/wrapper.ts
12220
- import BN9 from "bn.js";
12221
- function combineBaseAndExtendedPositionBinData(base, extended) {
12222
- const combinedLiquidityShares = base.liquidityShares;
12223
- const combinedRewardInfos = base.rewardInfos;
12224
- const combinedFeeInfos = base.feeInfos;
12225
- for (const binData of extended) {
12226
- combinedLiquidityShares.push(binData.liquidityShare);
12227
- combinedRewardInfos.push(binData.rewardInfo);
12228
- combinedFeeInfos.push(binData.feeInfo);
12229
- }
12230
- return {
12231
- liquidityShares: combinedLiquidityShares,
12232
- rewardInfos: combinedRewardInfos,
12233
- feeInfos: combinedFeeInfos
12234
- };
12235
- }
12236
- function wrapPosition(program, key, account) {
12237
- const disc = account.data.subarray(0, 8);
12238
- if (disc.equals(Buffer.from(getAccountDiscriminator("positionV2")))) {
12239
- const state = decodeAccount(
12240
- program,
12241
- "positionV2",
12242
- account.data
12243
- );
12244
- const extended = decodeExtendedPosition(
12245
- state,
12246
- program,
12247
- account.data.subarray(8 + POSITION_MIN_SIZE)
12248
- );
12249
- const combinedPositionBinData = combineBaseAndExtendedPositionBinData(
12250
- state,
12251
- extended
12252
- );
12253
- return new PositionV2Wrapper(key, state, extended, combinedPositionBinData);
12254
- } else {
12255
- throw new Error("Unknown position account");
12256
- }
12257
- }
12258
- var PositionV2Wrapper = class {
12259
- constructor(positionAddress, inner, extended, combinedPositionBinData) {
12260
- this.positionAddress = positionAddress;
12261
- this.inner = inner;
12262
- this.extended = extended;
12263
- this.combinedPositionBinData = combinedPositionBinData;
12264
- }
12265
- address() {
12266
- return this.positionAddress;
12267
- }
12268
- totalClaimedRewards() {
12269
- return this.inner.totalClaimedRewards;
12270
- }
12271
- feeOwner() {
12272
- return this.inner.feeOwner;
12273
- }
12274
- lockReleasePoint() {
12275
- return this.inner.lockReleasePoint;
12276
- }
12277
- operator() {
12278
- return this.inner.operator;
12279
- }
12280
- totalClaimedFeeYAmount() {
12281
- return this.inner.totalClaimedFeeYAmount;
12282
- }
12283
- totalClaimedFeeXAmount() {
12284
- return this.inner.totalClaimedFeeXAmount;
12285
- }
12286
- lbPair() {
12287
- return this.inner.lbPair;
12288
- }
12289
- lowerBinId() {
12290
- return new BN9(this.inner.lowerBinId);
12291
- }
12292
- upperBinId() {
12293
- return new BN9(this.inner.upperBinId);
12294
- }
12295
- liquidityShares() {
12296
- return this.combinedPositionBinData.liquidityShares;
12297
- }
12298
- rewardInfos() {
12299
- return this.combinedPositionBinData.rewardInfos;
12300
- }
12301
- feeInfos() {
12302
- return this.combinedPositionBinData.feeInfos;
12303
- }
12304
- lastUpdatedAt() {
12305
- return this.inner.lastUpdatedAt;
12306
- }
12307
- getBinArrayIndexesCoverage() {
12308
- const isExtended = this.extended.length > 0;
12309
- if (isExtended) {
12310
- return getBinArrayIndexesCoverage(this.lowerBinId(), this.upperBinId());
12311
- } else {
12312
- const lowerBinArrayIndex = binIdToBinArrayIndex(this.lowerBinId());
12313
- const upperBinArrayIndex = lowerBinArrayIndex.add(new BN9(1));
12314
- return [lowerBinArrayIndex, upperBinArrayIndex];
12315
- }
12316
- }
12317
- getBinArrayKeysCoverage(programId) {
12318
- return this.getBinArrayIndexesCoverage().map(
12319
- (index) => deriveBinArray(this.lbPair(), index, programId)[0]
12320
- );
12321
- }
12322
- version() {
12323
- return 1 /* V2 */;
12324
- }
12325
- owner() {
12326
- return this.inner.owner;
12327
- }
12328
- width() {
12329
- return this.upperBinId().sub(this.lowerBinId()).add(new BN9(1));
12330
- }
12331
- };
12332
-
12333
- // src/dlmm/helpers/positions/index.ts
12334
- function getBinArrayIndexesCoverage(lowerBinId, upperBinId) {
12335
- const lowerBinArrayIndex = binIdToBinArrayIndex(lowerBinId);
12336
- const upperBinArrayIndex = binIdToBinArrayIndex(upperBinId);
12337
- const binArrayIndexes = [];
12338
- for (let i = lowerBinArrayIndex.toNumber(); i <= upperBinArrayIndex.toNumber(); i++) {
12339
- binArrayIndexes.push(new BN10(i));
12340
- }
12341
- return binArrayIndexes;
12342
- }
12343
- function getBinArrayKeysCoverage(lowerBinId, upperBinId, lbPair, programId) {
12344
- const binArrayIndexes = getBinArrayIndexesCoverage(lowerBinId, upperBinId);
12345
- return binArrayIndexes.map((index) => {
12346
- return deriveBinArray(lbPair, index, programId)[0];
12347
- });
12348
- }
12349
- function getBinArrayAccountMetasCoverage(lowerBinId, upperBinId, lbPair, programId) {
12350
- return getBinArrayKeysCoverage(lowerBinId, upperBinId, lbPair, programId).map(
12351
- (key) => {
12352
- return {
12353
- pubkey: key,
12354
- isSigner: false,
12355
- isWritable: true
12356
- };
12357
- }
12358
- );
12359
- }
12360
- function getPositionLowerUpperBinIdWithLiquidity(position) {
12361
- const binWithLiquidity = position.positionBinData.filter(
12362
- (b) => !new BN10(b.binLiquidity).isZero() || !new BN10(b.positionFeeXAmount.toString()).isZero() || !new BN10(b.positionFeeYAmount.toString()).isZero() || !new BN10(b.positionRewardAmount[0].toString()).isZero() || !new BN10(b.positionRewardAmount[1].toString()).isZero()
12363
- );
12364
- return binWithLiquidity.length > 0 ? {
12365
- lowerBinId: new BN10(binWithLiquidity[0].binId),
12366
- upperBinId: new BN10(binWithLiquidity[binWithLiquidity.length - 1].binId)
12367
- } : null;
12368
- }
12369
- function isPositionNoFee(position) {
12370
- return position.feeX.isZero() && position.feeY.isZero();
12371
- }
12372
- function isPositionNoReward(position) {
12373
- return position.rewardOne.isZero() && position.rewardTwo.isZero();
12374
- }
12375
- function chunkBinRangeIntoExtendedPositions(minBinId, maxBinId) {
12376
- const chunkedBinRange = [];
12377
- for (let currentMinBinId = minBinId; currentMinBinId <= maxBinId; currentMinBinId += POSITION_MAX_LENGTH.toNumber()) {
12378
- const currentMaxBinId = Math.min(
12379
- currentMinBinId + POSITION_MAX_LENGTH.toNumber() - 1,
12380
- maxBinId
12381
- );
12382
- chunkedBinRange.push({
12383
- lowerBinId: currentMinBinId,
12384
- upperBinId: currentMaxBinId
12385
- });
12386
- }
12387
- return chunkedBinRange;
12388
- }
12389
- function chunkBinRange(minBinId, maxBinId, binPerChunk) {
12390
- const chunkedBinRange = [];
12391
- let startBinId = minBinId;
12392
- binPerChunk = binPerChunk ?? DEFAULT_BIN_PER_POSITION.toNumber();
12393
- while (startBinId <= maxBinId) {
12394
- const endBinId = Math.min(startBinId + binPerChunk - 1, maxBinId);
12395
- chunkedBinRange.push({
12396
- lowerBinId: startBinId,
12397
- upperBinId: endBinId
12398
- });
12399
- startBinId += binPerChunk;
12400
- }
12401
- return chunkedBinRange;
12424
+ );
12425
+ return [rewardPerTokenStored0, rewardPerTokenStored1];
12402
12426
  }
12403
- function chunkPositionBinRange(position, minBinId, maxBinId) {
12404
- const chunkedFeesAndRewards = [];
12405
- let totalAmountX = new BN10(0);
12406
- let totalAmountY = new BN10(0);
12407
- let totalFeeXAmount = new BN10(0);
12408
- let totalFeeYAmount = new BN10(0);
12409
- let totalRewardAmounts = [new BN10(0), new BN10(0)];
12410
- let count = 0;
12411
- for (let i = 0; i < position.positionData.positionBinData.length; i++) {
12412
- const positionBinData = position.positionData.positionBinData[i];
12413
- if (positionBinData.binId >= minBinId && positionBinData.binId <= maxBinId) {
12414
- totalFeeXAmount = totalFeeXAmount.add(
12415
- new BN10(positionBinData.positionFeeXAmount)
12416
- );
12417
- totalFeeYAmount = totalFeeYAmount.add(
12418
- new BN10(positionBinData.positionFeeYAmount)
12419
- );
12420
- totalAmountX = totalAmountX.add(new BN10(positionBinData.positionXAmount));
12421
- totalAmountY = totalAmountY.add(new BN10(positionBinData.positionYAmount));
12422
- for (const [
12423
- index,
12424
- reward
12425
- ] of positionBinData.positionRewardAmount.entries()) {
12426
- totalRewardAmounts[index] = totalRewardAmounts[index].add(
12427
- new BN10(reward)
12428
- );
12429
- }
12430
- count++;
12431
- }
12432
- if (count === DEFAULT_BIN_PER_POSITION.toNumber() || positionBinData.binId == maxBinId) {
12433
- chunkedFeesAndRewards.push({
12434
- minBinId: positionBinData.binId - count + 1,
12435
- maxBinId: positionBinData.binId,
12436
- feeXAmount: totalFeeXAmount,
12437
- feeYAmount: totalFeeYAmount,
12438
- rewardAmounts: totalRewardAmounts,
12439
- amountX: totalAmountX,
12440
- amountY: totalAmountY
12441
- });
12442
- totalFeeXAmount = new BN10(0);
12443
- totalFeeYAmount = new BN10(0);
12444
- totalAmountX = new BN10(0);
12445
- totalAmountY = new BN10(0);
12446
- totalRewardAmounts = [new BN10(0), new BN10(0)];
12447
- count = 0;
12427
+ function getBinArrayInfoForNonContiguousBinIds(binIds, programId, lbPair) {
12428
+ let binArrayBitmapExtension = programId;
12429
+ const binArrayIndexes = /* @__PURE__ */ new Set();
12430
+ for (const binId of binIds) {
12431
+ const binArrayIndex = binIdToBinArrayIndex(new BN10(binId));
12432
+ if (isOverflowDefaultBinArrayBitmap(binArrayIndex) && binArrayBitmapExtension.equals(programId)) {
12433
+ binArrayBitmapExtension = deriveBinArrayBitmapExtension(
12434
+ lbPair,
12435
+ programId
12436
+ )[0];
12448
12437
  }
12438
+ binArrayIndexes.add(binArrayIndex.toNumber());
12449
12439
  }
12450
- return chunkedFeesAndRewards;
12451
- }
12452
- function calculatePositionSize(binCount) {
12453
- const extraBinCount = binCount.gt(DEFAULT_BIN_PER_POSITION) ? binCount.sub(DEFAULT_BIN_PER_POSITION) : new BN10(0);
12454
- return new BN10(POSITION_MIN_SIZE).add(
12455
- extraBinCount.mul(new BN10(POSITION_BIN_DATA_SIZE))
12440
+ const binArrayPubkeys = [...binArrayIndexes].map(
12441
+ (idx) => deriveBinArray(lbPair, new BN10(idx), programId)[0]
12456
12442
  );
12443
+ const binArrayAccountMetas = binArrayPubkeys.map((pubkey) => {
12444
+ return {
12445
+ pubkey,
12446
+ isSigner: false,
12447
+ isWritable: true
12448
+ };
12449
+ });
12450
+ return {
12451
+ binArrayAccountMetas,
12452
+ binArrayBitmapExtension,
12453
+ binArrayIndexes: [...binArrayIndexes].map((idx) => new BN10(idx))
12454
+ };
12457
12455
  }
12458
- function getPositionRentExemption(connection, binCount) {
12459
- const size = calculatePositionSize(binCount);
12460
- return connection.getMinimumBalanceForRentExemption(size.toNumber());
12461
- }
12462
- async function getPositionExpandRentExemption(currentMinBinId, currentMaxBinId, connection, binCountToExpand) {
12463
- const currentPositionWidth = currentMaxBinId.sub(currentMinBinId).addn(1);
12464
- const positionWidthAfterExpand = currentPositionWidth.add(binCountToExpand);
12465
- if (positionWidthAfterExpand.lte(DEFAULT_BIN_PER_POSITION)) {
12466
- return 0;
12467
- } else {
12468
- const binCountInExpandedBytes = positionWidthAfterExpand.sub(
12469
- DEFAULT_BIN_PER_POSITION
12470
- );
12471
- const expandSize = binCountInExpandedBytes.toNumber() * POSITION_BIN_DATA_SIZE;
12472
- const [minimumLamports, rentExemptionLamports] = await Promise.all([
12473
- connection.getMinimumBalanceForRentExemption(0),
12474
- connection.getMinimumBalanceForRentExemption(expandSize)
12475
- ]);
12476
- return rentExemptionLamports - minimumLamports;
12456
+
12457
+ // src/dlmm/helpers/computeUnit.ts
12458
+ import {
12459
+ ComputeBudgetProgram,
12460
+ PublicKey as PublicKey6,
12461
+ TransactionMessage,
12462
+ VersionedTransaction
12463
+ } from "@solana/web3.js";
12464
+ var DEFAULT_ADD_LIQUIDITY_CU = 1e6;
12465
+ var DEFAULT_EXTEND_POSITION_HIGH_CU = 1e6;
12466
+ var DEFAULT_EXTEND_POSITION_LOW_CU = 3e4;
12467
+ var DEFAULT_INIT_POSITION_CU = 3e4;
12468
+ var DEFAULT_INIT_BIN_ARRAY_CU = 35e4;
12469
+ var MIN_CU_BUFFER = 5e4;
12470
+ var MAX_CU_BUFFER = 2e5;
12471
+ var MAX_CU = 14e5;
12472
+ var getDefaultExtendPositionCU = (side) => {
12473
+ switch (side) {
12474
+ case 0 /* Lower */:
12475
+ return DEFAULT_EXTEND_POSITION_HIGH_CU;
12476
+ case 1 /* Upper */:
12477
+ return DEFAULT_EXTEND_POSITION_LOW_CU;
12477
12478
  }
12478
- }
12479
- function getExtendedPositionBinCount(minBinId, maxBinId) {
12480
- const width = maxBinId.sub(minBinId).addn(1);
12481
- const extended = width.sub(DEFAULT_BIN_PER_POSITION);
12482
- return extended.lte(new BN10(0)) ? new BN10(0) : extended;
12483
- }
12484
- function decodeExtendedPosition(base, program, bytes) {
12485
- const width = base.upperBinId - base.lowerBinId + 1;
12486
- const extendedWidth = width - DEFAULT_BIN_PER_POSITION.toNumber();
12487
- const extendedPosition = [];
12488
- for (let i = 0; i < extendedWidth; i++) {
12489
- const offset = i * POSITION_BIN_DATA_SIZE;
12490
- const data = bytes.subarray(offset, offset + POSITION_BIN_DATA_SIZE);
12491
- const decodedPositionBinData = program.coder.types.decode(
12492
- // TODO: Find a type safe way
12493
- "positionBinData",
12494
- data
12479
+ };
12480
+ var getSimulationComputeUnits = async (connection, instructions, payer, lookupTables, commitment = "confirmed") => {
12481
+ const testInstructions = [
12482
+ // Set an arbitrarily high number in simulation
12483
+ // so we can be sure the transaction will succeed
12484
+ // and get the real compute units used
12485
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 14e5 }),
12486
+ ...instructions
12487
+ ];
12488
+ const testTransaction = new VersionedTransaction(
12489
+ new TransactionMessage({
12490
+ instructions: testInstructions,
12491
+ payerKey: payer,
12492
+ // RecentBlockhash can by any public key during simulation
12493
+ // since 'replaceRecentBlockhash' is set to 'true' below
12494
+ recentBlockhash: PublicKey6.default.toString()
12495
+ }).compileToV0Message(lookupTables)
12496
+ );
12497
+ const rpcResponse = await connection.simulateTransaction(testTransaction, {
12498
+ replaceRecentBlockhash: true,
12499
+ sigVerify: false,
12500
+ commitment
12501
+ });
12502
+ if (rpcResponse?.value?.err) {
12503
+ const logs = rpcResponse.value.logs?.join("\n \u2022 ") || "No logs available";
12504
+ throw new Error(
12505
+ `Transaction simulation failed:
12506
+ \u2022${logs}` + JSON.stringify(rpcResponse?.value?.err)
12495
12507
  );
12496
- extendedPosition.push(decodedPositionBinData);
12497
12508
  }
12498
- return extendedPosition;
12499
- }
12509
+ return rpcResponse.value.unitsConsumed || null;
12510
+ };
12500
12511
 
12501
12512
  // src/dlmm/helpers/rebalance/rebalancePosition.ts
12502
12513
  import { SYSVAR_CLOCK_PUBKEY } from "@solana/web3.js";
@@ -16748,6 +16759,242 @@ var DLMM = class {
16748
16759
  }
16749
16760
  return positionsMap;
16750
16761
  }
16762
+ /**
16763
+ * The function `getPositionsByUserAndTokenAddress` retrieves all of a user's positions across every
16764
+ * DLMM pool that includes the given token mint as either the X or Y token.
16765
+ * @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
16766
+ * class, which represents the connection to the Solana blockchain.
16767
+ * @param {PublicKey} userPubKey - The user's wallet public key.
16768
+ * @param {PublicKey} tokenMint - The token mint used to filter pools. Only positions in pools whose
16769
+ * `tokenXMint` or `tokenYMint` matches this mint are returned.
16770
+ * @param {Opt} [opt] - An optional object that contains additional options for the function.
16771
+ * @param {GetPositionsOpt} [getPositionsOpt] - Optional settings for chunked position fetching
16772
+ * @returns The function `getPositionsByUserAndTokenAddress` returns a `Promise` that resolves to a
16773
+ * `Map` object. The `Map` object contains key-value pairs, where the key is a string representing the
16774
+ * LB Pair account, and the value is an object of PositionInfo. Only pools containing `tokenMint` are
16775
+ * included.
16776
+ */
16777
+ static async getPositionsByUserAndTokenAddress(connection, userPubKey, tokenMint, opt, getPositionsOpt) {
16778
+ const allPositions = await DLMM.getAllLbPairPositionsByUser(
16779
+ connection,
16780
+ userPubKey,
16781
+ opt,
16782
+ getPositionsOpt
16783
+ );
16784
+ const targetMint = tokenMint.toBase58();
16785
+ const filteredPositions = /* @__PURE__ */ new Map();
16786
+ for (const [lbPairKey, positionInfo] of allPositions) {
16787
+ const tokenXMint = positionInfo.lbPair.tokenXMint.toBase58();
16788
+ const tokenYMint = positionInfo.lbPair.tokenYMint.toBase58();
16789
+ if (tokenXMint === targetMint || tokenYMint === targetMint) {
16790
+ filteredPositions.set(lbPairKey, positionInfo);
16791
+ }
16792
+ }
16793
+ return filteredPositions;
16794
+ }
16795
+ /**
16796
+ * The function `getLimitOrdersByUserAndTokenAddress` retrieves all of a user's limit orders across
16797
+ * every DLMM pool that includes the given token mint as either the X or Y token.
16798
+ * @param {Connection} connection - The `connection` parameter is an instance of the `Connection`
16799
+ * class, which represents the connection to the Solana blockchain.
16800
+ * @param {PublicKey} userPubKey - The user's wallet public key.
16801
+ * @param {PublicKey} tokenMint - The token mint used to filter pools. Only limit orders in pools
16802
+ * whose `tokenXMint` or `tokenYMint` matches this mint are returned.
16803
+ * @param {Opt} [opt] - An optional object that contains additional options for the function.
16804
+ * @returns The function `getLimitOrdersByUserAndTokenAddress` returns a `Promise` that resolves to a
16805
+ * `Map` object keyed by LB Pair account (base58), where each value is a `LimitOrderInfo` containing
16806
+ * the LB pair state, token reserves, and the parsed limit orders for that pool.
16807
+ */
16808
+ static async getLimitOrdersByUserAndTokenAddress(connection, userPubKey, tokenMint, opt) {
16809
+ const program = createProgram(connection, opt);
16810
+ const limitOrderAccounts = await chunkedGetProgramAccounts(
16811
+ program.provider.connection,
16812
+ program.programId,
16813
+ [limitOrderFilter(), limitOrderOwnerFilter(userPubKey)]
16814
+ );
16815
+ const limitOrderWrappers = limitOrderAccounts.map(
16816
+ ({ pubkey, account }) => wrapLimitOrder(program, pubkey, account)
16817
+ );
16818
+ if (limitOrderWrappers.length === 0) {
16819
+ return /* @__PURE__ */ new Map();
16820
+ }
16821
+ const lbPairKeys = Array.from(
16822
+ new Set(limitOrderWrappers.map((lo) => lo.lbPair().toBase58()))
16823
+ ).map((key) => new PublicKey10(key));
16824
+ const lbPairAccInfos = await chunkedGetMultipleAccountInfos(
16825
+ connection,
16826
+ lbPairKeys
16827
+ );
16828
+ const lbPairMap = /* @__PURE__ */ new Map();
16829
+ lbPairKeys.forEach((lbPairPubkey, i) => {
16830
+ const accInfo = lbPairAccInfos[i];
16831
+ if (!accInfo) {
16832
+ throw new Error(`LB Pair account ${lbPairPubkey.toBase58()} not found`);
16833
+ }
16834
+ lbPairMap.set(
16835
+ lbPairPubkey.toBase58(),
16836
+ decodeAccount(program, "lbPair", accInfo.data)
16837
+ );
16838
+ });
16839
+ const targetMint = tokenMint.toBase58();
16840
+ const matchingLbPairKeys = lbPairKeys.filter((lbPairPubkey) => {
16841
+ const lbPairState = lbPairMap.get(lbPairPubkey.toBase58());
16842
+ return lbPairState.tokenXMint.toBase58() === targetMint || lbPairState.tokenYMint.toBase58() === targetMint;
16843
+ });
16844
+ if (matchingLbPairKeys.length === 0) {
16845
+ return /* @__PURE__ */ new Map();
16846
+ }
16847
+ const matchingLbPairSet = new Set(
16848
+ matchingLbPairKeys.map((key) => key.toBase58())
16849
+ );
16850
+ const matchingLimitOrders = limitOrderWrappers.filter(
16851
+ (lo) => matchingLbPairSet.has(lo.lbPair().toBase58())
16852
+ );
16853
+ const reserveAndMintKeys = matchingLbPairKeys.map((lbPairPubkey) => {
16854
+ const { reserveX, reserveY, tokenXMint, tokenYMint } = lbPairMap.get(
16855
+ lbPairPubkey.toBase58()
16856
+ );
16857
+ return [reserveX, reserveY, tokenXMint, tokenYMint];
16858
+ }).flat();
16859
+ const binArrayPubkeySet = /* @__PURE__ */ new Set();
16860
+ matchingLimitOrders.forEach((lo) => {
16861
+ lo.getBinArrayKeysCoverage(program.programId).forEach((key) => {
16862
+ binArrayPubkeySet.add(key.toBase58());
16863
+ });
16864
+ });
16865
+ const binArrayKeys = Array.from(binArrayPubkeySet).map(
16866
+ (key) => new PublicKey10(key)
16867
+ );
16868
+ const [clockAccInfo, ...rest] = await chunkedGetMultipleAccountInfos(
16869
+ connection,
16870
+ [SYSVAR_CLOCK_PUBKEY2, ...binArrayKeys, ...reserveAndMintKeys]
16871
+ );
16872
+ const binArraysAccInfo = rest.slice(0, binArrayKeys.length);
16873
+ const reserveAndMintAccInfo = rest.slice(binArrayKeys.length);
16874
+ const clock = ClockLayout.decode(clockAccInfo.data);
16875
+ const binArrayMap = /* @__PURE__ */ new Map();
16876
+ binArrayKeys.forEach((binArrayPubkey, i) => {
16877
+ const accInfo = binArraysAccInfo[i];
16878
+ if (accInfo) {
16879
+ binArrayMap.set(
16880
+ binArrayPubkey.toBase58(),
16881
+ decodeAccount(program, "binArray", accInfo.data)
16882
+ );
16883
+ }
16884
+ });
16885
+ const seenMints = /* @__PURE__ */ new Set();
16886
+ const mintsWithAccount = matchingLbPairKeys.flatMap((lbPairPubkey, idx) => {
16887
+ const { tokenXMint, tokenYMint } = lbPairMap.get(
16888
+ lbPairPubkey.toBase58()
16889
+ );
16890
+ const index = idx * 4;
16891
+ return [
16892
+ {
16893
+ mintAddress: tokenXMint,
16894
+ mintAccountInfo: reserveAndMintAccInfo[index + 2]
16895
+ },
16896
+ {
16897
+ mintAddress: tokenYMint,
16898
+ mintAccountInfo: reserveAndMintAccInfo[index + 3]
16899
+ }
16900
+ ];
16901
+ }).filter(({ mintAddress, mintAccountInfo }) => {
16902
+ if (!mintAccountInfo || seenMints.has(mintAddress.toBase58())) {
16903
+ return false;
16904
+ }
16905
+ seenMints.add(mintAddress.toBase58());
16906
+ return true;
16907
+ });
16908
+ const mintHookAccountsMap = await getMultipleMintsExtraAccountMetasForTransferHook(
16909
+ connection,
16910
+ mintsWithAccount
16911
+ );
16912
+ const lbPairTokenMap = /* @__PURE__ */ new Map();
16913
+ matchingLbPairKeys.forEach((lbPairPubkey, idx) => {
16914
+ const index = idx * 4;
16915
+ const reserveXAccount = reserveAndMintAccInfo[index];
16916
+ const reserveYAccount = reserveAndMintAccInfo[index + 1];
16917
+ const mintXAccount = reserveAndMintAccInfo[index + 2];
16918
+ const mintYAccount = reserveAndMintAccInfo[index + 3];
16919
+ if (!reserveXAccount || !reserveYAccount) {
16920
+ throw new Error(
16921
+ `Reserve account for LB Pair ${lbPairPubkey.toBase58()} not found`
16922
+ );
16923
+ }
16924
+ if (!mintXAccount || !mintYAccount) {
16925
+ throw new Error(
16926
+ `Mint account for LB Pair ${lbPairPubkey.toBase58()} not found`
16927
+ );
16928
+ }
16929
+ const lbPairState = lbPairMap.get(lbPairPubkey.toBase58());
16930
+ const reserveAccX = AccountLayout.decode(reserveXAccount.data);
16931
+ const reserveAccY = AccountLayout.decode(reserveYAccount.data);
16932
+ const mintX = unpackMint2(
16933
+ reserveAccX.mint,
16934
+ mintXAccount,
16935
+ mintXAccount.owner
16936
+ );
16937
+ const mintY = unpackMint2(
16938
+ reserveAccY.mint,
16939
+ mintYAccount,
16940
+ mintYAccount.owner
16941
+ );
16942
+ const { tokenXProgram, tokenYProgram } = getTokenProgramId(lbPairState);
16943
+ const tokenX = {
16944
+ publicKey: lbPairState.tokenXMint,
16945
+ reserve: lbPairState.reserveX,
16946
+ amount: reserveAccX.amount,
16947
+ mint: mintX,
16948
+ owner: tokenXProgram,
16949
+ transferHookAccountMetas: mintHookAccountsMap.get(lbPairState.tokenXMint.toBase58()) ?? []
16950
+ };
16951
+ const tokenY = {
16952
+ publicKey: lbPairState.tokenYMint,
16953
+ reserve: lbPairState.reserveY,
16954
+ amount: reserveAccY.amount,
16955
+ mint: mintY,
16956
+ owner: tokenYProgram,
16957
+ transferHookAccountMetas: mintHookAccountsMap.get(lbPairState.tokenYMint.toBase58()) ?? []
16958
+ };
16959
+ lbPairTokenMap.set(lbPairPubkey.toBase58(), {
16960
+ tokenX,
16961
+ tokenY,
16962
+ mintX,
16963
+ mintY
16964
+ });
16965
+ });
16966
+ const limitOrdersMap = /* @__PURE__ */ new Map();
16967
+ for (const lo of matchingLimitOrders) {
16968
+ const lbPairKey = lo.lbPair().toBase58();
16969
+ const lbPairState = lbPairMap.get(lbPairKey);
16970
+ const { tokenX, tokenY, mintX, mintY } = lbPairTokenMap.get(lbPairKey);
16971
+ const parsedLo = lo.parseInfo(
16972
+ program.programId,
16973
+ lbPairState,
16974
+ mintX,
16975
+ mintY,
16976
+ clock,
16977
+ binArrayMap
16978
+ );
16979
+ const entry = {
16980
+ publicKey: lo.address(),
16981
+ limitOrderData: parsedLo
16982
+ };
16983
+ const existing = limitOrdersMap.get(lbPairKey);
16984
+ if (existing) {
16985
+ existing.limitOrders.push(entry);
16986
+ } else {
16987
+ limitOrdersMap.set(lbPairKey, {
16988
+ publicKey: lo.lbPair(),
16989
+ lbPair: lbPairState,
16990
+ tokenX,
16991
+ tokenY,
16992
+ limitOrders: [entry]
16993
+ });
16994
+ }
16995
+ }
16996
+ return limitOrdersMap;
16997
+ }
16751
16998
  static getPricePerLamport(tokenXDecimal, tokenYDecimal, price) {
16752
16999
  return new Decimal11(price).mul(new Decimal11(10 ** (tokenYDecimal - tokenXDecimal))).toString();
16753
17000
  }
@@ -23018,6 +23265,7 @@ export {
23018
23265
  getBinArrayKeysCoverage,
23019
23266
  getBinArrayLowerUpperBinId,
23020
23267
  getBinArraysRequiredByPositionRange,
23268
+ getBinArraysRequiredByPositionRange2,
23021
23269
  getBinCount,
23022
23270
  getBinFromBinArray,
23023
23271
  getBinIdIndexInBinArray,