@hawksightco/hawk-sdk 1.3.236 → 1.3.238

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.
@@ -46,6 +46,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.txgen = exports.Transactions = void 0;
49
+ exports.getHybridChunkOffsets = getHybridChunkOffsets;
50
+ exports.batchHybridChunkInstructionGroups = batchHybridChunkInstructionGroups;
49
51
  const errors_1 = require("../errors");
50
52
  const dlmm_1 = require("@meteora-ag/dlmm");
51
53
  const web3 = __importStar(require("@solana/web3.js"));
@@ -70,6 +72,53 @@ const anchor = __importStar(require("@coral-xyz/anchor"));
70
72
  const RaydiumIxGenerator_1 = require("../ixGenerator/RaydiumIxGenerator");
71
73
  const RaydiumSDK_1 = require("./RaydiumSDK");
72
74
  const types_3 = require("../types");
75
+ function getHybridChunkOffsets(positionLowerBinId, chunkLowerBinId, chunkUpperBinId) {
76
+ return {
77
+ chunkLowerOffset: chunkLowerBinId - positionLowerBinId,
78
+ chunkUpperOffset: chunkUpperBinId - positionLowerBinId,
79
+ };
80
+ }
81
+ function getInstructionDedupKey(ix) {
82
+ return [
83
+ ix.programId.toString(),
84
+ ix.data.toString('base64'),
85
+ ...ix.keys.map(meta => [
86
+ meta.pubkey.toString(),
87
+ meta.isSigner ? '1' : '0',
88
+ meta.isWritable ? '1' : '0',
89
+ ].join(':')),
90
+ ].join('|');
91
+ }
92
+ function dedupeInitBinArrayInstructions(ixs) {
93
+ const seenInitKeys = new Set();
94
+ const deduped = [];
95
+ for (const ix of ixs) {
96
+ if (ix.label !== 'init_bin_array') {
97
+ deduped.push(ix);
98
+ continue;
99
+ }
100
+ const dedupKey = getInstructionDedupKey(ix.instruction);
101
+ if (seenInitKeys.has(dedupKey)) {
102
+ continue;
103
+ }
104
+ seenInitKeys.add(dedupKey);
105
+ deduped.push(ix);
106
+ }
107
+ return deduped;
108
+ }
109
+ function batchHybridChunkInstructionGroups(chunkInstructionGroups, chunksPerTransaction = 2) {
110
+ if (!Number.isInteger(chunksPerTransaction) || chunksPerTransaction <= 0) {
111
+ throw new Error('chunksPerTransaction must be a positive integer');
112
+ }
113
+ const batchedGroups = [];
114
+ for (let i = 0; i < chunkInstructionGroups.length; i += chunksPerTransaction) {
115
+ const mergedGroup = chunkInstructionGroups
116
+ .slice(i, i + chunksPerTransaction)
117
+ .flat();
118
+ batchedGroups.push(dedupeInitBinArrayInstructions(mergedGroup));
119
+ }
120
+ return batchedGroups;
121
+ }
73
122
  class Transactions {
74
123
  /**
75
124
  * Prohibit creating instance other than getInstance
@@ -1703,70 +1752,6 @@ class Transactions {
1703
1752
  }
1704
1753
  });
1705
1754
  }
1706
- /**
1707
- *
1708
- * @param connection The Solana web3 connection object for blockchain interactions.
1709
- * @param params Parameters required for rebalance
1710
- * @returns A ResponseWithStatus containing TransactionMetadataResponse.
1711
- */
1712
- rebalanceAutomationIx(_a) {
1713
- return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1714
- const program = yield meteora_1.MeteoraDLMM.program(connection);
1715
- const position = yield program.account.positionV2.fetch(params.currentPosition);
1716
- const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, position.lbPair, this.ix);
1717
- const userPda = (0, functions_1.generateUserPda)(params.userWallet);
1718
- // Step 1: Claim all fees/rewards, remove all liquidity and close current position
1719
- const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
1720
- const userPosition = userPositions.find(userPosition => userPosition.publicKey.equals(params.currentPosition));
1721
- if (userPosition === undefined) {
1722
- throw new Error(`Position: ${params.currentPosition} does not exist.`);
1723
- }
1724
- const binIdsToRemove = userPosition.positionData.positionBinData.map(bin => bin.binId);
1725
- const removeLiquidityBuilder = yield dlmmPool.removeLiquidity(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1726
- user: userPda,
1727
- position: params.currentPosition,
1728
- fromBinId: position.lowerBinId,
1729
- toBinId: position.upperBinId,
1730
- bps: new bn_js_1.default(10000),
1731
- shouldClaimAndClose: true,
1732
- }, hsToMeteora_1.meteoraToHawksightAutomationIxs);
1733
- if (params.useAta) {
1734
- removeLiquidityBuilder.replaceClaimFeeTokenToATA();
1735
- removeLiquidityBuilder.replaceClaimRewardToATA();
1736
- }
1737
- else {
1738
- removeLiquidityBuilder.replaceClaimFeeTokenToSTA();
1739
- removeLiquidityBuilder.replaceClaimRewardToSTA();
1740
- }
1741
- // Re-deposit fees (TODO: How to re-deposit reward tokens that is not X or Y token?)
1742
- const initPositionAndAddLiquidityBuilder = yield dlmmPool.initializePositionAndAddLiquidityByStrategy(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1743
- positionPubKey: params.newPosition,
1744
- user: userPda,
1745
- totalXAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1746
- totalYAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1747
- strategy: {
1748
- maxBinId: params.binRange.upperRange,
1749
- minBinId: params.binRange.lowerRange,
1750
- strategyType: types_3.StrategyTypeMap[params.distribution],
1751
- },
1752
- skipInputTokenCheck: true, // Rebalance should be independent of user wallet TA
1753
- }, hsToMeteora_1.meteoraToHawksightAutomationIxs);
1754
- const mainInstructions = [
1755
- // Initialize required ATA
1756
- ...removeLiquidityBuilder.createAtaIxs,
1757
- // Remove liquidity
1758
- ...removeLiquidityBuilder.mainIxs,
1759
- // Re-deposit liquidity
1760
- ...initPositionAndAddLiquidityBuilder.mainIxs,
1761
- ];
1762
- return (0, functions_1.createTransactionMeta)({
1763
- payer: params.userWallet,
1764
- description: 'Automation IX: Meteora Auto-rebalance instructions (Close position and deposit to new position)',
1765
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1766
- mainInstructions,
1767
- });
1768
- });
1769
- }
1770
1755
  /**
1771
1756
  *
1772
1757
  * @param connection The Solana web3 connection object for blockchain interactions.
@@ -1858,246 +1843,6 @@ class Transactions {
1858
1843
  }
1859
1844
  });
1860
1845
  }
1861
- /**
1862
- * Rebalance a Meteora DLMM position with hybrid liquidity support.
1863
- *
1864
- * Supports two modes:
1865
- * - Simple mode: Single distribution (same as rebalanceAutomationIx2)
1866
- * - Hybrid mode: Multiple liquidity layers with per-side distribution control
1867
- *
1868
- * Simple mode (1 TX): Remove + close + init + deposit (same as Ixs2)
1869
- * Hybrid mode (2 TXs):
1870
- * TX1: Remove liquidity + claim fees/rewards + close position
1871
- * TX2: Init new position + deposit layer 1 (static amounts) + deposit layer 2 (sweep remaining)
1872
- */
1873
- rebalanceAutomationIx3(_a) {
1874
- return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1875
- var _b, _c;
1876
- try {
1877
- // --- Validate and normalize layers ---
1878
- let layers;
1879
- if (params.distribution && !params.layers) {
1880
- layers = [
1881
- {
1882
- distribution: params.distribution,
1883
- percentageX: 100,
1884
- percentageY: 100,
1885
- },
1886
- ];
1887
- }
1888
- else if (params.layers && !params.distribution) {
1889
- layers = params.layers;
1890
- }
1891
- else {
1892
- throw new Error('Provide either distribution or layers, not both');
1893
- }
1894
- if (layers.length === 0 || layers.length > 3) {
1895
- throw new Error('layers must have 1-3 entries');
1896
- }
1897
- const sumX = layers.reduce((s, l) => s + l.percentageX, 0);
1898
- const sumY = layers.reduce((s, l) => s + l.percentageY, 0);
1899
- if (sumX !== 100 || sumY !== 100) {
1900
- throw new Error(`Layer percentages must sum to 100 per side (got X=${sumX}, Y=${sumY})`);
1901
- }
1902
- // --- Build labeled instructions ---
1903
- const program = yield meteora_1.MeteoraDLMM.program(connection);
1904
- const positionOnChain = yield program.account.positionV2.fetch(params.currentPosition);
1905
- const lbPair = positionOnChain.lbPair;
1906
- const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
1907
- const userPda = (0, functions_1.generateUserPda)(params.userWallet);
1908
- // Get position data for amount estimates and bin range
1909
- const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
1910
- const userPosition = userPositions.find(p => p.publicKey.equals(params.currentPosition));
1911
- if (!userPosition) {
1912
- throw new Error(`Position: ${params.currentPosition} does not exist.`);
1913
- }
1914
- const currentLowerBinId = userPosition.positionData.lowerBinId;
1915
- const currentUpperBinId = userPosition.positionData.upperBinId;
1916
- const lbPairState = dlmmPool.dlmm.lbPair;
1917
- const tokenXMint = lbPairState.tokenXMint;
1918
- const tokenYMint = lbPairState.tokenYMint;
1919
- const rewardInfos = lbPairState.rewardInfos;
1920
- const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [
1921
- tokenXMint,
1922
- tokenYMint,
1923
- ]);
1924
- const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
1925
- const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
1926
- const remainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
1927
- const pdaTokenTypeForClaimables = params.useAta
1928
- ? types_1.TokenType.ATA
1929
- : types_1.TokenType.STA;
1930
- // Estimate total X/Y from position data (liquidity + fees)
1931
- const estimatedTotalX = new bn_js_1.default(userPosition.positionData.totalXAmount).add(userPosition.positionData.feeX);
1932
- const estimatedTotalY = new bn_js_1.default(userPosition.positionData.totalYAmount).add(userPosition.positionData.feeY);
1933
- const instructions = [];
1934
- const labels = [];
1935
- const removeLiquidityIx = yield this.ix.meteoraDlmm.removeLiquidityByRange2Automation({
1936
- connection,
1937
- userWallet: params.userWallet,
1938
- lbPair,
1939
- position: params.currentPosition,
1940
- tokenXMint,
1941
- tokenYMint,
1942
- tokenXProgram,
1943
- tokenYProgram,
1944
- fromBinId: currentLowerBinId,
1945
- toBinId: currentUpperBinId,
1946
- bpsToRemove: 10000,
1947
- pdaTokenType: types_1.TokenType.ATA,
1948
- remainingAccountsInfo,
1949
- });
1950
- instructions.push(removeLiquidityIx);
1951
- labels.push('remove');
1952
- const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2Automation(connection, {
1953
- userWallet: params.userWallet,
1954
- lbPair,
1955
- position: params.currentPosition,
1956
- tokenMintX: tokenXMint,
1957
- tokenMintY: tokenYMint,
1958
- tokenProgramX: tokenXProgram,
1959
- tokenProgramY: tokenYProgram,
1960
- lowerBinId: currentLowerBinId,
1961
- upperBinId: currentUpperBinId,
1962
- pdaTokenType: pdaTokenTypeForClaimables,
1963
- remainingAccountsInfo,
1964
- });
1965
- instructions.push(claimFeeIx);
1966
- labels.push('claim_fee');
1967
- for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
1968
- const rewardInfo = rewardInfos[rewardIndex];
1969
- if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default))
1970
- continue;
1971
- const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [rewardInfo.mint]);
1972
- const rewardTokenProgram = rewardTokenProgramMap[rewardInfo.mint.toString()];
1973
- const rewardRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, rewardInfo.mint, rewardTokenProgram);
1974
- const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2Automation(connection, {
1975
- userWallet: params.userWallet,
1976
- lbPair,
1977
- position: params.currentPosition,
1978
- rewardIndex,
1979
- rewardMint: rewardInfo.mint,
1980
- rewardVault: rewardInfo.vault,
1981
- tokenProgram: rewardTokenProgram,
1982
- lowerBinId: currentLowerBinId,
1983
- upperBinId: currentUpperBinId,
1984
- pdaTokenType: types_1.TokenType.STA,
1985
- remainingAccountsInfo: rewardRemainingAccountsInfo,
1986
- });
1987
- instructions.push(claimRewardIx);
1988
- labels.push('claim_reward');
1989
- }
1990
- const closePositionIx = yield this.ix.meteoraDlmm.closePosition2Automation({
1991
- connection,
1992
- userWallet: params.userWallet,
1993
- position: params.currentPosition,
1994
- lbPair,
1995
- });
1996
- instructions.push(closePositionIx);
1997
- labels.push('close');
1998
- // Find the last layer index that has non-zero percentage for X and Y
1999
- let lastActiveXIndex = -1;
2000
- let lastActiveYIndex = -1;
2001
- for (let i = layers.length - 1; i >= 0; i--) {
2002
- if (lastActiveXIndex === -1 && layers[i].percentageX > 0)
2003
- lastActiveXIndex = i;
2004
- if (lastActiveYIndex === -1 && layers[i].percentageY > 0)
2005
- lastActiveYIndex = i;
2006
- }
2007
- // Helper to compute optional amounts for a layer
2008
- const computeAmounts = (layer, i) => {
2009
- let optionalTokenXAmount;
2010
- let optionalTokenYAmount;
2011
- if (layer.percentageX === 0) {
2012
- optionalTokenXAmount = new bn_js_1.default(0);
2013
- }
2014
- else if (i === lastActiveXIndex) {
2015
- optionalTokenXAmount = undefined; // sweep remaining
2016
- }
2017
- else {
2018
- optionalTokenXAmount = estimatedTotalX
2019
- .mul(new bn_js_1.default(layer.percentageX))
2020
- .div(new bn_js_1.default(100));
2021
- }
2022
- if (layer.percentageY === 0) {
2023
- optionalTokenYAmount = new bn_js_1.default(0);
2024
- }
2025
- else if (i === lastActiveYIndex) {
2026
- optionalTokenYAmount = undefined; // sweep remaining
2027
- }
2028
- else {
2029
- optionalTokenYAmount = estimatedTotalY
2030
- .mul(new bn_js_1.default(layer.percentageY))
2031
- .div(new bn_js_1.default(100));
2032
- }
2033
- return { optionalTokenXAmount, optionalTokenYAmount };
2034
- };
2035
- // Layer 0: init position + first deposit via relativeOpenAutomation
2036
- const firstLayer = layers[0];
2037
- const firstAmounts = computeAmounts(firstLayer, 0);
2038
- const firstStrategyType = types_3.StrategyTypeMap[firstLayer.distribution];
2039
- const initAndDepositIx = yield this.ix.meteoraDlmm.relativeOpenAutomation(connection, {
2040
- userWallet: params.userWallet,
2041
- lbPair,
2042
- position: params.newPosition,
2043
- relativeLowerBinId: params.relativeBinRange.lowerRange,
2044
- relativeUpperBinId: params.relativeBinRange.upperRange,
2045
- strategyType: firstStrategyType,
2046
- checkRange: {
2047
- minBinId: params.checkRange.lowerRange,
2048
- maxBinId: params.checkRange.upperRange,
2049
- },
2050
- targetActiveBin: (_b = params.targetActiveBin) !== null && _b !== void 0 ? _b : undefined,
2051
- userTokenXAmount: firstAmounts.optionalTokenXAmount,
2052
- userTokenYAmount: firstAmounts.optionalTokenYAmount,
2053
- pdaTokenType: types_1.TokenType.ATA,
2054
- });
2055
- instructions.push(initAndDepositIx);
2056
- labels.push('init');
2057
- // Layers 1+ : deposit-only via addLiquidityByStrategy2Automation
2058
- const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2059
- const effectiveActiveId = (_c = params.targetActiveBin) !== null && _c !== void 0 ? _c : activeId;
2060
- const absLower = effectiveActiveId + params.relativeBinRange.lowerRange;
2061
- const absUpper = effectiveActiveId + params.relativeBinRange.upperRange;
2062
- for (let i = 1; i < layers.length; i++) {
2063
- const layer = layers[i];
2064
- const { optionalTokenXAmount, optionalTokenYAmount } = computeAmounts(layer, i);
2065
- const strategyType = types_3.StrategyTypeMap[layer.distribution];
2066
- const depositIx = yield this.ix.meteoraDlmm.addLiquidityByStrategy2Automation(connection, {
2067
- userWallet: params.userWallet,
2068
- lbPair,
2069
- position: params.newPosition,
2070
- tokenXMint,
2071
- tokenYMint,
2072
- tokenXProgram,
2073
- tokenYProgram,
2074
- activeId: effectiveActiveId,
2075
- maxActiveBinSlippage: 0,
2076
- strategyParametersMinBinId: absLower,
2077
- strategyParametersMaxBinId: absUpper,
2078
- strategyParametersStrategyType: strategyType,
2079
- strategyParametersParameters: new Array(64).fill(0),
2080
- userTokenXAmount: optionalTokenXAmount,
2081
- userTokenYAmount: optionalTokenYAmount,
2082
- remainingAccountsInfo,
2083
- pdaTokenType: types_1.TokenType.ATA,
2084
- });
2085
- instructions.push(depositIx);
2086
- labels.push('deposit');
2087
- }
2088
- return { instructions, labels };
2089
- }
2090
- catch (error) {
2091
- console.error('=== REBALANCE AUTOMATION IX3 ERROR ===');
2092
- console.error('Error type:', error instanceof Error ? error.constructor.name : typeof error);
2093
- console.error('Error message:', error instanceof Error ? error.message : String(error));
2094
- console.error('Error stack:', error instanceof Error ? error.stack : 'No stack trace');
2095
- console.error('Full error object:', error);
2096
- console.error('=== END ERROR LOG ===');
2097
- throw error;
2098
- }
2099
- });
2100
- }
2101
1846
  rebalanceSmallPositionAutomation(_a) {
2102
1847
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2103
1848
  // Current theoretical limit (149-bin)
@@ -2841,98 +2586,6 @@ class Transactions {
2841
2586
  }
2842
2587
  });
2843
2588
  }
2844
- /**
2845
- * Generates a single rebalanceLiquidityAutomation instruction for reshaping a Meteora DLMM position.
2846
- *
2847
- * This is a low-level building block that creates ONE instruction to:
2848
- * - Remove liquidity from specified bins (removeLiquidityParams)
2849
- * - Add liquidity to new bins (addLiquidityParams)
2850
- *
2851
- * Unlike meteoraRebalanceLargePositionAutomation2 which handles full position reshaping
2852
- * with chunking and multiple TXs, this function returns a single instruction that can
2853
- * be composed into custom transaction flows.
2854
- *
2855
- * Features:
2856
- * - Token2022 transfer hook support
2857
- * - No fee/reward claiming (shouldClaimFee: false, shouldClaimReward: false)
2858
- * - Uses ATA token accounts
2859
- * - NoShrinkBoth shrink mode
2860
- *
2861
- * Note: Not part of test suite yet. For remove + add liquidity params, please fork
2862
- * hawk-api/src/meteora/liquidityStrategy.ts to generate the parameters.
2863
- *
2864
- * @param connection Solana web3 connection
2865
- * @param params Reshape parameters including position, bin ranges, and liquidity params
2866
- * @returns LabeledInstructions with single 'rebalance_liquidity' instruction
2867
- */
2868
- meteoraReshapePositionAutomation(_a) {
2869
- return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2870
- var _b, _c;
2871
- // Fetch pool data
2872
- const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.lbPair, this.ix);
2873
- const lbPairState = dlmmPool.dlmm.lbPair;
2874
- const tokenXMint = lbPairState.tokenXMint;
2875
- const tokenYMint = lbPairState.tokenYMint;
2876
- const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [
2877
- tokenXMint,
2878
- tokenYMint,
2879
- ]);
2880
- const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
2881
- const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
2882
- // Fetch transfer hook accounts for token X and Y (Token2022 support)
2883
- const baseRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2884
- // Build combined remainingAccountsInfo with transfer hooks for X, Y, and rewards
2885
- // The slices describe: TransferHookX, TransferHookY, TransferHookMultiReward(index) for each reward
2886
- // IMPORTANT: Always include all slices, even with length=0, so Meteora knows the account structure
2887
- const combinedSlices = [];
2888
- const combinedAccounts = [];
2889
- // Always add TransferHookX and TransferHookY slices (even if length=0)
2890
- const xSlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookX);
2891
- const ySlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookY);
2892
- combinedSlices.push({
2893
- accountsType: types_1.RemainingAccountsType.TransferHookX,
2894
- length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0,
2895
- });
2896
- combinedSlices.push({
2897
- accountsType: types_1.RemainingAccountsType.TransferHookY,
2898
- length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0,
2899
- });
2900
- // Add transfer hook accounts from base (for X and Y)
2901
- combinedAccounts.push(...baseRemainingAccountsInfo.accounts);
2902
- const remainingAccountsInfo = {
2903
- slices: combinedSlices,
2904
- accounts: combinedAccounts,
2905
- };
2906
- return {
2907
- instructions: [
2908
- yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2909
- connection,
2910
- userWallet: params.userWallet,
2911
- position: params.position,
2912
- lbPair: params.lbPair,
2913
- tokenXMint,
2914
- tokenYMint,
2915
- tokenXProgram,
2916
- tokenYProgram,
2917
- activeId: params.activeId,
2918
- pdaTokenType: types_1.TokenType.ATA,
2919
- maxActiveBinSlippage: 0,
2920
- shouldClaimFee: false,
2921
- shouldClaimReward: false,
2922
- minWithdrawXAmount: new bn_js_1.default(0),
2923
- maxDepositXAmount: new bn_js_1.default(0),
2924
- minWithdrawYAmount: new bn_js_1.default(0),
2925
- maxDepositYAmount: new bn_js_1.default(0),
2926
- removeLiquidityParams: params.removeLiquidityParams,
2927
- addLiquidityParams: params.addLiquidityParams,
2928
- shrinkMode: types_3.ShrinkMode.NoShrinkBoth,
2929
- remainingAccountsInfo,
2930
- }),
2931
- ],
2932
- labels: ['rebalance_liquidity'],
2933
- };
2934
- });
2935
- }
2936
2589
  /**
2937
2590
  * Compute claimable fees for a position directly from on-chain account data.
2938
2591
  * Avoids expensive getPositionsByUserAndLbPair by parsing raw buffers.
@@ -4437,16 +4090,21 @@ class Transactions {
4437
4090
  }
4438
4091
  for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
4439
4092
  const chunk = chunks[chunkIndex];
4440
- const mergedLayer = chunk.layers.reduce((acc, l) => ({
4441
- x0: acc.x0.add(l.params.x0),
4442
- y0: acc.y0.add(l.params.y0),
4443
- deltaX: acc.deltaX.add(l.params.deltaX),
4444
- deltaY: acc.deltaY.add(l.params.deltaY),
4445
- }), { x0: new bn_js_1.default(0), y0: new bn_js_1.default(0), deltaX: new bn_js_1.default(0), deltaY: new bn_js_1.default(0) });
4446
- const onChainParams = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(mergedLayer.x0, mergedLayer.y0, mergedLayer.deltaX, mergedLayer.deltaY);
4447
- const mergedBinsAmounts = (0, liquidityStrategy_1.toAmountIntoBins)(new bn_js_1.default(activeId), chunk.minDeltaId, chunk.maxDeltaId, mergedLayer.deltaX, mergedLayer.deltaY, mergedLayer.x0, mergedLayer.y0, binStep, favorXInActiveId);
4448
- const chunkMaxX = mergedBinsAmounts.reduce((s, b) => s.add(b.amountX), new bn_js_1.default(0));
4449
- const chunkMaxY = mergedBinsAmounts.reduce((s, b) => s.add(b.amountY), new bn_js_1.default(0));
4093
+ const chunkAddLiquidityParams = chunk.layers.map(layer => {
4094
+ const onChainParams = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(layer.params.x0, layer.params.y0, layer.params.deltaX, layer.params.deltaY);
4095
+ return {
4096
+ minDeltaId: chunk.minDeltaId.toNumber(),
4097
+ maxDeltaId: chunk.maxDeltaId.toNumber(),
4098
+ x0: onChainParams.x0,
4099
+ y0: onChainParams.y0,
4100
+ deltaX: onChainParams.deltaX,
4101
+ deltaY: onChainParams.deltaY,
4102
+ bitFlag: onChainParams.bitFlag,
4103
+ favorXInActiveId,
4104
+ };
4105
+ });
4106
+ const chunkMaxX = chunk.layers.reduce((s, layer) => s.add(layer.maxAmountX), new bn_js_1.default(0));
4107
+ const chunkMaxY = chunk.layers.reduce((s, layer) => s.add(layer.maxAmountY), new bn_js_1.default(0));
4450
4108
  const instructions = [];
4451
4109
  if (!depositIncluded) {
4452
4110
  depositIncluded = true;
@@ -4482,18 +4140,7 @@ class Transactions {
4482
4140
  minWithdrawYAmount: new bn_js_1.default(0),
4483
4141
  maxDepositYAmount: chunkMaxY,
4484
4142
  removeLiquidityParams: [],
4485
- addLiquidityParams: [
4486
- {
4487
- minDeltaId: chunk.minDeltaId.toNumber(),
4488
- maxDeltaId: chunk.maxDeltaId.toNumber(),
4489
- x0: onChainParams.x0,
4490
- y0: onChainParams.y0,
4491
- deltaX: onChainParams.deltaX,
4492
- deltaY: onChainParams.deltaY,
4493
- bitFlag: onChainParams.bitFlag,
4494
- favorXInActiveId,
4495
- },
4496
- ],
4143
+ addLiquidityParams: chunkAddLiquidityParams,
4497
4144
  });
4498
4145
  instructions.push({
4499
4146
  instruction: depositIx,
@@ -4823,7 +4470,7 @@ class Transactions {
4823
4470
  };
4824
4471
  return {
4825
4472
  instruction: ix,
4826
- label: 'Add liquidity by strategy (meteora deposit)'
4473
+ label: 'Add liquidity by strategy (meteora deposit)',
4827
4474
  };
4828
4475
  }),
4829
4476
  ];
@@ -6404,23 +6051,15 @@ class Transactions {
6404
6051
  });
6405
6052
  });
6406
6053
  }
6407
- /**
6408
- * Hybrid liquidity rebalance for automation: teardown old position and rebuild
6409
- * with independent X/Y distributions per layer using rebalanceLiquidityAutomation.
6410
- *
6411
- * Supports all position sizes (≤70, 71-149, ≥150 bins).
6412
- * All hybrid layers are passed as multiple addLiquidityParams entries in a single
6413
- * rebalanceLiquidityAutomation call per chunk (rather than one call per layer).
6414
- */
6415
- meteoraRebalanceHybridLiquidityAutomation(_a) {
6054
+ meteoraRebalanceHybridLiquidityV2Automation(_a) {
6416
6055
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
6417
6056
  var _b, _c;
6418
6057
  try {
6419
6058
  const MAX_INIT_WIDTH = 70;
6420
6059
  const MAX_EXTEND_LENGTH = 91;
6421
- const MAX_BINS_PER_WITHDRAW_CHUNK = 149;
6422
- const MAX_BINS_PER_DEPOSIT_CHUNK = 149;
6423
- const CLASS = 'meteoraRebalanceHybridLiquidityAutomation';
6060
+ const MAX_BINS_PER_WITHDRAW_CHUNK = 175;
6061
+ const CHUNKS_PER_TRANSACTION = 3;
6062
+ const CLASS = 'meteoraRebalanceHybridLiquidityV2Automation';
6424
6063
  // --- Validate layers ---
6425
6064
  const layers = params.layers;
6426
6065
  if (layers.length === 0 || layers.length > 3) {
@@ -6431,14 +6070,13 @@ class Transactions {
6431
6070
  if (sumX !== 100 || sumY !== 100) {
6432
6071
  throw new Error(`Layer percentages must sum to 100 per side (got X=${sumX}, Y=${sumY})`);
6433
6072
  }
6434
- const { lbPair, lbPairState, dlmmPool, lowerBinId: currentLowerBinId, upperBinId: currentUpperBinId, estimatedTotalX, estimatedTotalY, activeId, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, withdrawFn, depositFn, } = yield this.resolvePositionContext({
6073
+ const { lbPair, lbPairState, dlmmPool, lowerBinId: currentLowerBinId, upperBinId: currentUpperBinId, estimatedTotalX, estimatedTotalY, activeId, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, withdrawFn, baseRemainingAccountsInfo, } = yield this.resolvePositionContext({
6435
6074
  connection,
6436
6075
  userWallet: params.userWallet,
6437
6076
  position: params.currentPosition,
6438
6077
  compound: params.compound,
6439
6078
  targetActiveBin: params.targetActiveBin,
6440
6079
  });
6441
- // checkRange validation
6442
6080
  if (activeId < params.checkRange.lowerRange ||
6443
6081
  activeId > params.checkRange.upperRange) {
6444
6082
  throw new Error(`Active bin ${activeId} outside checkRange [${params.checkRange.lowerRange}, ${params.checkRange.upperRange}]`);
@@ -6447,13 +6085,13 @@ class Transactions {
6447
6085
  const newUpperBinId = activeId + params.relativeBinRange.upperRange;
6448
6086
  const newWidth = newUpperBinId - newLowerBinId + 1;
6449
6087
  const currentWidth = currentUpperBinId - currentLowerBinId + 1;
6450
- const binStep = new bn_js_1.default(lbPairState.binStep);
6088
+ const maxBinsPerDepositChunk = newWidth === 69 ? 69 : 50;
6089
+ const useLayeredDepositsForSmallPosition = newWidth <= 69 && layers.length > 1;
6451
6090
  // =========================================================================
6452
6091
  // PHASE 1: TEARDOWN (withdraw from old position + close)
6453
6092
  // =========================================================================
6454
6093
  const teardownTxGroups = [];
6455
6094
  if (currentWidth <= MAX_BINS_PER_WITHDRAW_CHUNK) {
6456
- // Small/medium: single withdraw TX
6457
6095
  teardownTxGroups.push([
6458
6096
  ...(yield withdrawFn({
6459
6097
  position: params.currentPosition,
@@ -6475,7 +6113,6 @@ class Transactions {
6475
6113
  ]);
6476
6114
  }
6477
6115
  else {
6478
- // Large: chunked withdrawal
6479
6116
  const withdrawChunks = (0, liquidityStrategy_1.chunkBinRange)(currentLowerBinId, currentUpperBinId, MAX_BINS_PER_WITHDRAW_CHUNK);
6480
6117
  for (let i = 0; i < withdrawChunks.length; i++) {
6481
6118
  const chunk = withdrawChunks[i];
@@ -6505,23 +6142,20 @@ class Transactions {
6505
6142
  }
6506
6143
  }
6507
6144
  // =========================================================================
6508
- // PHASE 2: REBUILD (init + extend + deposit with hybrid layers)
6145
+ // PHASE 2: REBUILD (init + extend + deposit with NEW add_liquidity_2 instruction)
6509
6146
  // =========================================================================
6510
6147
  const effectiveAmountX = (_b = params.amountXOverride) !== null && _b !== void 0 ? _b : estimatedTotalX;
6511
6148
  const effectiveAmountY = (_c = params.amountYOverride) !== null && _c !== void 0 ? _c : estimatedTotalY;
6512
6149
  const favorXInActiveId = effectiveAmountY.isZero() && !effectiveAmountX.isZero();
6513
6150
  const minDeltaId = newLowerBinId - activeId;
6514
6151
  const maxDeltaId = newUpperBinId - activeId;
6515
- // Compute hybrid strategy for the full new range
6516
- const strategyResults = (0, liquidityStrategy_1.distributionToHybridStrategy)({
6517
- hybridDistribution: layers,
6518
- amountX: effectiveAmountX,
6519
- amountY: effectiveAmountY,
6520
- minDeltaId: new bn_js_1.default(minDeltaId),
6521
- maxDeltaId: new bn_js_1.default(maxDeltaId),
6522
- binStep,
6523
- activeId: new bn_js_1.default(activeId),
6524
- });
6152
+ const binStep = new bn_js_1.default(lbPairState.binStep);
6153
+ const contractLayers = layers.map(l => ({
6154
+ strategyTypeX: (0, liquidityStrategy_1.distributionToStrategyType)(l.x.distribution),
6155
+ strategyTypeY: (0, liquidityStrategy_1.distributionToStrategyType)(l.y.distribution),
6156
+ percentageX: l.x.percentage,
6157
+ percentageY: l.y.percentage,
6158
+ }));
6525
6159
  // Build init + extend instructions
6526
6160
  const initExtendIxs = [];
6527
6161
  const initWidth = Math.min(MAX_INIT_WIDTH, newWidth);
@@ -6553,158 +6187,151 @@ class Transactions {
6553
6187
  });
6554
6188
  positionBinsAllocated += toAdd;
6555
6189
  }
6556
- // Build deposit TX group(s)
6557
6190
  const rebuildTxGroups = [];
6558
- if (newWidth <= MAX_BINS_PER_DEPOSIT_CHUNK) {
6559
- // Small/medium: all layers in one rebalanceLiquidity call.
6560
- // Split into two TXs when extension is needed (newWidth > MAX_INIT_WIDTH) to
6561
- // avoid exceeding the TX size limit with init + extend + binArrayInits + deposit.
6562
- //
6563
- // Merge all layers into a single AddLiquidityParams entry by summing x0/y0/deltaX/deltaY.
6564
- // Meteora's rebalanceLiquidity requires non-overlapping ranges across entries; since all
6565
- // layers share the same full range, they must be merged into one. The formula is linear
6566
- // so summing params is equivalent to summing per-bin amounts from each layer.
6567
- const mergedLayer = strategyResults.reduce((acc, l) => ({
6568
- x0: acc.x0.add(l.x0),
6569
- y0: acc.y0.add(l.y0),
6570
- deltaX: acc.deltaX.add(l.deltaX),
6571
- deltaY: acc.deltaY.add(l.deltaY),
6572
- }), {
6573
- x0: new bn_js_1.default(0),
6574
- y0: new bn_js_1.default(0),
6575
- deltaX: new bn_js_1.default(0),
6576
- deltaY: new bn_js_1.default(0),
6577
- });
6578
- const mergedP = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(mergedLayer.x0, mergedLayer.y0, mergedLayer.deltaX, mergedLayer.deltaY);
6579
- const allAddLiquidityParams = [
6580
- {
6581
- minDeltaId,
6582
- maxDeltaId,
6583
- x0: mergedP.x0,
6584
- y0: mergedP.y0,
6585
- deltaX: mergedP.deltaX,
6586
- deltaY: mergedP.deltaY,
6587
- bitFlag: mergedP.bitFlag,
6588
- favorXInActiveId,
6589
- },
6590
- ];
6591
- const mergedBinsAmounts = (0, liquidityStrategy_1.toAmountIntoBins)(new bn_js_1.default(activeId), new bn_js_1.default(minDeltaId), new bn_js_1.default(maxDeltaId), mergedLayer.deltaX, mergedLayer.deltaY, mergedLayer.x0, mergedLayer.y0, binStep, favorXInActiveId);
6592
- const totalMaxX = mergedBinsAmounts.reduce((s, b) => s.add(b.amountX), new bn_js_1.default(0));
6593
- const totalMaxY = mergedBinsAmounts.reduce((s, b) => s.add(b.amountY), new bn_js_1.default(0));
6191
+ if (newWidth <= maxBinsPerDepositChunk) {
6594
6192
  const binArrayInitIxs = yield this._initBinArraysForRange(connection, lbPair, dlmmPool, newLowerBinId, newUpperBinId);
6595
6193
  const binArrayInitIxsLabeled = binArrayInitIxs.map(ix => ({
6596
6194
  label: 'init_bin_array',
6597
6195
  class: CLASS,
6598
6196
  instruction: ix,
6599
6197
  }));
6600
- const depositIx = yield depositFn({
6601
- position: params.newPosition,
6602
- shouldClaimFee: false,
6603
- shouldClaimReward: false,
6604
- maxDepositXAmount: totalMaxX,
6605
- maxDepositYAmount: totalMaxY,
6606
- pdaTokenType: types_1.TokenType.ATA,
6607
- addLiquidityParams: allAddLiquidityParams,
6608
- origin: CLASS,
6609
- });
6610
- if (newWidth <= MAX_INIT_WIDTH) {
6611
- // ≤70 bins: no extension needed, everything fits in one TX
6612
- rebuildTxGroups.push([
6613
- ...initExtendIxs,
6198
+ if (useLayeredDepositsForSmallPosition) {
6199
+ const strategyResults = (0, liquidityStrategy_1.distributionToHybridStrategy)({
6200
+ hybridDistribution: layers,
6201
+ amountX: effectiveAmountX,
6202
+ amountY: effectiveAmountY,
6203
+ minDeltaId: new bn_js_1.default(minDeltaId),
6204
+ maxDeltaId: new bn_js_1.default(maxDeltaId),
6205
+ binStep,
6206
+ activeId: new bn_js_1.default(activeId),
6207
+ });
6208
+ rebuildTxGroups.push(initExtendIxs);
6209
+ const layeredDepositIxs = [
6614
6210
  ...binArrayInitIxsLabeled,
6615
- depositIx,
6616
- ]);
6211
+ ];
6212
+ for (let i = 0; i < strategyResults.length; i++) {
6213
+ const layerStrategy = strategyResults[i];
6214
+ if (layerStrategy.maxAmountX.isZero() && layerStrategy.maxAmountY.isZero()) {
6215
+ continue;
6216
+ }
6217
+ const singleLayer = {
6218
+ strategyTypeX: contractLayers[i].strategyTypeX,
6219
+ strategyTypeY: contractLayers[i].strategyTypeY,
6220
+ percentageX: layers[i].x.percentage > 0 ? 100 : 0,
6221
+ percentageY: layers[i].y.percentage > 0 ? 100 : 0,
6222
+ };
6223
+ const depositIx = yield this.ix.meteoraDlmm.addLiquidity2Automation({
6224
+ connection,
6225
+ userWallet: params.userWallet,
6226
+ lbPair,
6227
+ position: params.newPosition,
6228
+ tokenXMint,
6229
+ tokenYMint,
6230
+ tokenXProgram,
6231
+ tokenYProgram,
6232
+ layers: [singleLayer],
6233
+ checkRange: params.checkRange,
6234
+ userTokenXAmount: layerStrategy.maxAmountX,
6235
+ userTokenYAmount: layerStrategy.maxAmountY,
6236
+ remainingAccountsInfo: baseRemainingAccountsInfo,
6237
+ pdaTokenType: types_1.TokenType.ATA,
6238
+ lowerBinId: newLowerBinId,
6239
+ upperBinId: newUpperBinId,
6240
+ });
6241
+ layeredDepositIxs.push({ label: 'deposit_v2', class: CLASS, instruction: depositIx });
6242
+ }
6243
+ if (layeredDepositIxs.length > 0) {
6244
+ rebuildTxGroups.push(layeredDepositIxs);
6245
+ }
6617
6246
  }
6618
6247
  else {
6619
- // 71-149 bins: extension needed, split init+extend from deposit to stay within TX size limit
6620
- rebuildTxGroups.push(initExtendIxs);
6621
- rebuildTxGroups.push([...binArrayInitIxsLabeled, depositIx]);
6248
+ const depositIx = yield this.ix.meteoraDlmm.addLiquidity2Automation({
6249
+ connection,
6250
+ userWallet: params.userWallet,
6251
+ lbPair,
6252
+ position: params.newPosition,
6253
+ tokenXMint,
6254
+ tokenYMint,
6255
+ tokenXProgram,
6256
+ tokenYProgram,
6257
+ layers: contractLayers,
6258
+ checkRange: params.checkRange,
6259
+ userTokenXAmount: effectiveAmountX,
6260
+ userTokenYAmount: effectiveAmountY,
6261
+ remainingAccountsInfo: baseRemainingAccountsInfo,
6262
+ pdaTokenType: types_1.TokenType.ATA,
6263
+ lowerBinId: newLowerBinId,
6264
+ upperBinId: newUpperBinId,
6265
+ });
6266
+ if (newWidth <= MAX_INIT_WIDTH) {
6267
+ rebuildTxGroups.push([
6268
+ ...initExtendIxs,
6269
+ ...binArrayInitIxsLabeled,
6270
+ { label: 'deposit_v2', class: CLASS, instruction: depositIx },
6271
+ ]);
6272
+ }
6273
+ else {
6274
+ rebuildTxGroups.push(initExtendIxs);
6275
+ rebuildTxGroups.push([
6276
+ ...binArrayInitIxsLabeled,
6277
+ { label: 'deposit_v2', class: CLASS, instruction: depositIx },
6278
+ ]);
6279
+ }
6622
6280
  }
6623
6281
  }
6624
6282
  else {
6625
- // Large: init+extend in first TX, then one TX per deposit chunk
6626
6283
  rebuildTxGroups.push(initExtendIxs);
6627
- const depositChunks = (0, liquidityStrategy_1.chunkHybridDepositParameters)(strategyResults, new bn_js_1.default(minDeltaId), new bn_js_1.default(maxDeltaId), new bn_js_1.default(activeId), binStep, MAX_BINS_PER_DEPOSIT_CHUNK, favorXInActiveId);
6284
+ const strategyResults = (0, liquidityStrategy_1.distributionToHybridStrategy)({
6285
+ hybridDistribution: layers,
6286
+ amountX: effectiveAmountX,
6287
+ amountY: effectiveAmountY,
6288
+ minDeltaId: new bn_js_1.default(minDeltaId),
6289
+ maxDeltaId: new bn_js_1.default(maxDeltaId),
6290
+ binStep,
6291
+ activeId: new bn_js_1.default(activeId),
6292
+ });
6293
+ const depositChunks = (0, liquidityStrategy_1.chunkHybridDepositParameters)(strategyResults, new bn_js_1.default(minDeltaId), new bn_js_1.default(maxDeltaId), new bn_js_1.default(activeId), binStep, maxBinsPerDepositChunk, favorXInActiveId);
6294
+ const chunkInstructionGroups = [];
6628
6295
  for (const chunk of depositChunks) {
6629
- // Merge all layers into a single AddLiquidityParams entry per chunk (see comment above).
6630
- const chunkMergedLayer = chunk.layers.reduce((acc, l) => ({
6631
- x0: acc.x0.add(l.params.x0),
6632
- y0: acc.y0.add(l.params.y0),
6633
- deltaX: acc.deltaX.add(l.params.deltaX),
6634
- deltaY: acc.deltaY.add(l.params.deltaY),
6635
- }), {
6636
- x0: new bn_js_1.default(0),
6637
- y0: new bn_js_1.default(0),
6638
- deltaX: new bn_js_1.default(0),
6639
- deltaY: new bn_js_1.default(0),
6640
- });
6641
- const chunkMergedP = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunkMergedLayer.x0, chunkMergedLayer.y0, chunkMergedLayer.deltaX, chunkMergedLayer.deltaY);
6642
- const chunkAddLiquidityParams = [
6643
- {
6644
- minDeltaId: chunk.minDeltaId.toNumber(),
6645
- maxDeltaId: chunk.maxDeltaId.toNumber(),
6646
- x0: chunkMergedP.x0,
6647
- y0: chunkMergedP.y0,
6648
- deltaX: chunkMergedP.deltaX,
6649
- deltaY: chunkMergedP.deltaY,
6650
- bitFlag: chunkMergedP.bitFlag,
6651
- favorXInActiveId,
6652
- },
6653
- ];
6654
- const chunkMergedBinsAmounts = (0, liquidityStrategy_1.toAmountIntoBins)(new bn_js_1.default(activeId), chunk.minDeltaId, chunk.maxDeltaId, chunkMergedLayer.deltaX, chunkMergedLayer.deltaY, chunkMergedLayer.x0, chunkMergedLayer.y0, binStep, favorXInActiveId);
6655
- const chunkTotalMaxX = chunkMergedBinsAmounts.reduce((s, b) => s.add(b.amountX), new bn_js_1.default(0));
6656
- const chunkTotalMaxY = chunkMergedBinsAmounts.reduce((s, b) => s.add(b.amountY), new bn_js_1.default(0));
6296
+ const { chunkLowerOffset, chunkUpperOffset } = getHybridChunkOffsets(newLowerBinId, chunk.lowerBinId, chunk.upperBinId);
6297
+ const chunkAmountX = chunk.layers.reduce((sum, layer) => sum.add(layer.maxAmountX), new bn_js_1.default(0));
6298
+ const chunkAmountY = chunk.layers.reduce((sum, layer) => sum.add(layer.maxAmountY), new bn_js_1.default(0));
6299
+ if (chunkAmountX.isZero() && chunkAmountY.isZero()) {
6300
+ continue;
6301
+ }
6657
6302
  const binArrayInitIxs = yield this._initBinArraysForRange(connection, lbPair, dlmmPool, chunk.lowerBinId, chunk.upperBinId);
6658
- rebuildTxGroups.push([
6303
+ const depositIx = yield this.ix.meteoraDlmm.addLiquidity2Automation({
6304
+ connection,
6305
+ userWallet: params.userWallet,
6306
+ lbPair,
6307
+ position: params.newPosition,
6308
+ tokenXMint,
6309
+ tokenYMint,
6310
+ tokenXProgram,
6311
+ tokenYProgram,
6312
+ layers: contractLayers,
6313
+ checkRange: params.checkRange,
6314
+ userTokenXAmount: chunkAmountX,
6315
+ userTokenYAmount: chunkAmountY,
6316
+ chunkLowerOffset,
6317
+ chunkUpperOffset,
6318
+ remainingAccountsInfo: baseRemainingAccountsInfo,
6319
+ pdaTokenType: types_1.TokenType.ATA,
6320
+ lowerBinId: chunk.lowerBinId,
6321
+ upperBinId: chunk.upperBinId,
6322
+ });
6323
+ chunkInstructionGroups.push([
6659
6324
  ...binArrayInitIxs.map(ix => ({
6660
6325
  label: 'init_bin_array',
6661
6326
  class: CLASS,
6662
6327
  instruction: ix,
6663
6328
  })),
6664
- yield depositFn({
6665
- position: params.newPosition,
6666
- shouldClaimFee: false,
6667
- shouldClaimReward: false,
6668
- maxDepositXAmount: chunkTotalMaxX,
6669
- maxDepositYAmount: chunkTotalMaxY,
6670
- pdaTokenType: types_1.TokenType.ATA,
6671
- addLiquidityParams: chunkAddLiquidityParams,
6672
- origin: CLASS,
6673
- }),
6329
+ { label: 'deposit_v2', class: CLASS, instruction: depositIx },
6674
6330
  ]);
6675
6331
  }
6332
+ rebuildTxGroups.push(...batchHybridChunkInstructionGroups(chunkInstructionGroups, CHUNKS_PER_TRANSACTION));
6676
6333
  }
6677
6334
  // =========================================================================
6678
- // PHASE 3: SWEEP REMAINING DUST
6679
- // =========================================================================
6680
- // After the main hybrid deposit, add one final deposit with undefined amounts
6681
- // so the on-chain instruction reads the actual ATA balance and sweeps any dust.
6682
- // Uses Spot distribution. Bin range follows the position's range (preserving
6683
- // directional bias), clamped to 70 bins max (Meteora's single-call limit).
6684
- const { sweepLower, sweepUpper } = this._calculateSweepBinRange(params.relativeBinRange.lowerRange, params.relativeBinRange.upperRange);
6685
- const sweepIx = yield this.ix.meteoraDlmm.meteoraDlmmDepositRelativeAutomation({
6686
- connection,
6687
- userWallet: params.userWallet,
6688
- lbPair,
6689
- position: params.newPosition,
6690
- tokenXMint,
6691
- tokenYMint,
6692
- tokenXProgram,
6693
- tokenYProgram,
6694
- activeId,
6695
- relativeBinRange: { lowerRange: sweepLower, upperRange: sweepUpper },
6696
- strategyType: 6, // SpotImBalanced — handles any X/Y ratio including single-sided
6697
- optionalTokenXAmount: undefined, // sweep — use full ATA balance
6698
- optionalTokenYAmount: undefined, // sweep — use full ATA balance
6699
- checkRange: params.checkRange,
6700
- pdaTokenType: types_1.TokenType.ATA,
6701
- });
6702
- rebuildTxGroups.push([{
6703
- label: 'sweep_dust',
6704
- class: CLASS,
6705
- instruction: sweepIx,
6706
- }]);
6707
- // =========================================================================
6708
6335
  // Assemble final TX list
6709
6336
  // =========================================================================
6710
6337
  const allTxGroups = [...teardownTxGroups, ...rebuildTxGroups];
@@ -6719,7 +6346,7 @@ class Transactions {
6719
6346
  return transactions;
6720
6347
  }
6721
6348
  catch (error) {
6722
- console.error('=== REBALANCE HYBRID LIQUIDITY AUTOMATION ERROR ===');
6349
+ console.error('=== REBALANCE HYBRID LIQUIDITY V2 AUTOMATION ERROR ===');
6723
6350
  console.error('Error:', error instanceof Error ? error.message : String(error));
6724
6351
  console.error('Stack:', error instanceof Error ? error.stack : 'No stack trace');
6725
6352
  console.error('=== END ERROR LOG ===');
@@ -6727,20 +6354,13 @@ class Transactions {
6727
6354
  }
6728
6355
  });
6729
6356
  }
6730
- /**
6731
- * Hybrid liquidity redeposit for automation: withdraw all liquidity from the same
6732
- * position and re-deposit with independent X/Y distributions per layer.
6733
- *
6734
- * Unlike rebalance, the position is NOT closed or moved — the same bin range is reused.
6735
- * Supports all position sizes (≤70, 71-149, ≥150 bins).
6736
- */
6737
- meteoraRedepositHybridLiquidityAutomation(_a) {
6357
+ meteoraRedepositHybridLiquidityV2Automation(_a) {
6738
6358
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
6739
6359
  var _b, _c;
6740
6360
  try {
6741
- const MAX_BINS_PER_WITHDRAW_CHUNK = 149;
6742
- const MAX_BINS_PER_DEPOSIT_CHUNK = 149;
6743
- const CLASS = 'meteoraRedepositHybridLiquidityAutomation';
6361
+ const MAX_BINS_PER_WITHDRAW_CHUNK = 150;
6362
+ const CHUNKS_PER_TRANSACTION = 3;
6363
+ const CLASS = 'meteoraRedepositHybridLiquidityV2Automation';
6744
6364
  // --- Validate layers ---
6745
6365
  const layers = params.layers;
6746
6366
  if (layers.length === 0 || layers.length > 3) {
@@ -6751,7 +6371,7 @@ class Transactions {
6751
6371
  if (sumX !== 100 || sumY !== 100) {
6752
6372
  throw new Error(`Layer percentages must sum to 100 per side (got X=${sumX}, Y=${sumY})`);
6753
6373
  }
6754
- const { lbPair, lbPairState, lowerBinId, upperBinId, estimatedTotalX, estimatedTotalY, activeId, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, withdrawFn, depositFn, } = yield this.resolvePositionContext({
6374
+ const { lbPair, lbPairState, dlmmPool, lowerBinId, upperBinId, estimatedTotalX, estimatedTotalY, activeId, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, withdrawFn, baseRemainingAccountsInfo, } = yield this.resolvePositionContext({
6755
6375
  connection,
6756
6376
  userWallet: params.userWallet,
6757
6377
  position: params.position,
@@ -6760,12 +6380,20 @@ class Transactions {
6760
6380
  skipClaim: true,
6761
6381
  });
6762
6382
  const positionWidth = upperBinId - lowerBinId + 1;
6763
- const binStep = new bn_js_1.default(lbPairState.binStep);
6383
+ const maxBinsPerDepositChunk = positionWidth === 69 ? 69 : 45;
6384
+ const useLayeredDepositsForSmallPosition = positionWidth <= 69 && layers.length > 1;
6764
6385
  const effectiveAmountX = (_b = params.amountXOverride) !== null && _b !== void 0 ? _b : estimatedTotalX;
6765
6386
  const effectiveAmountY = (_c = params.amountYOverride) !== null && _c !== void 0 ? _c : estimatedTotalY;
6766
6387
  const favorXInActiveId = effectiveAmountY.isZero() && !effectiveAmountX.isZero();
6767
6388
  const minDeltaId = lowerBinId - activeId;
6768
6389
  const maxDeltaId = upperBinId - activeId;
6390
+ const binStep = new bn_js_1.default(lbPairState.binStep);
6391
+ const contractLayers = layers.map(l => ({
6392
+ strategyTypeX: (0, liquidityStrategy_1.distributionToStrategyType)(l.x.distribution),
6393
+ strategyTypeY: (0, liquidityStrategy_1.distributionToStrategyType)(l.y.distribution),
6394
+ percentageX: l.x.percentage,
6395
+ percentageY: l.y.percentage,
6396
+ }));
6769
6397
  // =========================================================================
6770
6398
  // PHASE 1: WITHDRAW (no close — same position)
6771
6399
  // =========================================================================
@@ -6796,140 +6424,123 @@ class Transactions {
6796
6424
  }
6797
6425
  }
6798
6426
  // =========================================================================
6799
- // PHASE 2: DEPOSIT (hybrid layers, no init/extend needed)
6427
+ // PHASE 2: DEPOSIT (hybrid layers via new add_liquidity_2 instruction)
6800
6428
  // =========================================================================
6801
- const strategyResults = (0, liquidityStrategy_1.distributionToHybridStrategy)({
6802
- hybridDistribution: layers,
6803
- amountX: effectiveAmountX,
6804
- amountY: effectiveAmountY,
6805
- minDeltaId: new bn_js_1.default(minDeltaId),
6806
- maxDeltaId: new bn_js_1.default(maxDeltaId),
6807
- binStep,
6808
- activeId: new bn_js_1.default(activeId),
6809
- });
6810
6429
  const depositTxGroups = [];
6811
- if (positionWidth <= MAX_BINS_PER_DEPOSIT_CHUNK) {
6812
- // Single deposit TX — all layers merged into one rebalanceLiquidity call.
6813
- // Merge all layers into a single AddLiquidityParams entry by summing x0/y0/deltaX/deltaY.
6814
- // Meteora's rebalanceLiquidity requires non-overlapping ranges across entries; since all
6815
- // layers share the same full range, they must be merged into one. The formula is linear
6816
- // so summing params is equivalent to summing per-bin amounts from each layer.
6817
- const mergedLayer = strategyResults.reduce((acc, l) => ({
6818
- x0: acc.x0.add(l.x0),
6819
- y0: acc.y0.add(l.y0),
6820
- deltaX: acc.deltaX.add(l.deltaX),
6821
- deltaY: acc.deltaY.add(l.deltaY),
6822
- }), {
6823
- x0: new bn_js_1.default(0),
6824
- y0: new bn_js_1.default(0),
6825
- deltaX: new bn_js_1.default(0),
6826
- deltaY: new bn_js_1.default(0),
6827
- });
6828
- const mergedP = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(mergedLayer.x0, mergedLayer.y0, mergedLayer.deltaX, mergedLayer.deltaY);
6829
- const allAddLiquidityParams = [
6830
- {
6831
- minDeltaId,
6832
- maxDeltaId,
6833
- x0: mergedP.x0,
6834
- y0: mergedP.y0,
6835
- deltaX: mergedP.deltaX,
6836
- deltaY: mergedP.deltaY,
6837
- bitFlag: mergedP.bitFlag,
6838
- favorXInActiveId,
6839
- },
6840
- ];
6841
- const mergedBinsAmounts = (0, liquidityStrategy_1.toAmountIntoBins)(new bn_js_1.default(activeId), new bn_js_1.default(minDeltaId), new bn_js_1.default(maxDeltaId), mergedLayer.deltaX, mergedLayer.deltaY, mergedLayer.x0, mergedLayer.y0, binStep, favorXInActiveId);
6842
- const totalMaxX = mergedBinsAmounts.reduce((s, b) => s.add(b.amountX), new bn_js_1.default(0));
6843
- const totalMaxY = mergedBinsAmounts.reduce((s, b) => s.add(b.amountY), new bn_js_1.default(0));
6844
- depositTxGroups.push([
6845
- yield depositFn({
6430
+ if (positionWidth <= maxBinsPerDepositChunk) {
6431
+ if (useLayeredDepositsForSmallPosition) {
6432
+ const strategyResults = (0, liquidityStrategy_1.distributionToHybridStrategy)({
6433
+ hybridDistribution: layers,
6434
+ amountX: effectiveAmountX,
6435
+ amountY: effectiveAmountY,
6436
+ minDeltaId: new bn_js_1.default(minDeltaId),
6437
+ maxDeltaId: new bn_js_1.default(maxDeltaId),
6438
+ binStep,
6439
+ activeId: new bn_js_1.default(activeId),
6440
+ });
6441
+ const layeredDepositIxs = [];
6442
+ for (let i = 0; i < strategyResults.length; i++) {
6443
+ const layerStrategy = strategyResults[i];
6444
+ if (layerStrategy.maxAmountX.isZero() && layerStrategy.maxAmountY.isZero()) {
6445
+ continue;
6446
+ }
6447
+ const singleLayer = {
6448
+ strategyTypeX: contractLayers[i].strategyTypeX,
6449
+ strategyTypeY: contractLayers[i].strategyTypeY,
6450
+ percentageX: layers[i].x.percentage > 0 ? 100 : 0,
6451
+ percentageY: layers[i].y.percentage > 0 ? 100 : 0,
6452
+ };
6453
+ const depositIx = yield this.ix.meteoraDlmm.addLiquidity2Automation({
6454
+ connection,
6455
+ userWallet: params.userWallet,
6456
+ lbPair,
6457
+ position: params.position,
6458
+ tokenXMint,
6459
+ tokenYMint,
6460
+ tokenXProgram,
6461
+ tokenYProgram,
6462
+ layers: [singleLayer],
6463
+ userTokenXAmount: layerStrategy.maxAmountX,
6464
+ userTokenYAmount: layerStrategy.maxAmountY,
6465
+ remainingAccountsInfo: baseRemainingAccountsInfo,
6466
+ pdaTokenType: types_1.TokenType.ATA,
6467
+ lowerBinId,
6468
+ upperBinId,
6469
+ });
6470
+ layeredDepositIxs.push({ label: 'deposit_v2', class: CLASS, instruction: depositIx });
6471
+ }
6472
+ if (layeredDepositIxs.length > 0) {
6473
+ depositTxGroups.push(layeredDepositIxs);
6474
+ }
6475
+ }
6476
+ else {
6477
+ const depositIx = yield this.ix.meteoraDlmm.addLiquidity2Automation({
6478
+ connection,
6479
+ userWallet: params.userWallet,
6480
+ lbPair,
6846
6481
  position: params.position,
6847
- shouldClaimFee: false,
6848
- shouldClaimReward: false,
6849
- maxDepositXAmount: totalMaxX,
6850
- maxDepositYAmount: totalMaxY,
6482
+ tokenXMint,
6483
+ tokenYMint,
6484
+ tokenXProgram,
6485
+ tokenYProgram,
6486
+ layers: contractLayers,
6487
+ userTokenXAmount: effectiveAmountX,
6488
+ userTokenYAmount: effectiveAmountY,
6489
+ remainingAccountsInfo: baseRemainingAccountsInfo,
6851
6490
  pdaTokenType: types_1.TokenType.ATA,
6852
- addLiquidityParams: allAddLiquidityParams,
6853
- origin: CLASS,
6854
- }),
6855
- ]);
6491
+ lowerBinId,
6492
+ upperBinId,
6493
+ });
6494
+ depositTxGroups.push([
6495
+ { label: 'deposit_v2', class: CLASS, instruction: depositIx },
6496
+ ]);
6497
+ }
6856
6498
  }
6857
6499
  else {
6858
- // Chunked deposit — one TX per chunk, all layers per chunk
6859
- const depositChunks = (0, liquidityStrategy_1.chunkHybridDepositParameters)(strategyResults, new bn_js_1.default(minDeltaId), new bn_js_1.default(maxDeltaId), new bn_js_1.default(activeId), binStep, MAX_BINS_PER_DEPOSIT_CHUNK, favorXInActiveId);
6500
+ const strategyResults = (0, liquidityStrategy_1.distributionToHybridStrategy)({
6501
+ hybridDistribution: layers,
6502
+ amountX: effectiveAmountX,
6503
+ amountY: effectiveAmountY,
6504
+ minDeltaId: new bn_js_1.default(minDeltaId),
6505
+ maxDeltaId: new bn_js_1.default(maxDeltaId),
6506
+ binStep,
6507
+ activeId: new bn_js_1.default(activeId),
6508
+ });
6509
+ const depositChunks = (0, liquidityStrategy_1.chunkHybridDepositParameters)(strategyResults, new bn_js_1.default(minDeltaId), new bn_js_1.default(maxDeltaId), new bn_js_1.default(activeId), binStep, maxBinsPerDepositChunk, favorXInActiveId);
6510
+ const chunkInstructionGroups = [];
6860
6511
  for (const chunk of depositChunks) {
6861
- // Merge all layers into a single AddLiquidityParams entry per chunk (see comment above).
6862
- const chunkMergedLayer = chunk.layers.reduce((acc, l) => ({
6863
- x0: acc.x0.add(l.params.x0),
6864
- y0: acc.y0.add(l.params.y0),
6865
- deltaX: acc.deltaX.add(l.params.deltaX),
6866
- deltaY: acc.deltaY.add(l.params.deltaY),
6867
- }), {
6868
- x0: new bn_js_1.default(0),
6869
- y0: new bn_js_1.default(0),
6870
- deltaX: new bn_js_1.default(0),
6871
- deltaY: new bn_js_1.default(0),
6512
+ const { chunkLowerOffset, chunkUpperOffset } = getHybridChunkOffsets(lowerBinId, chunk.lowerBinId, chunk.upperBinId);
6513
+ const chunkAmountX = chunk.layers.reduce((sum, layer) => sum.add(layer.maxAmountX), new bn_js_1.default(0));
6514
+ const chunkAmountY = chunk.layers.reduce((sum, layer) => sum.add(layer.maxAmountY), new bn_js_1.default(0));
6515
+ if (chunkAmountX.isZero() && chunkAmountY.isZero()) {
6516
+ continue;
6517
+ }
6518
+ const depositIx = yield this.ix.meteoraDlmm.addLiquidity2Automation({
6519
+ connection,
6520
+ userWallet: params.userWallet,
6521
+ lbPair,
6522
+ position: params.position,
6523
+ tokenXMint,
6524
+ tokenYMint,
6525
+ tokenXProgram,
6526
+ tokenYProgram,
6527
+ layers: contractLayers,
6528
+ userTokenXAmount: chunkAmountX,
6529
+ userTokenYAmount: chunkAmountY,
6530
+ chunkLowerOffset,
6531
+ chunkUpperOffset,
6532
+ remainingAccountsInfo: baseRemainingAccountsInfo,
6533
+ pdaTokenType: types_1.TokenType.ATA,
6534
+ lowerBinId: chunk.lowerBinId,
6535
+ upperBinId: chunk.upperBinId,
6872
6536
  });
6873
- const chunkMergedP = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunkMergedLayer.x0, chunkMergedLayer.y0, chunkMergedLayer.deltaX, chunkMergedLayer.deltaY);
6874
- const chunkAddLiquidityParams = [
6875
- {
6876
- minDeltaId: chunk.minDeltaId.toNumber(),
6877
- maxDeltaId: chunk.maxDeltaId.toNumber(),
6878
- x0: chunkMergedP.x0,
6879
- y0: chunkMergedP.y0,
6880
- deltaX: chunkMergedP.deltaX,
6881
- deltaY: chunkMergedP.deltaY,
6882
- bitFlag: chunkMergedP.bitFlag,
6883
- favorXInActiveId,
6884
- },
6885
- ];
6886
- const chunkMergedBinsAmounts = (0, liquidityStrategy_1.toAmountIntoBins)(new bn_js_1.default(activeId), chunk.minDeltaId, chunk.maxDeltaId, chunkMergedLayer.deltaX, chunkMergedLayer.deltaY, chunkMergedLayer.x0, chunkMergedLayer.y0, binStep, favorXInActiveId);
6887
- const chunkTotalMaxX = chunkMergedBinsAmounts.reduce((s, b) => s.add(b.amountX), new bn_js_1.default(0));
6888
- const chunkTotalMaxY = chunkMergedBinsAmounts.reduce((s, b) => s.add(b.amountY), new bn_js_1.default(0));
6889
- depositTxGroups.push([
6890
- yield depositFn({
6891
- position: params.position,
6892
- shouldClaimFee: false,
6893
- shouldClaimReward: false,
6894
- maxDepositXAmount: chunkTotalMaxX,
6895
- maxDepositYAmount: chunkTotalMaxY,
6896
- pdaTokenType: types_1.TokenType.ATA,
6897
- addLiquidityParams: chunkAddLiquidityParams,
6898
- origin: CLASS,
6899
- }),
6537
+ chunkInstructionGroups.push([
6538
+ { label: 'deposit_v2', class: CLASS, instruction: depositIx },
6900
6539
  ]);
6901
6540
  }
6541
+ depositTxGroups.push(...batchHybridChunkInstructionGroups(chunkInstructionGroups, CHUNKS_PER_TRANSACTION));
6902
6542
  }
6903
6543
  // =========================================================================
6904
- // PHASE 3: SWEEP REMAINING DUST
6905
- // =========================================================================
6906
- // After the main hybrid deposit, add one final deposit with undefined amounts
6907
- // so the on-chain instruction reads the actual ATA balance and sweeps any dust.
6908
- // Uses Spot distribution. Bin range follows the position's range (preserving
6909
- // directional bias), clamped to 70 bins max (Meteora's single-call limit).
6910
- const { sweepLower, sweepUpper } = this._calculateSweepBinRange(minDeltaId, maxDeltaId);
6911
- const sweepIx = yield this.ix.meteoraDlmm.meteoraDlmmDepositRelativeAutomation({
6912
- connection,
6913
- userWallet: params.userWallet,
6914
- lbPair,
6915
- position: params.position,
6916
- tokenXMint,
6917
- tokenYMint,
6918
- tokenXProgram,
6919
- tokenYProgram,
6920
- activeId,
6921
- relativeBinRange: { lowerRange: sweepLower, upperRange: sweepUpper },
6922
- strategyType: 6, // SpotImBalanced — handles any X/Y ratio including single-sided
6923
- optionalTokenXAmount: undefined, // sweep — use full ATA balance
6924
- optionalTokenYAmount: undefined, // sweep — use full ATA balance
6925
- pdaTokenType: types_1.TokenType.ATA,
6926
- });
6927
- depositTxGroups.push([{
6928
- label: 'sweep_dust',
6929
- class: CLASS,
6930
- instruction: sweepIx,
6931
- }]);
6932
- // =========================================================================
6933
6544
  // Assemble final TX list
6934
6545
  // =========================================================================
6935
6546
  const allTxGroups = [...withdrawTxGroups, ...depositTxGroups];
@@ -6944,7 +6555,7 @@ class Transactions {
6944
6555
  return transactions;
6945
6556
  }
6946
6557
  catch (error) {
6947
- console.error('=== REDEPOSIT HYBRID LIQUIDITY AUTOMATION ERROR ===');
6558
+ console.error('=== REDEPOSIT HYBRID LIQUIDITY V2 AUTOMATION ERROR ===');
6948
6559
  console.error('Error:', error instanceof Error ? error.message : String(error));
6949
6560
  console.error('Stack:', error instanceof Error ? error.stack : 'No stack trace');
6950
6561
  console.error('=== END ERROR LOG ===');
@@ -7019,7 +6630,10 @@ class Transactions {
7019
6630
  if (userPosition === undefined) {
7020
6631
  throw new Error(`Unexpected error: Position (${position}) doesn't exist on-chain`);
7021
6632
  }
7022
- const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
6633
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [
6634
+ tokenXMint,
6635
+ tokenYMint,
6636
+ ]);
7023
6637
  const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
7024
6638
  const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
7025
6639
  const baseRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
@@ -7052,8 +6666,14 @@ class Transactions {
7052
6666
  const combinedAccounts = [];
7053
6667
  const xSlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookX);
7054
6668
  const ySlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookY);
7055
- combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookX, length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0 });
7056
- combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookY, length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0 });
6669
+ combinedSlices.push({
6670
+ accountsType: types_1.RemainingAccountsType.TransferHookX,
6671
+ length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0,
6672
+ });
6673
+ combinedSlices.push({
6674
+ accountsType: types_1.RemainingAccountsType.TransferHookY,
6675
+ length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0,
6676
+ });
7057
6677
  combinedAccounts.push(...baseRemainingAccountsInfo.accounts);
7058
6678
  for (const reward of rewardInfos) {
7059
6679
  const rewardTransferHookInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, reward.rewardMint, reward.rewardTokenProgram);
@@ -7081,12 +6701,16 @@ class Transactions {
7081
6701
  const feeY = positionData.feeY;
7082
6702
  const HAWK_FEE_BPS = 800;
7083
6703
  const FEE_BPS_DENOM = 10000;
7084
- const netFeeX = feeX.mul(new bn_js_1.default(FEE_BPS_DENOM - HAWK_FEE_BPS)).div(new bn_js_1.default(FEE_BPS_DENOM));
7085
- const netFeeY = feeY.mul(new bn_js_1.default(FEE_BPS_DENOM - HAWK_FEE_BPS)).div(new bn_js_1.default(FEE_BPS_DENOM));
7086
- const estimatedTotalX = (compound && !skipClaim)
6704
+ const netFeeX = feeX
6705
+ .mul(new bn_js_1.default(FEE_BPS_DENOM - HAWK_FEE_BPS))
6706
+ .div(new bn_js_1.default(FEE_BPS_DENOM));
6707
+ const netFeeY = feeY
6708
+ .mul(new bn_js_1.default(FEE_BPS_DENOM - HAWK_FEE_BPS))
6709
+ .div(new bn_js_1.default(FEE_BPS_DENOM));
6710
+ const estimatedTotalX = compound && !skipClaim
7087
6711
  ? new bn_js_1.default(positionData.totalXAmount).add(netFeeX)
7088
6712
  : new bn_js_1.default(positionData.totalXAmount);
7089
- const estimatedTotalY = (compound && !skipClaim)
6713
+ const estimatedTotalY = compound && !skipClaim
7090
6714
  ? new bn_js_1.default(positionData.totalYAmount).add(netFeeY)
7091
6715
  : new bn_js_1.default(positionData.totalYAmount);
7092
6716
  const _rebalanceLiquidityAutomation = (_a) => __awaiter(this, [_a], void 0, function* ({ position, maxDepositXAmount, maxDepositYAmount, pdaTokenType, shrinkMode, shouldClaimFee, shouldClaimReward, removeLiquidityParams, addLiquidityParams, maxActiveBinSlippage, }) {
@@ -7095,7 +6719,10 @@ class Transactions {
7095
6719
  userWallet: userWallet,
7096
6720
  position,
7097
6721
  lbPair,
7098
- tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
6722
+ tokenXMint,
6723
+ tokenYMint,
6724
+ tokenXProgram,
6725
+ tokenYProgram,
7099
6726
  activeId,
7100
6727
  pdaTokenType,
7101
6728
  maxActiveBinSlippage,
@@ -7127,7 +6754,9 @@ class Transactions {
7127
6754
  });
7128
6755
  });
7129
6756
  const withdrawFn = (_a) => __awaiter(this, [_a], void 0, function* ({ position, minBinId, maxBinId, compound, origin, }) {
7130
- const pdaTokenTypeForClaimables = compound ? types_1.TokenType.ATA : types_1.TokenType.STA;
6757
+ const pdaTokenTypeForClaimables = compound
6758
+ ? types_1.TokenType.ATA
6759
+ : types_1.TokenType.STA;
7131
6760
  const ixs = [];
7132
6761
  if (!skipClaim) {
7133
6762
  // 1. Claim fees with hawk-side cut (must happen before withdraw+shrink invalidates position)
@@ -7179,7 +6808,7 @@ class Transactions {
7179
6808
  maxBinId,
7180
6809
  shouldClaimReward: false,
7181
6810
  shouldClaimFee: false,
7182
- shrinkMode: types_3.ShrinkMode.Default,
6811
+ shrinkMode: types_3.ShrinkMode.NoShrinkBoth,
7183
6812
  pdaTokenType: types_1.TokenType.ATA,
7184
6813
  }),
7185
6814
  });
@@ -7261,17 +6890,18 @@ class Transactions {
7261
6890
  const ownerFeeReward = (0, functions_1.generateAta)(addresses_1.SITE_FEE_OWNER, pool.rewardMint);
7262
6891
  // Mints that need ATAs on userPdaLamport (for withdrawal)
7263
6892
  const withdrawMints = [
7264
- ...new Set([
7265
- pool.tokenMint.toString(),
7266
- pool.rewardMint.toString(),
7267
- ]),
6893
+ ...new Set([pool.tokenMint.toString(), pool.rewardMint.toString()]),
7268
6894
  ].map(v => new web3.PublicKey(v));
7269
6895
  // 1. Init ATAs for output token + reward on user PDA lamport
7270
6896
  const initAtaIxs = withdrawMints.map(mint => {
7271
6897
  return (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(userWallet, (0, functions_1.generateAta)(userPdaLamport, mint), userPdaLamport, mint);
7272
6898
  });
7273
6899
  // Init ATAs for reward-related tokens on userPda (for harvest)
7274
- const initHarvestAtaIxs = [pool.lpMint, pool.rewardMint, addresses_1.SABER_IOU_MINT].map(mint => {
6900
+ const initHarvestAtaIxs = [
6901
+ pool.lpMint,
6902
+ pool.rewardMint,
6903
+ addresses_1.SABER_IOU_MINT,
6904
+ ].map(mint => {
7275
6905
  return (0, spl_token_1.createAssociatedTokenAccountIdempotentInstruction)(userWallet, (0, functions_1.generateAta)(userPda, mint), userPda, mint);
7276
6906
  });
7277
6907
  // 2. Harvest rewards from Quarry