@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.
- package/dist/src/classes/Transactions.d.ts +8 -63
- package/dist/src/classes/Transactions.d.ts.map +1 -1
- package/dist/src/classes/Transactions.js +356 -726
- package/dist/src/classes/TxGeneratorAutomations.d.ts +7 -64
- package/dist/src/classes/TxGeneratorAutomations.d.ts.map +1 -1
- package/dist/src/classes/TxGeneratorAutomations.js +32 -203
- package/dist/src/ixGenerator/MeteoraDlmmIxGenerator.d.ts +46 -17
- package/dist/src/ixGenerator/MeteoraDlmmIxGenerator.d.ts.map +1 -1
- package/dist/src/ixGenerator/MeteoraDlmmIxGenerator.js +550 -186
- package/dist/src/types.d.ts +0 -39
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -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
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
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 =
|
|
6422
|
-
const
|
|
6423
|
-
const CLASS = '
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
6516
|
-
const
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
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 <=
|
|
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
|
-
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
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
|
|
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
|
-
|
|
6630
|
-
const
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
6742
|
-
const
|
|
6743
|
-
const CLASS = '
|
|
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,
|
|
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
|
|
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
|
|
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 <=
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
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
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
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
|
-
|
|
6853
|
-
|
|
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
|
-
|
|
6859
|
-
|
|
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
|
-
|
|
6862
|
-
const
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
6867
|
-
|
|
6868
|
-
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
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
|
-
|
|
6874
|
-
|
|
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, [
|
|
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({
|
|
7056
|
-
|
|
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
|
|
7085
|
-
|
|
7086
|
-
|
|
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 =
|
|
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,
|
|
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
|
|
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.
|
|
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 = [
|
|
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
|