@hawksightco/hawk-sdk 1.3.169 → 1.3.171
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/addresses.d.ts +1 -0
- package/dist/src/addresses.d.ts.map +1 -1
- package/dist/src/addresses.js +2 -1
- package/dist/src/classes/Transactions.d.ts +72 -1
- package/dist/src/classes/Transactions.d.ts.map +1 -1
- package/dist/src/classes/Transactions.js +560 -0
- package/dist/src/classes/TxGenerator.d.ts +72 -1
- package/dist/src/classes/TxGenerator.d.ts.map +1 -1
- package/dist/src/classes/TxGenerator.js +332 -0
- package/dist/src/functions.d.ts +18 -1
- package/dist/src/functions.d.ts.map +1 -1
- package/dist/src/functions.js +148 -0
- package/dist/src/idl/jupiter-idl.d.ts +36 -0
- package/dist/src/idl/jupiter-idl.d.ts.map +1 -1
- package/dist/src/idl/jupiter-idl.js +36 -0
- package/dist/src/ixGenerator/IyfMainIxGenerator.d.ts +6 -0
- package/dist/src/ixGenerator/IyfMainIxGenerator.d.ts.map +1 -1
- package/dist/src/ixGenerator/IyfMainIxGenerator.js +22 -0
- package/dist/src/ixGenerator/MeteoraDlmmIxGenerator.d.ts +167 -1
- package/dist/src/ixGenerator/MeteoraDlmmIxGenerator.d.ts.map +1 -1
- package/dist/src/ixGenerator/MeteoraDlmmIxGenerator.js +517 -0
- package/dist/src/meteora/index.d.ts +2 -0
- package/dist/src/meteora/index.d.ts.map +1 -0
- package/dist/src/meteora/index.js +17 -0
- package/dist/src/meteora/liquidityStrategy.d.ts +268 -0
- package/dist/src/meteora/liquidityStrategy.d.ts.map +1 -0
- package/dist/src/meteora/liquidityStrategy.js +1069 -0
- package/dist/src/meteora.d.ts +1 -0
- package/dist/src/meteora.d.ts.map +1 -1
- package/dist/src/meteora.js +6 -2
- package/dist/src/types.d.ts +139 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +16 -1
- package/package.json +7 -3
- package/test/artifacts/temp/.gitignore +2 -0
- package/test/artifacts/temp/accounts/.gitignore +2 -0
- package/test/visualization/output/.gitignore +2 -0
|
@@ -57,6 +57,7 @@ const orca_1 = require("../orca");
|
|
|
57
57
|
const OrcaPdaGenerator_1 = require("../pdaGenerator/OrcaPdaGenerator");
|
|
58
58
|
const hsToMeteora_1 = require("../hsToMeteora");
|
|
59
59
|
const meteora_1 = require("../meteora");
|
|
60
|
+
const liquidityStrategy_1 = require("../meteora/liquidityStrategy");
|
|
60
61
|
const anchor_1 = require("../anchor");
|
|
61
62
|
const types_2 = require("../types");
|
|
62
63
|
const Logging_1 = require("./Logging");
|
|
@@ -232,6 +233,43 @@ class Transactions {
|
|
|
232
233
|
});
|
|
233
234
|
});
|
|
234
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Creates meteora instruction that creates new position and deposit
|
|
238
|
+
* - Supports larger positions
|
|
239
|
+
*
|
|
240
|
+
* @param connection The Solana web3 connection object for blockchain interactions.
|
|
241
|
+
* @param payer The public key of the payer for transaction fees.
|
|
242
|
+
* @param params Parameters required
|
|
243
|
+
* @returns A ResponseWithStatus containing either TransactionMetadataResponse.
|
|
244
|
+
*/
|
|
245
|
+
meteoraCreatePositionAndDeposit2(_a) {
|
|
246
|
+
return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
|
|
247
|
+
// The logic is routed to meteoraDepositLargerPosition so that front-end no longer need
|
|
248
|
+
// to change anything in the front-end code.
|
|
249
|
+
// The only change they need to implement is the maximum number of bins allowed to
|
|
250
|
+
// initialize a position.
|
|
251
|
+
//
|
|
252
|
+
// Recommended bin range is up to 149 bins to ensure stability.
|
|
253
|
+
return yield this.meteoraDepositLargerPosition({
|
|
254
|
+
connection,
|
|
255
|
+
params: {
|
|
256
|
+
userWallet: params.userWallet,
|
|
257
|
+
lbPair: params.pool,
|
|
258
|
+
position: params.position,
|
|
259
|
+
lowerBinId: params.binRange.lowerRange,
|
|
260
|
+
upperBinId: params.binRange.upperRange,
|
|
261
|
+
totalXAmount: params.totalXAmount,
|
|
262
|
+
totalYAmount: params.totalYAmount,
|
|
263
|
+
distribution: params.distribution,
|
|
264
|
+
slippage: params.slippage,
|
|
265
|
+
skipInputTokenCheck: params.skipInputTokenCheck,
|
|
266
|
+
pdaTokenType: params.pdaTokenType,
|
|
267
|
+
initializePosition: true,
|
|
268
|
+
},
|
|
269
|
+
fetch: undefined,
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
}
|
|
235
273
|
/**
|
|
236
274
|
* Creates meteora instruction that creates new position and deposit.
|
|
237
275
|
*
|
|
@@ -426,6 +464,49 @@ class Transactions {
|
|
|
426
464
|
});
|
|
427
465
|
});
|
|
428
466
|
}
|
|
467
|
+
/**
|
|
468
|
+
* Creates meteora instruction that deposits to position.
|
|
469
|
+
*
|
|
470
|
+
* @param connection The Solana web3 connection object for blockchain interactions.
|
|
471
|
+
* @param payer The public key of the payer for transaction fees.
|
|
472
|
+
* @param params Parameters required
|
|
473
|
+
* @returns A ResponseWithStatus containing either TransactionMetadataResponse.
|
|
474
|
+
*/
|
|
475
|
+
meteoraDeposit2(_a) {
|
|
476
|
+
return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
|
|
477
|
+
const program = yield meteora_1.MeteoraDLMM.program(connection);
|
|
478
|
+
let lbPair, maxBinId, minBinId;
|
|
479
|
+
if (params.fastGeneration !== undefined) {
|
|
480
|
+
lbPair = params.fastGeneration.pool;
|
|
481
|
+
maxBinId = params.fastGeneration.upperBinId;
|
|
482
|
+
minBinId = params.fastGeneration.lowerBinId;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
const position = yield program.account.positionV2.fetch(params.position);
|
|
486
|
+
lbPair = position.lbPair;
|
|
487
|
+
maxBinId = position.upperBinId;
|
|
488
|
+
minBinId = position.lowerBinId;
|
|
489
|
+
}
|
|
490
|
+
return yield this.meteoraDepositLargerPosition({
|
|
491
|
+
connection,
|
|
492
|
+
params: {
|
|
493
|
+
userWallet: params.userWallet,
|
|
494
|
+
lbPair,
|
|
495
|
+
position: params.position,
|
|
496
|
+
lowerBinId: minBinId,
|
|
497
|
+
upperBinId: maxBinId,
|
|
498
|
+
totalXAmount: params.totalXAmount,
|
|
499
|
+
totalYAmount: params.totalYAmount,
|
|
500
|
+
distribution: params.distribution,
|
|
501
|
+
slippage: params.slippage,
|
|
502
|
+
skipInputTokenCheck: params.skipInputTokenCheck,
|
|
503
|
+
pdaTokenType: params.pdaTokenType,
|
|
504
|
+
initializePosition: false,
|
|
505
|
+
},
|
|
506
|
+
fetch: undefined,
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
}
|
|
429
510
|
/**
|
|
430
511
|
* Creates meteora instruction withdraws from a position.
|
|
431
512
|
*
|
|
@@ -586,6 +667,135 @@ class Transactions {
|
|
|
586
667
|
});
|
|
587
668
|
});
|
|
588
669
|
}
|
|
670
|
+
/**
|
|
671
|
+
* Withdraws liquidity from a Meteora DLMM position using simple instructions.
|
|
672
|
+
*
|
|
673
|
+
* Unlike meteoraWithdraw which uses Meteora SDK (that generates multiple claimFee ixs
|
|
674
|
+
* potentially bloating tx size), this method uses direct instructions:
|
|
675
|
+
* - removeLiquidityByRange2: Withdraw liquidity from the specified bin range
|
|
676
|
+
* - claimFee2: Single instruction to claim fees
|
|
677
|
+
* - claimReward2: N instructions (one per active reward)
|
|
678
|
+
* - closePositionIfEmpty: Closes position if shouldClaimAndClose is true
|
|
679
|
+
*
|
|
680
|
+
* @param connection The Solana web3 connection object for blockchain interactions.
|
|
681
|
+
* @param params Parameters required for withdrawal
|
|
682
|
+
* @returns A ResponseWithStatus containing TransactionMetadataResponse.
|
|
683
|
+
*/
|
|
684
|
+
meteoraWithdrawLargerPosition(_a) {
|
|
685
|
+
return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
|
|
686
|
+
const program = yield meteora_1.MeteoraDLMM.program(connection);
|
|
687
|
+
// Determine lbPair and bin range
|
|
688
|
+
let lbPair;
|
|
689
|
+
let lowerBinId;
|
|
690
|
+
let upperBinId;
|
|
691
|
+
if (params.fastGeneration !== undefined) {
|
|
692
|
+
// Use fastGeneration data
|
|
693
|
+
lbPair = params.fastGeneration.pool;
|
|
694
|
+
lowerBinId = params.fastGeneration.lowerBinId;
|
|
695
|
+
upperBinId = params.fastGeneration.upperBinId;
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
// Fetch position from blockchain
|
|
699
|
+
const position = yield program.account.positionV2.fetch(params.position);
|
|
700
|
+
lbPair = position.lbPair;
|
|
701
|
+
lowerBinId = position.lowerBinId;
|
|
702
|
+
upperBinId = position.upperBinId;
|
|
703
|
+
}
|
|
704
|
+
// Get pool data for token mints and programs
|
|
705
|
+
const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
|
|
706
|
+
const lbPairState = dlmmPool.dlmm.lbPair;
|
|
707
|
+
const tokenXMint = lbPairState.tokenXMint;
|
|
708
|
+
const tokenYMint = lbPairState.tokenYMint;
|
|
709
|
+
// Get token programs for each mint
|
|
710
|
+
const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
|
|
711
|
+
const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
|
|
712
|
+
const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
|
|
713
|
+
// Fetch remainingAccountsInfo for Token2022 transfer hooks (if any)
|
|
714
|
+
const remainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
|
|
715
|
+
const amountBps = params.shouldClaimAndClose
|
|
716
|
+
? new bn_js_1.default(10000)
|
|
717
|
+
: params.amountBps;
|
|
718
|
+
const mainInstructions = [];
|
|
719
|
+
// 1. removeLiquidityByRange2 - withdraw liquidity
|
|
720
|
+
const removeLiquidityIx = yield this.ix.meteoraDlmm.removeLiquidityByRange2({
|
|
721
|
+
connection,
|
|
722
|
+
userWallet: params.userWallet,
|
|
723
|
+
lbPair,
|
|
724
|
+
position: params.position,
|
|
725
|
+
tokenXMint,
|
|
726
|
+
tokenYMint,
|
|
727
|
+
tokenXProgram,
|
|
728
|
+
tokenYProgram,
|
|
729
|
+
fromBinId: lowerBinId,
|
|
730
|
+
toBinId: upperBinId,
|
|
731
|
+
bpsToRemove: amountBps.toNumber(),
|
|
732
|
+
pdaTokenType: params.pdaTokenType,
|
|
733
|
+
remainingAccountsInfo,
|
|
734
|
+
});
|
|
735
|
+
mainInstructions.push(removeLiquidityIx);
|
|
736
|
+
// 2. claimFee2 - single instruction to claim fees
|
|
737
|
+
const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2(connection, {
|
|
738
|
+
userWallet: params.userWallet,
|
|
739
|
+
lbPair,
|
|
740
|
+
position: params.position,
|
|
741
|
+
tokenMintX: tokenXMint,
|
|
742
|
+
tokenMintY: tokenYMint,
|
|
743
|
+
tokenProgramX: tokenXProgram,
|
|
744
|
+
tokenProgramY: tokenYProgram,
|
|
745
|
+
lowerBinId,
|
|
746
|
+
upperBinId,
|
|
747
|
+
});
|
|
748
|
+
mainInstructions.push(claimFeeIx);
|
|
749
|
+
// 3. claimReward2 - N instructions (one per active reward)
|
|
750
|
+
// Fetch lbPair account to get reward infos
|
|
751
|
+
const lbPairInfo = yield program.account.lbPair.fetch(lbPair);
|
|
752
|
+
for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
|
|
753
|
+
const rewardInfo = lbPairInfo.rewardInfos[rewardIndex];
|
|
754
|
+
// Skip if reward is not initialized (mint is default/zero pubkey)
|
|
755
|
+
if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default)) {
|
|
756
|
+
continue;
|
|
757
|
+
}
|
|
758
|
+
const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2(connection, {
|
|
759
|
+
userWallet: params.userWallet,
|
|
760
|
+
lbPair,
|
|
761
|
+
position: params.position,
|
|
762
|
+
rewardIndex,
|
|
763
|
+
rewardMint: rewardInfo.mint,
|
|
764
|
+
rewardVault: rewardInfo.vault,
|
|
765
|
+
tokenProgram: addresses_1.TOKEN_PROGRAM_ID,
|
|
766
|
+
lowerBinId,
|
|
767
|
+
upperBinId,
|
|
768
|
+
});
|
|
769
|
+
mainInstructions.push(claimRewardIx);
|
|
770
|
+
}
|
|
771
|
+
// 4. closePositionIfEmpty - only when shouldClaimAndClose is true
|
|
772
|
+
if (params.shouldClaimAndClose) {
|
|
773
|
+
const closePositionIx = yield this.ix.meteoraDlmm.closePositionIfEmpty({
|
|
774
|
+
connection,
|
|
775
|
+
userWallet: params.userWallet,
|
|
776
|
+
position: params.position,
|
|
777
|
+
});
|
|
778
|
+
mainInstructions.push(closePositionIx);
|
|
779
|
+
}
|
|
780
|
+
// Build description
|
|
781
|
+
let description;
|
|
782
|
+
if (params.shouldClaimAndClose) {
|
|
783
|
+
description = 'Full position withdrawal with claim and close from Meteora DLMM (larger position)';
|
|
784
|
+
}
|
|
785
|
+
else if (amountBps.eq(new bn_js_1.default(10000))) {
|
|
786
|
+
description = 'Full position withdrawal without close from Meteora DLMM (larger position)';
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
description = 'Partial position withdrawal from Meteora DLMM (larger position)';
|
|
790
|
+
}
|
|
791
|
+
return (0, functions_1.createTransactionMeta)({
|
|
792
|
+
payer: params.userWallet,
|
|
793
|
+
description,
|
|
794
|
+
addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
|
|
795
|
+
mainInstructions,
|
|
796
|
+
});
|
|
797
|
+
});
|
|
798
|
+
}
|
|
589
799
|
/**
|
|
590
800
|
* Creates meteora instruction that claims fees and rewards.
|
|
591
801
|
*
|
|
@@ -1603,6 +1813,355 @@ class Transactions {
|
|
|
1603
1813
|
}
|
|
1604
1814
|
throw new Error(`Unexpected error: Cannot find "RemoveLiquidityByRange" or "RemoveLiquidityByRange2" instruction from instructions`);
|
|
1605
1815
|
}
|
|
1816
|
+
/**
|
|
1817
|
+
* Creates a large position with more than 69 bins
|
|
1818
|
+
* - Known limitation: Can create a position with 1344 bins in a single transaction
|
|
1819
|
+
*
|
|
1820
|
+
* @param connection - Solana connection
|
|
1821
|
+
* @param params - Parameters containing userWallet, lbPair, position, lowerBinId, upperBinId
|
|
1822
|
+
* @returns Array of TransactionInstructions for initializing and extending the position
|
|
1823
|
+
*/
|
|
1824
|
+
meteoraInitializeLargePosition(_a) {
|
|
1825
|
+
return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
|
|
1826
|
+
const MAX_INIT_WIDTH = 70; // Maximum bins for initialize position
|
|
1827
|
+
const MAX_EXTEND_LENGTH = 91; // Maximum bins per increasePositionLength call
|
|
1828
|
+
const { userWallet, lbPair, position, lowerBinId, upperBinId } = params;
|
|
1829
|
+
// Calculate total bins needed
|
|
1830
|
+
const totalBins = upperBinId - lowerBinId + 1;
|
|
1831
|
+
// Validate bin count (max 1344 supported by Meteora)
|
|
1832
|
+
if (totalBins > 1344) {
|
|
1833
|
+
throw new Error(`Position size ${totalBins} bins exceeds maximum of 1344 bins`);
|
|
1834
|
+
}
|
|
1835
|
+
const instructions = [];
|
|
1836
|
+
// Step 1: Create initialize position (from lowerBinId with max 70 bins)
|
|
1837
|
+
const initWidth = Math.min(totalBins, MAX_INIT_WIDTH);
|
|
1838
|
+
const initializePositionIx = yield this.ix.meteoraDlmm.initializePosition({
|
|
1839
|
+
connection,
|
|
1840
|
+
userWallet,
|
|
1841
|
+
lbPair,
|
|
1842
|
+
position,
|
|
1843
|
+
lowerBinId,
|
|
1844
|
+
width: initWidth,
|
|
1845
|
+
});
|
|
1846
|
+
instructions.push(initializePositionIx);
|
|
1847
|
+
// Step 2: Extend to the right in chunks of 91 bins if needed
|
|
1848
|
+
// After init, we have bins from lowerBinId to lowerBinId + initWidth - 1
|
|
1849
|
+
// We need to extend up to upperBinId
|
|
1850
|
+
let currentUpperBinId = lowerBinId + initWidth - 1;
|
|
1851
|
+
while (currentUpperBinId < upperBinId) {
|
|
1852
|
+
// Calculate how many bins to add (max 91)
|
|
1853
|
+
const binsRemaining = upperBinId - currentUpperBinId;
|
|
1854
|
+
const binsToAdd = Math.min(binsRemaining, MAX_EXTEND_LENGTH);
|
|
1855
|
+
const extendIx = yield this.ix.meteoraDlmm.increasePositionLength({
|
|
1856
|
+
connection,
|
|
1857
|
+
userWallet,
|
|
1858
|
+
lbPair,
|
|
1859
|
+
position,
|
|
1860
|
+
lengthToAdd: binsToAdd,
|
|
1861
|
+
side: types_1.MeteoraPositionSide.Upper, // Extend to the right (upper side)
|
|
1862
|
+
});
|
|
1863
|
+
instructions.push(extendIx);
|
|
1864
|
+
currentUpperBinId += binsToAdd;
|
|
1865
|
+
}
|
|
1866
|
+
return (0, functions_1.createTransactionMeta)({
|
|
1867
|
+
payer: params.userWallet,
|
|
1868
|
+
description: 'Initialize large Meteora DLMM Position',
|
|
1869
|
+
addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
|
|
1870
|
+
mainInstructions: instructions,
|
|
1871
|
+
});
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
/**
|
|
1875
|
+
* Deposit liquidity to a large Meteora DLMM position using rebalanceLiquidity.
|
|
1876
|
+
* Splits the deposit into multiple transactions (one per chunk of bins)
|
|
1877
|
+
* to stay within Solana's account limit per transaction.
|
|
1878
|
+
*
|
|
1879
|
+
* @param connection - Solana connection
|
|
1880
|
+
* @param params - MeteoraDepositToLargePosition parameters
|
|
1881
|
+
* @returns Array of TransactionMetadataResponse, one per chunk
|
|
1882
|
+
*/
|
|
1883
|
+
meteoraDepositToLargePosition(_a) {
|
|
1884
|
+
return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
|
|
1885
|
+
const MAX_BINS_PER_TX = 149;
|
|
1886
|
+
const { userWallet, lbPair, position, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, lowerBinId, upperBinId, totalXAmount, totalYAmount, strategyType = liquidityStrategy_1.StrategyType.SPOT, favorXInActiveId = false, pdaTokenType, } = params;
|
|
1887
|
+
const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
|
|
1888
|
+
const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
|
|
1889
|
+
const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
|
|
1890
|
+
console.log(`Active ID: ${activeId}, Bin Step: ${binStep.toString()}`);
|
|
1891
|
+
// Calculate delta IDs relative to active bin for entire position
|
|
1892
|
+
const minDeltaId = new bn_js_1.default(lowerBinId - activeId);
|
|
1893
|
+
const maxDeltaId = new bn_js_1.default(upperBinId - activeId);
|
|
1894
|
+
// Build strategy parameters ONCE for entire position
|
|
1895
|
+
const strategyParams = (0, liquidityStrategy_1.buildStrategyParameters)(strategyType, totalXAmount, totalYAmount, minDeltaId, maxDeltaId, binStep, new bn_js_1.default(activeId), favorXInActiveId);
|
|
1896
|
+
console.log(`Strategy params - x0: ${strategyParams.x0.toString()}, y0: ${strategyParams.y0.toString()}, deltaX: ${strategyParams.deltaX.toString()}, deltaY: ${strategyParams.deltaY.toString()}`);
|
|
1897
|
+
// Chunk the deposit using the same strategy parameters
|
|
1898
|
+
const chunks = (0, liquidityStrategy_1.chunkDepositParameters)(strategyParams, minDeltaId, maxDeltaId, new bn_js_1.default(activeId), binStep, MAX_BINS_PER_TX, favorXInActiveId);
|
|
1899
|
+
console.log(`Total chunks: ${chunks.length}`);
|
|
1900
|
+
const transactions = [];
|
|
1901
|
+
// === TRANSACTION 1: Create LTA accounts and deposit tokens ===
|
|
1902
|
+
const depositInstructions = [];
|
|
1903
|
+
// Build deposit array for tokens with non-zero amounts
|
|
1904
|
+
const deposits = [];
|
|
1905
|
+
if (totalXAmount.gt(new bn_js_1.default(0))) {
|
|
1906
|
+
deposits.push({ mint: tokenXMint, amount: totalXAmount });
|
|
1907
|
+
}
|
|
1908
|
+
if (totalYAmount.gt(new bn_js_1.default(0))) {
|
|
1909
|
+
deposits.push({ mint: tokenYMint, amount: totalYAmount });
|
|
1910
|
+
}
|
|
1911
|
+
// Deposit tokens to ATA accounts
|
|
1912
|
+
if (deposits.length > 0) {
|
|
1913
|
+
depositInstructions.push(yield this.ix.iyfMain.depositMultipleTokenV2({
|
|
1914
|
+
connection,
|
|
1915
|
+
payer: userWallet,
|
|
1916
|
+
deposit: deposits,
|
|
1917
|
+
pdaTokenType,
|
|
1918
|
+
}));
|
|
1919
|
+
}
|
|
1920
|
+
let depositIncluded = false;
|
|
1921
|
+
// === TRANSACTIONS 2+: Chunked liquidity deposits ===
|
|
1922
|
+
for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
|
|
1923
|
+
const chunk = chunks[chunkIndex];
|
|
1924
|
+
// Convert strategy parameters to on-chain format with bitFlag for negative values
|
|
1925
|
+
const onChainParams = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunk.params.x0, chunk.params.y0, chunk.params.deltaX, chunk.params.deltaY);
|
|
1926
|
+
console.log(`Creating transaction ${chunkIndex + 2}/${chunks.length + 1} for bins ${chunk.lowerBinId} to ${chunk.upperBinId} -- deltaIds: ${chunk.minDeltaId.toString()} to ${chunk.maxDeltaId.toString()}, X: ${chunk.maxAmountX.toString()}, Y: ${chunk.maxAmountY.toString()}, bitFlag: ${onChainParams.bitFlag}`);
|
|
1927
|
+
const instructions = [];
|
|
1928
|
+
// Add deposit instruction at the beginning of the first transaction
|
|
1929
|
+
if (!depositIncluded) {
|
|
1930
|
+
depositIncluded = true;
|
|
1931
|
+
instructions.push(...depositInstructions);
|
|
1932
|
+
}
|
|
1933
|
+
// Add initialize bin arrays instruction
|
|
1934
|
+
const initBinArraysIx = yield this.ix.meteoraDlmm.meteoraDlmmInitializeBinArray({
|
|
1935
|
+
connection,
|
|
1936
|
+
userWallet,
|
|
1937
|
+
lbPair,
|
|
1938
|
+
lowerBinId: chunk.lowerBinId,
|
|
1939
|
+
upperBinId: chunk.upperBinId,
|
|
1940
|
+
});
|
|
1941
|
+
instructions.push(initBinArraysIx);
|
|
1942
|
+
// Add liquidity via rebalanceLiquidity
|
|
1943
|
+
// Note: Always use TokenType.LTA since we deposit to LTA in the first transaction
|
|
1944
|
+
const depositIx = yield this.ix.meteoraDlmm.rebalanceLiquidity({
|
|
1945
|
+
connection,
|
|
1946
|
+
userWallet,
|
|
1947
|
+
position,
|
|
1948
|
+
lbPair,
|
|
1949
|
+
tokenXMint,
|
|
1950
|
+
tokenYMint,
|
|
1951
|
+
tokenXProgram,
|
|
1952
|
+
tokenYProgram,
|
|
1953
|
+
activeId,
|
|
1954
|
+
pdaTokenType,
|
|
1955
|
+
// RebalanceLiquidityParams
|
|
1956
|
+
maxActiveBinSlippage: 300,
|
|
1957
|
+
shouldClaimFee: false,
|
|
1958
|
+
shouldClaimReward: false,
|
|
1959
|
+
minWithdrawXAmount: new bn_js_1.default(0),
|
|
1960
|
+
maxDepositXAmount: chunk.maxAmountX,
|
|
1961
|
+
minWithdrawYAmount: new bn_js_1.default(0),
|
|
1962
|
+
maxDepositYAmount: chunk.maxAmountY,
|
|
1963
|
+
removeLiquidityParams: [], // No removal
|
|
1964
|
+
addLiquidityParams: [{
|
|
1965
|
+
minDeltaId: chunk.minDeltaId.toNumber(),
|
|
1966
|
+
maxDeltaId: chunk.maxDeltaId.toNumber(),
|
|
1967
|
+
x0: onChainParams.x0,
|
|
1968
|
+
y0: onChainParams.y0,
|
|
1969
|
+
deltaX: onChainParams.deltaX,
|
|
1970
|
+
deltaY: onChainParams.deltaY,
|
|
1971
|
+
bitFlag: onChainParams.bitFlag,
|
|
1972
|
+
favorXInActiveId,
|
|
1973
|
+
}],
|
|
1974
|
+
});
|
|
1975
|
+
instructions.push(depositIx);
|
|
1976
|
+
// Create transaction for this chunk
|
|
1977
|
+
const txMeta = yield (0, functions_1.createTransactionMeta)({
|
|
1978
|
+
payer: userWallet,
|
|
1979
|
+
description: `Deposit to large Meteora DLMM Position (chunk ${chunkIndex + 1}/${chunks.length})`,
|
|
1980
|
+
addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
|
|
1981
|
+
mainInstructions: instructions,
|
|
1982
|
+
});
|
|
1983
|
+
transactions.push(txMeta);
|
|
1984
|
+
}
|
|
1985
|
+
return transactions;
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
/**
|
|
1989
|
+
* Deposit liquidity to a Meteora DLMM position (up to 128 bins) with optional position initialization.
|
|
1990
|
+
*
|
|
1991
|
+
* This method combines:
|
|
1992
|
+
* - Initialize bin arrays (meteoraDlmmInitializeBinArray) - idempotent
|
|
1993
|
+
* - Optionally initialize position (if initializePosition is true):
|
|
1994
|
+
* - For <= 70 bins: uses initializePositionAndAddLiquidityByStrategy
|
|
1995
|
+
* - For > 70 bins: uses initializePosition + increasePositionLength + addLiquidityByStrategy
|
|
1996
|
+
* - Add liquidity using addLiquidityByStrategy
|
|
1997
|
+
*
|
|
1998
|
+
* Designed for automation compatibility - all operations in a single transaction.
|
|
1999
|
+
* Note: Max 128 bins supported due to CU constraints with ATA-based deposits.
|
|
2000
|
+
*
|
|
2001
|
+
* @param connection - Solana connection
|
|
2002
|
+
* @param params - MeteoraDepositLargerPosition parameters
|
|
2003
|
+
* @returns Single TransactionMetadataResponse
|
|
2004
|
+
*/
|
|
2005
|
+
meteoraDepositLargerPosition(_a) {
|
|
2006
|
+
return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
|
|
2007
|
+
const MAX_INIT_WIDTH = 70; // Maximum bins for initialize position (hard limit)
|
|
2008
|
+
const MAX_EXTEND_LENGTH = 91; // Maximum bins per increasePositionLength call (hard limit)
|
|
2009
|
+
// const MAX_TOTAL_BINS = 128; // Maximum total bins supported in single tx (CU limitation with ATA deposit)
|
|
2010
|
+
const { userWallet, lbPair, position, lowerBinId, upperBinId, totalXAmount, totalYAmount, distribution, slippage, skipInputTokenCheck, pdaTokenType, initializePosition = true, } = params;
|
|
2011
|
+
// // Validate bin count
|
|
2012
|
+
const totalBins = upperBinId - lowerBinId + 1;
|
|
2013
|
+
// // NOTE: Max hard total bins allowed to initialize a position is 161 bins.
|
|
2014
|
+
// // But the recommended is only up to 149 bins to ensure stability.
|
|
2015
|
+
// const MAX_TOTAL_BINS = 161;
|
|
2016
|
+
// if (totalBins > MAX_TOTAL_BINS) {
|
|
2017
|
+
// throw new Error(`Position size ${totalBins} bins exceeds maximum of ${MAX_TOTAL_BINS} bins for single transaction`);
|
|
2018
|
+
// }
|
|
2019
|
+
// Get pool data
|
|
2020
|
+
const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
|
|
2021
|
+
const userPda = (0, functions_1.generateUserPda)(userWallet);
|
|
2022
|
+
const instructions = [];
|
|
2023
|
+
// Generate instructions that initializes bin arrays (but doesn't mean we will execute them)
|
|
2024
|
+
const initBinArraysIxs = yield this.ix.meteoraDlmm.meteoraDlmmInitializeBinArrayDefault({
|
|
2025
|
+
connection,
|
|
2026
|
+
userWallet,
|
|
2027
|
+
lbPair,
|
|
2028
|
+
lowerBinId,
|
|
2029
|
+
upperBinId,
|
|
2030
|
+
});
|
|
2031
|
+
// Get all bin arrays from given range
|
|
2032
|
+
const binArrays = meteora_1.MeteoraFunctions.findMeteoraTickArrays(lbPair, lowerBinId, upperBinId);
|
|
2033
|
+
// Check if these bin array accounts are already initialized (get multiple account info)
|
|
2034
|
+
const binArrayAccounts = yield (0, functions_1.getBatchedMultipleAccountsInfo)(connection, binArrays);
|
|
2035
|
+
// Loop through uninitialized bin arrays. We only inject instruction of uninitialized bin arrays.
|
|
2036
|
+
for (let i = 0; i < binArrayAccounts.length; i++) {
|
|
2037
|
+
if (binArrayAccounts[i] === null) {
|
|
2038
|
+
instructions.push(initBinArraysIxs[i]);
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
// Step 2: Either initialize position and add liquidity, or just add liquidity
|
|
2042
|
+
if (initializePosition) {
|
|
2043
|
+
if (totalBins <= MAX_INIT_WIDTH) {
|
|
2044
|
+
// Simple case: <= 70 bins - use initializePositionAndAddLiquidityByStrategy
|
|
2045
|
+
const initPositionAndAddLiquidityIxs = (yield dlmmPool.initializePositionAndAddLiquidityByStrategy(connection, userWallet, userWallet, {
|
|
2046
|
+
positionPubKey: position,
|
|
2047
|
+
totalXAmount,
|
|
2048
|
+
totalYAmount,
|
|
2049
|
+
strategy: {
|
|
2050
|
+
minBinId: lowerBinId,
|
|
2051
|
+
maxBinId: upperBinId,
|
|
2052
|
+
strategyType: types_3.StrategyTypeMap[distribution],
|
|
2053
|
+
},
|
|
2054
|
+
user: userPda,
|
|
2055
|
+
slippage,
|
|
2056
|
+
skipInputTokenCheck,
|
|
2057
|
+
opt: {
|
|
2058
|
+
pdaTokenType,
|
|
2059
|
+
},
|
|
2060
|
+
}, hsToMeteora_1.meteoraToHawksight)).default();
|
|
2061
|
+
// Filter out initializeBinArray instructions since we already initialized them above
|
|
2062
|
+
// with the correct funder (user wallet instead of user PDA)
|
|
2063
|
+
const initializeBinArraySighash = (0, functions_1.sighash)('initialize_bin_array');
|
|
2064
|
+
const filteredIxs = initPositionAndAddLiquidityIxs.filter(ix => {
|
|
2065
|
+
if (!ix.programId.equals(addresses_1.METEORA_DLMM_PROGRAM))
|
|
2066
|
+
return true;
|
|
2067
|
+
const ixSighash = ix.data.subarray(0, 8);
|
|
2068
|
+
return !Buffer.from(ixSighash).equals(Buffer.from(initializeBinArraySighash));
|
|
2069
|
+
});
|
|
2070
|
+
instructions.push(...filteredIxs);
|
|
2071
|
+
}
|
|
2072
|
+
else {
|
|
2073
|
+
// Complex case: > 70 bins - need to initialize position + extend + add liquidity separately
|
|
2074
|
+
// Step 2a: Initialize position with first 70 bins
|
|
2075
|
+
const initWidth = MAX_INIT_WIDTH;
|
|
2076
|
+
const initializePositionIx = yield this.ix.meteoraDlmm.initializePosition({
|
|
2077
|
+
connection,
|
|
2078
|
+
userWallet,
|
|
2079
|
+
lbPair,
|
|
2080
|
+
position,
|
|
2081
|
+
lowerBinId,
|
|
2082
|
+
width: initWidth,
|
|
2083
|
+
});
|
|
2084
|
+
instructions.push(initializePositionIx);
|
|
2085
|
+
// Step 2b: Extend position to cover all bins
|
|
2086
|
+
let currentUpperBinId = lowerBinId + initWidth - 1;
|
|
2087
|
+
while (currentUpperBinId < upperBinId) {
|
|
2088
|
+
const binsRemaining = upperBinId - currentUpperBinId;
|
|
2089
|
+
const binsToAdd = Math.min(binsRemaining, MAX_EXTEND_LENGTH);
|
|
2090
|
+
const extendIx = yield this.ix.meteoraDlmm.increasePositionLength({
|
|
2091
|
+
connection,
|
|
2092
|
+
userWallet,
|
|
2093
|
+
lbPair,
|
|
2094
|
+
position,
|
|
2095
|
+
lengthToAdd: binsToAdd,
|
|
2096
|
+
side: types_1.MeteoraPositionSide.Upper,
|
|
2097
|
+
});
|
|
2098
|
+
instructions.push(extendIx);
|
|
2099
|
+
currentUpperBinId += binsToAdd;
|
|
2100
|
+
}
|
|
2101
|
+
// Step 2c: Add liquidity to the full position
|
|
2102
|
+
const addLiquidityIxs = (yield dlmmPool.addLiquidityByStrategy(connection, userWallet, userWallet, {
|
|
2103
|
+
positionPubKey: position,
|
|
2104
|
+
totalXAmount,
|
|
2105
|
+
totalYAmount,
|
|
2106
|
+
strategy: {
|
|
2107
|
+
minBinId: lowerBinId,
|
|
2108
|
+
maxBinId: upperBinId,
|
|
2109
|
+
strategyType: types_3.StrategyTypeMap[distribution],
|
|
2110
|
+
},
|
|
2111
|
+
user: userPda,
|
|
2112
|
+
slippage,
|
|
2113
|
+
skipInputTokenCheck,
|
|
2114
|
+
pdaTokenType,
|
|
2115
|
+
}, hsToMeteora_1.meteoraToHawksight)).default();
|
|
2116
|
+
// Filter out initializeBinArray instructions since we already initialized them above
|
|
2117
|
+
// with the correct funder (user wallet instead of user PDA)
|
|
2118
|
+
const initializeBinArraySighash = (0, functions_1.sighash)('initialize_bin_array');
|
|
2119
|
+
const filteredIxs = addLiquidityIxs.filter(ix => {
|
|
2120
|
+
if (!ix.programId.equals(addresses_1.METEORA_DLMM_PROGRAM))
|
|
2121
|
+
return true;
|
|
2122
|
+
const ixSighash = ix.data.subarray(0, 8);
|
|
2123
|
+
return !Buffer.from(ixSighash).equals(Buffer.from(initializeBinArraySighash));
|
|
2124
|
+
});
|
|
2125
|
+
instructions.push(...filteredIxs);
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
else {
|
|
2129
|
+
// Just add liquidity to existing position
|
|
2130
|
+
const addLiquidityIxs = (yield dlmmPool.addLiquidityByStrategy(connection, userWallet, userWallet, {
|
|
2131
|
+
positionPubKey: position,
|
|
2132
|
+
totalXAmount,
|
|
2133
|
+
totalYAmount,
|
|
2134
|
+
strategy: {
|
|
2135
|
+
minBinId: lowerBinId,
|
|
2136
|
+
maxBinId: upperBinId,
|
|
2137
|
+
strategyType: types_3.StrategyTypeMap[distribution],
|
|
2138
|
+
},
|
|
2139
|
+
user: userPda,
|
|
2140
|
+
slippage,
|
|
2141
|
+
skipInputTokenCheck,
|
|
2142
|
+
pdaTokenType,
|
|
2143
|
+
}, hsToMeteora_1.meteoraToHawksight)).default();
|
|
2144
|
+
// Filter out initializeBinArray instructions since we already initialized them above
|
|
2145
|
+
// with the correct funder (user wallet instead of user PDA)
|
|
2146
|
+
const initializeBinArraySighash = (0, functions_1.sighash)('initialize_bin_array');
|
|
2147
|
+
const filteredIxs = addLiquidityIxs.filter(ix => {
|
|
2148
|
+
if (!ix.programId.equals(addresses_1.METEORA_DLMM_PROGRAM))
|
|
2149
|
+
return true;
|
|
2150
|
+
const ixSighash = ix.data.subarray(0, 8);
|
|
2151
|
+
return !Buffer.from(ixSighash).equals(Buffer.from(initializeBinArraySighash));
|
|
2152
|
+
});
|
|
2153
|
+
instructions.push(...filteredIxs);
|
|
2154
|
+
}
|
|
2155
|
+
return (0, functions_1.createTransactionMeta)({
|
|
2156
|
+
payer: userWallet,
|
|
2157
|
+
description: initializePosition
|
|
2158
|
+
? 'Initialize Meteora DLMM Position and deposit liquidity'
|
|
2159
|
+
: 'Deposit liquidity to Meteora DLMM Position',
|
|
2160
|
+
addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
|
|
2161
|
+
mainInstructions: instructions,
|
|
2162
|
+
});
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
1606
2165
|
/**
|
|
1607
2166
|
* Creates orca instruction that opens new position
|
|
1608
2167
|
*
|
|
@@ -1636,6 +2195,7 @@ class Transactions {
|
|
|
1636
2195
|
systemProgram: web3.SystemProgram.programId,
|
|
1637
2196
|
})
|
|
1638
2197
|
.instruction();
|
|
2198
|
+
// @ts-ignore
|
|
1639
2199
|
const orcaIx = yield anchor_1.Anchor.instance()
|
|
1640
2200
|
.iyfMain.methods.iyfExtensionExecute(extensionIx.data)
|
|
1641
2201
|
.accounts({
|