@hawksightco/hawk-sdk 1.3.200 → 1.3.202

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.
@@ -200,6 +200,8 @@ class Transactions {
200
200
  /**
201
201
  * Creates meteora instruction that creates new position and deposit.
202
202
  *
203
+ * @deprecated Use meteoraCreatePositionAndDepositToLargePosition instead.
204
+ *
203
205
  * @param connection The Solana web3 connection object for blockchain interactions.
204
206
  * @param payer The public key of the payer for transaction fees.
205
207
  * @param params Parameters required
@@ -237,6 +239,8 @@ class Transactions {
237
239
  * Creates meteora instruction that creates new position and deposit
238
240
  * - Supports larger positions
239
241
  *
242
+ * @deprecated Use meteoraCreatePositionAndDepositToLargePosition instead.
243
+ *
240
244
  * @param connection The Solana web3 connection object for blockchain interactions.
241
245
  * @param payer The public key of the payer for transaction fees.
242
246
  * @param params Parameters required
@@ -420,6 +424,8 @@ class Transactions {
420
424
  /**
421
425
  * Creates meteora instruction that deposits to position.
422
426
  *
427
+ * @deprecated Use meteoraDepositToLargePosition instead
428
+ *
423
429
  * @param connection The Solana web3 connection object for blockchain interactions.
424
430
  * @param payer The public key of the payer for transaction fees.
425
431
  * @param params Parameters required
@@ -467,6 +473,8 @@ class Transactions {
467
473
  /**
468
474
  * Creates meteora instruction that deposits to position.
469
475
  *
476
+ * @deprecated Use meteoraDepositToLargePosition instead
477
+ *
470
478
  * @param connection The Solana web3 connection object for blockchain interactions.
471
479
  * @param payer The public key of the payer for transaction fees.
472
480
  * @param params Parameters required
@@ -510,6 +518,8 @@ class Transactions {
510
518
  /**
511
519
  * Creates meteora instruction withdraws from a position.
512
520
  *
521
+ * @deprecated Use meteoraWithdrawLargePosition instead
522
+ *
513
523
  * @param connection The Solana web3 connection object for blockchain interactions.
514
524
  * @param payer The public key of the payer for transaction fees.
515
525
  * @param params Parameters required
@@ -670,6 +680,8 @@ class Transactions {
670
680
  /**
671
681
  * Withdraws liquidity from a Meteora DLMM position using simple instructions.
672
682
  *
683
+ * @deprecated Use meteoraWithdrawLargePosition instead
684
+ *
673
685
  * Unlike meteoraWithdraw which uses Meteora SDK (that generates multiple claimFee ixs
674
686
  * potentially bloating tx size), this method uses direct instructions:
675
687
  * - removeLiquidityByRange2: Withdraw liquidity from the specified bin range
@@ -682,118 +694,219 @@ class Transactions {
682
694
  * @returns A ResponseWithStatus containing TransactionMetadataResponse.
683
695
  */
684
696
  meteoraWithdrawLargerPosition(_a) {
697
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, fetch, }) {
698
+ const mainInstructions = yield this._meteoraWithdrawLargerPosition({ connection, params, fetch });
699
+ // Build description
700
+ let description;
701
+ if (params.shouldClaimAndClose) {
702
+ description = 'Full position withdrawal with claim and close from Meteora DLMM (larger position)';
703
+ }
704
+ else if (params.amountBps.eq(new bn_js_1.default(10000))) {
705
+ description = 'Full position withdrawal without close from Meteora DLMM (larger position)';
706
+ }
707
+ else {
708
+ description = 'Partial position withdrawal from Meteora DLMM (larger position)';
709
+ }
710
+ return (0, functions_1.createTransactionMeta)({
711
+ payer: params.userWallet,
712
+ description,
713
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
714
+ mainInstructions,
715
+ });
716
+ });
717
+ }
718
+ /**
719
+ * Withdraw liquidity from a large Meteora DLMM position (up to 1400 bins).
720
+ *
721
+ * - For ≤149 bins: delegates to meteoraWithdrawLargerPosition (single tx)
722
+ * - For ≥150 bins: resolves pool data once, chunks into ≤149-bin ranges,
723
+ * calls _buildWithdrawInstructions per chunk. Only the last chunk sets
724
+ * shouldClaimAndClose (if requested).
725
+ *
726
+ * @param connection The Solana web3 connection object for blockchain interactions.
727
+ * @param params MeteoraWithdrawLargerPosition parameters
728
+ * @returns Array of TransactionMetadataResponse, one per chunk
729
+ */
730
+ meteoraWithdrawLargePosition(_a) {
731
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
732
+ // Determine lbPair and bin range
733
+ let lbPair;
734
+ let lowerBinId;
735
+ let upperBinId;
736
+ if (params.fastGeneration !== undefined) {
737
+ lbPair = params.fastGeneration.pool;
738
+ lowerBinId = params.fastGeneration.lowerBinId;
739
+ upperBinId = params.fastGeneration.upperBinId;
740
+ }
741
+ else {
742
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
743
+ const position = yield program.account.positionV2.fetch(params.position);
744
+ lbPair = position.lbPair;
745
+ lowerBinId = position.lowerBinId;
746
+ upperBinId = position.upperBinId;
747
+ }
748
+ const totalBins = upperBinId - lowerBinId + 1;
749
+ // ≤149 bins: single-tx path
750
+ if (totalBins <= 149) {
751
+ const result = yield this.meteoraWithdrawLargerPosition({
752
+ connection,
753
+ params,
754
+ fetch: undefined,
755
+ });
756
+ return [result];
757
+ }
758
+ // ≥150 bins: multi-tx chunked withdraw
759
+ const resolved = yield this._resolveWithdrawPoolData({ connection, lbPair });
760
+ const amountBps = params.shouldClaimAndClose ? new bn_js_1.default(10000) : params.amountBps;
761
+ // Chunk into ≤149-bin ranges
762
+ const CHUNK_SIZE = 149;
763
+ const chunks = [];
764
+ for (let binStart = lowerBinId; binStart <= upperBinId; binStart += CHUNK_SIZE) {
765
+ const chunkUpper = Math.min(binStart + CHUNK_SIZE - 1, upperBinId);
766
+ chunks.push({ chunkLower: binStart, chunkUpper });
767
+ }
768
+ const transactions = [];
769
+ for (let i = 0; i < chunks.length; i++) {
770
+ const { chunkLower, chunkUpper } = chunks[i];
771
+ const isLastChunk = i === chunks.length - 1;
772
+ const instructions = yield this._buildWithdrawInstructions(Object.assign({ connection, userWallet: params.userWallet, position: params.position, lbPair, lowerBinId: chunkLower, upperBinId: chunkUpper, amountBps, shouldClaimAndClose: isLastChunk && params.shouldClaimAndClose, pdaTokenType: params.pdaTokenType }, resolved));
773
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
774
+ payer: params.userWallet,
775
+ description: `Withdraw from large Meteora DLMM Position (chunk ${i + 1}/${chunks.length})`,
776
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
777
+ mainInstructions: instructions,
778
+ }));
779
+ }
780
+ return transactions;
781
+ });
782
+ }
783
+ /**
784
+ * Withdraws liquidity from a Meteora DLMM position using simple instructions.
785
+ *
786
+ * Unlike meteoraWithdraw which uses Meteora SDK (that generates multiple claimFee ixs
787
+ * potentially bloating tx size), this method uses direct instructions:
788
+ * - removeLiquidityByRange2: Withdraw liquidity from the specified bin range
789
+ * - claimFee2: Single instruction to claim fees
790
+ * - claimReward2: N instructions (one per active reward)
791
+ * - closePositionIfEmpty: Closes position if shouldClaimAndClose is true
792
+ *
793
+ * @param connection The Solana web3 connection object for blockchain interactions.
794
+ * @param params Parameters required for withdrawal
795
+ * @returns A ResponseWithStatus containing TransactionMetadataResponse.
796
+ */
797
+ _meteoraWithdrawLargerPosition(_a) {
685
798
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
686
- const program = yield meteora_1.MeteoraDLMM.program(connection);
687
799
  // Determine lbPair and bin range
688
800
  let lbPair;
689
801
  let lowerBinId;
690
802
  let upperBinId;
691
803
  if (params.fastGeneration !== undefined) {
692
- // Use fastGeneration data
693
804
  lbPair = params.fastGeneration.pool;
694
805
  lowerBinId = params.fastGeneration.lowerBinId;
695
806
  upperBinId = params.fastGeneration.upperBinId;
696
807
  }
697
808
  else {
698
- // Fetch position from blockchain
809
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
699
810
  const position = yield program.account.positionV2.fetch(params.position);
700
811
  lbPair = position.lbPair;
701
812
  lowerBinId = position.lowerBinId;
702
813
  upperBinId = position.upperBinId;
703
814
  }
704
- // Get pool data for token mints and programs
815
+ // Resolve pool data
816
+ const resolved = yield this._resolveWithdrawPoolData({ connection, lbPair });
817
+ return this._buildWithdrawInstructions(Object.assign({ connection, userWallet: params.userWallet, position: params.position, lbPair,
818
+ lowerBinId,
819
+ upperBinId, amountBps: params.shouldClaimAndClose ? new bn_js_1.default(10000) : params.amountBps, shouldClaimAndClose: params.shouldClaimAndClose, pdaTokenType: params.pdaTokenType }, resolved));
820
+ });
821
+ }
822
+ /**
823
+ * Resolves pool data needed for withdraw instructions.
824
+ * Call once, then pass the result to _buildWithdrawInstructions for each chunk.
825
+ */
826
+ _resolveWithdrawPoolData(_a) {
827
+ return __awaiter(this, arguments, void 0, function* ({ connection, lbPair }) {
828
+ // Create DLMM pool first — this also initializes MeteoraDLMM._program
829
+ // so we don't need a separate MeteoraDLMM.program() call (which fetches a dummy pool).
705
830
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
831
+ const program = dlmmPool.dlmm.program;
706
832
  const lbPairState = dlmmPool.dlmm.lbPair;
707
833
  const tokenXMint = lbPairState.tokenXMint;
708
834
  const tokenYMint = lbPairState.tokenYMint;
709
- // Get token programs for each mint
710
835
  const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
711
836
  const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
712
837
  const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
713
- // Fetch remainingAccountsInfo for Token2022 transfer hooks (if any)
714
838
  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;
839
+ const lbPairInfo = yield program.account.lbPair.fetch(lbPair);
840
+ return { tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, remainingAccountsInfo, lbPairInfo };
841
+ });
842
+ }
843
+ /**
844
+ * Builds withdraw instructions for a single bin range chunk.
845
+ * Requires pre-resolved pool data (from _resolveWithdrawPoolData).
846
+ */
847
+ _buildWithdrawInstructions(params) {
848
+ return __awaiter(this, void 0, void 0, function* () {
718
849
  const mainInstructions = [];
719
850
  // 1. removeLiquidityByRange2 - withdraw liquidity
720
851
  const removeLiquidityIx = yield this.ix.meteoraDlmm.removeLiquidityByRange2({
721
- connection,
852
+ connection: params.connection,
722
853
  userWallet: params.userWallet,
723
- lbPair,
854
+ lbPair: params.lbPair,
724
855
  position: params.position,
725
- tokenXMint,
726
- tokenYMint,
727
- tokenXProgram,
728
- tokenYProgram,
729
- fromBinId: lowerBinId,
730
- toBinId: upperBinId,
731
- bpsToRemove: amountBps.toNumber(),
856
+ tokenXMint: params.tokenXMint,
857
+ tokenYMint: params.tokenYMint,
858
+ tokenXProgram: params.tokenXProgram,
859
+ tokenYProgram: params.tokenYProgram,
860
+ fromBinId: params.lowerBinId,
861
+ toBinId: params.upperBinId,
862
+ bpsToRemove: params.amountBps.toNumber(),
732
863
  pdaTokenType: params.pdaTokenType,
733
- remainingAccountsInfo,
864
+ remainingAccountsInfo: params.remainingAccountsInfo,
734
865
  });
735
866
  mainInstructions.push(removeLiquidityIx);
736
867
  // 2. claimFee2 - single instruction to claim fees
737
- const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2(connection, {
868
+ const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2(params.connection, {
738
869
  userWallet: params.userWallet,
739
- lbPair,
870
+ lbPair: params.lbPair,
740
871
  position: params.position,
741
- tokenMintX: tokenXMint,
742
- tokenMintY: tokenYMint,
743
- tokenProgramX: tokenXProgram,
744
- tokenProgramY: tokenYProgram,
745
- lowerBinId,
746
- upperBinId,
872
+ tokenMintX: params.tokenXMint,
873
+ tokenMintY: params.tokenYMint,
874
+ tokenProgramX: params.tokenXProgram,
875
+ tokenProgramY: params.tokenYProgram,
876
+ lowerBinId: params.lowerBinId,
877
+ upperBinId: params.upperBinId,
747
878
  });
748
879
  mainInstructions.push(claimFeeIx);
749
880
  // 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
881
  for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
753
- const rewardInfo = lbPairInfo.rewardInfos[rewardIndex];
882
+ const rewardInfo = params.lbPairInfo.rewardInfos[rewardIndex];
754
883
  // Skip if reward is not initialized (mint is default/zero pubkey)
755
884
  if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default)) {
756
885
  continue;
757
886
  }
758
- const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2(connection, {
887
+ const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2(params.connection, {
759
888
  userWallet: params.userWallet,
760
- lbPair,
889
+ lbPair: params.lbPair,
761
890
  position: params.position,
762
891
  rewardIndex,
763
892
  rewardMint: rewardInfo.mint,
764
893
  rewardVault: rewardInfo.vault,
765
894
  tokenProgram: addresses_1.TOKEN_PROGRAM_ID,
766
- lowerBinId,
767
- upperBinId,
895
+ lowerBinId: params.lowerBinId,
896
+ upperBinId: params.upperBinId,
768
897
  });
769
898
  mainInstructions.push(claimRewardIx);
770
899
  }
771
900
  // 4. closePositionIfEmpty - only when shouldClaimAndClose is true
772
901
  if (params.shouldClaimAndClose) {
773
902
  const closePositionIx = yield this.ix.meteoraDlmm.closePositionIfEmpty({
774
- connection,
903
+ connection: params.connection,
775
904
  userWallet: params.userWallet,
776
905
  position: params.position,
777
906
  });
778
907
  mainInstructions.push(closePositionIx);
779
908
  }
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
- });
909
+ return mainInstructions;
797
910
  });
798
911
  }
799
912
  /**
@@ -827,6 +940,99 @@ class Transactions {
827
940
  return txMeta;
828
941
  });
829
942
  }
943
+ /**
944
+ * Claim fees and rewards from a large Meteora DLMM position (up to 1400 bins).
945
+ *
946
+ * For ≤149 bins, delegates to the single-TX meteoraClaim.
947
+ * For ≥150 bins, chunks the bin range into ≤149-bin pieces and builds
948
+ * claimFee2 + claimReward2 per chunk, returning multiple TXs.
949
+ *
950
+ * @param connection The Solana web3 connection object for blockchain interactions.
951
+ * @param params MeteoraClaim parameters (userWallet, position, fastGeneration)
952
+ * @returns Array of TransactionMetadataResponse, one per chunk
953
+ */
954
+ meteoraClaimLargePosition(_a) {
955
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
956
+ // Determine lbPair and bin range
957
+ let lbPair;
958
+ let lowerBinId;
959
+ let upperBinId;
960
+ if (params.fastGeneration !== undefined) {
961
+ lbPair = params.fastGeneration.pool;
962
+ // fastGeneration for MeteoraClaim doesn't include bin IDs, so we must fetch
963
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
964
+ const position = yield program.account.positionV2.fetch(params.position);
965
+ lowerBinId = position.lowerBinId;
966
+ upperBinId = position.upperBinId;
967
+ }
968
+ else {
969
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
970
+ const position = yield program.account.positionV2.fetch(params.position);
971
+ lbPair = position.lbPair;
972
+ lowerBinId = position.lowerBinId;
973
+ upperBinId = position.upperBinId;
974
+ }
975
+ const totalBins = upperBinId - lowerBinId + 1;
976
+ // ≤149 bins: single-tx path
977
+ if (totalBins <= 149) {
978
+ const result = yield this.meteoraClaim({ connection, params, fetch: undefined });
979
+ return [result];
980
+ }
981
+ // ≥150 bins: multi-tx chunked claim
982
+ const resolved = yield this._resolveWithdrawPoolData({ connection, lbPair });
983
+ // Chunk into ≤149-bin ranges
984
+ const CHUNK_SIZE = 149;
985
+ const chunks = [];
986
+ for (let binStart = lowerBinId; binStart <= upperBinId; binStart += CHUNK_SIZE) {
987
+ const chunkUpper = Math.min(binStart + CHUNK_SIZE - 1, upperBinId);
988
+ chunks.push({ chunkLower: binStart, chunkUpper });
989
+ }
990
+ const transactions = [];
991
+ for (let i = 0; i < chunks.length; i++) {
992
+ const { chunkLower, chunkUpper } = chunks[i];
993
+ const instructions = [];
994
+ // claimFee2 for this chunk
995
+ const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2(connection, {
996
+ userWallet: params.userWallet,
997
+ lbPair,
998
+ position: params.position,
999
+ tokenMintX: resolved.tokenXMint,
1000
+ tokenMintY: resolved.tokenYMint,
1001
+ tokenProgramX: resolved.tokenXProgram,
1002
+ tokenProgramY: resolved.tokenYProgram,
1003
+ lowerBinId: chunkLower,
1004
+ upperBinId: chunkUpper,
1005
+ });
1006
+ instructions.push(claimFeeIx);
1007
+ // claimReward2 per chunk for each active reward
1008
+ for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
1009
+ const rewardInfo = resolved.lbPairInfo.rewardInfos[rewardIndex];
1010
+ if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default)) {
1011
+ continue;
1012
+ }
1013
+ const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2(connection, {
1014
+ userWallet: params.userWallet,
1015
+ lbPair,
1016
+ position: params.position,
1017
+ rewardIndex,
1018
+ rewardMint: rewardInfo.mint,
1019
+ rewardVault: rewardInfo.vault,
1020
+ tokenProgram: addresses_1.TOKEN_PROGRAM_ID,
1021
+ lowerBinId: chunkLower,
1022
+ upperBinId: chunkUpper,
1023
+ });
1024
+ instructions.push(claimRewardIx);
1025
+ }
1026
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
1027
+ payer: params.userWallet,
1028
+ description: `Claim from large Meteora DLMM Position (chunk ${i + 1}/${chunks.length})`,
1029
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1030
+ mainInstructions: instructions,
1031
+ }));
1032
+ }
1033
+ return transactions;
1034
+ });
1035
+ }
830
1036
  /**
831
1037
  * Claim all meteora fees and rewards by list of pools owned by given user
832
1038
  *
@@ -982,6 +1188,9 @@ class Transactions {
982
1188
  });
983
1189
  });
984
1190
  }
1191
+ /**
1192
+ * @deprecated Use compoundFromLargePositionAutomationIx instead
1193
+ */
985
1194
  compoundAutomationIx(_a) {
986
1195
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
987
1196
  var _b;
@@ -1138,119 +1347,363 @@ class Transactions {
1138
1347
  }
1139
1348
  });
1140
1349
  }
1350
+ /**
1351
+ * @deprecated Use claimFromLargePositionAutomationIx instead
1352
+ *
1353
+ * @param param0
1354
+ * @returns
1355
+ */
1141
1356
  claimAutomationIx(_a) {
1142
- return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1143
- try {
1144
- console.log('=== CLAIM AUTOMATION IX START ===');
1145
- console.log('Params:', {
1146
- userWallet: params.userWallet.toString(),
1147
- position: params.position.toString(),
1148
- });
1149
- const program = yield meteora_1.MeteoraDLMM.program(connection);
1150
- console.log('Program fetched successfully');
1151
- const position = yield program.account.positionV2.fetch(params.position);
1152
- console.log('Position fetched:', {
1153
- lbPair: position.lbPair.toString(),
1154
- owner: position.owner.toString(),
1155
- lowerBinId: position.lowerBinId.toString(),
1156
- upperBinId: position.upperBinId.toString(),
1157
- });
1158
- const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, position.lbPair, this.ix);
1159
- console.log('DLMM pool created successfully');
1160
- const userPda = (0, functions_1.generateUserPda)(params.userWallet);
1161
- console.log('User PDA generated:', userPda.toString());
1162
- const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
1163
- console.log('User positions fetched, count:', userPositions.length);
1164
- const userPosition = userPositions.find(userPosition => userPosition.publicKey.equals(params.position));
1165
- if (userPosition === undefined) {
1166
- throw new Error(`Position: ${params.position} does not exist.`);
1167
- }
1168
- console.log('User position found');
1169
- // Claim fee and claim reward ixs
1170
- console.log('Creating MeteoraFunctions...');
1171
- const fn = new meteora_1.MeteoraFunctions(this.ix);
1172
- console.log('Calling claimAllRewardsByPosition...');
1173
- const claimBuilder = yield fn.claimAllRewardsByPosition(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1174
- owner: userPda,
1175
- position: params.position,
1176
- lbPair: position.lbPair,
1177
- pdaTokenType: types_1.TokenType.STA,
1178
- }, hsToMeteora_1.meteoraToHawksightAutomationIxs);
1179
- console.log('Claim builder created successfully');
1180
- const mainInstructions = [
1181
- ...claimBuilder.mainIxs,
1182
- ];
1183
- console.log('=== CLAIM AUTOMATION IX SUCCESS ===');
1184
- try {
1185
- console.log('Creating transaction metadata...');
1186
- const result = (0, functions_1.createTransactionMeta)({
1187
- payer: params.userWallet,
1188
- description: 'Automation IX: Meteora Auto-claim instructions (claim fee, reward)',
1189
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1190
- mainInstructions,
1191
- });
1192
- console.log('Transaction metadata created successfully');
1193
- return result;
1194
- }
1195
- catch (metadataError) {
1196
- console.error('=== TRANSACTION METADATA ERROR ===');
1197
- console.error('Error creating transaction metadata:', metadataError);
1198
- console.error('Main instructions count:', mainInstructions.length);
1199
- console.error('Main instructions:', mainInstructions.map(ix => ({
1200
- programId: ix.programId.toString(),
1201
- keysCount: ix.keys.length,
1202
- dataLength: ix.data.length,
1203
- })));
1204
- console.error('=== END METADATA ERROR LOG ===');
1205
- throw metadataError;
1206
- }
1207
- }
1208
- catch (error) {
1209
- console.error('=== CLAIM AUTOMATION IX ERROR ===');
1210
- console.error('Error type:', error instanceof Error ? error.constructor.name : typeof error);
1211
- console.error('Error message:', error instanceof Error ? error.message : String(error));
1212
- console.error('Error stack:', error instanceof Error ? error.stack : 'No stack trace');
1213
- console.error('Full error object:', error);
1214
- console.error('=== END CLAIM AUTOMATION ERROR LOG ===');
1215
- throw error;
1216
- }
1217
- });
1218
- }
1219
- rebalanceAutomationIx(_a) {
1220
1357
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1221
1358
  const program = yield meteora_1.MeteoraDLMM.program(connection);
1222
- const position = yield program.account.positionV2.fetch(params.currentPosition);
1359
+ const position = yield program.account.positionV2.fetch(params.position);
1360
+ if (!position || !position.lbPair) {
1361
+ throw new Error(`Invalid position data: ${params.position}`);
1362
+ }
1223
1363
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, position.lbPair, this.ix);
1224
1364
  const userPda = (0, functions_1.generateUserPda)(params.userWallet);
1225
- // Step 1: Claim all fees/rewards, remove all liquidity and close current position
1226
1365
  const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
1227
- const userPosition = userPositions.find(userPosition => userPosition.publicKey.equals(params.currentPosition));
1366
+ const userPosition = userPositions.find(userPosition => userPosition.publicKey.equals(params.position));
1228
1367
  if (userPosition === undefined) {
1229
- throw new Error(`Position: ${params.currentPosition} does not exist.`);
1368
+ throw new Error(`Position: ${params.position} does not exist.`);
1230
1369
  }
1231
- const binIdsToRemove = userPosition.positionData.positionBinData.map(bin => bin.binId);
1232
- const removeLiquidityBuilder = yield dlmmPool.removeLiquidity(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1233
- user: userPda,
1234
- position: params.currentPosition,
1235
- fromBinId: position.lowerBinId,
1236
- toBinId: position.upperBinId,
1237
- bps: new bn_js_1.default(10000),
1238
- shouldClaimAndClose: true,
1370
+ // Claim fee and claim reward ixs
1371
+ const fn = new meteora_1.MeteoraFunctions(this.ix);
1372
+ const claimBuilder = yield fn.claimAllRewardsByPosition(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1373
+ owner: userPda,
1374
+ position: params.position,
1375
+ lbPair: position.lbPair,
1376
+ pdaTokenType: types_1.TokenType.STA,
1239
1377
  }, hsToMeteora_1.meteoraToHawksightAutomationIxs);
1240
- if (!!params.useAta) {
1241
- removeLiquidityBuilder.replaceClaimFeeTokenToATA();
1242
- removeLiquidityBuilder.replaceClaimRewardToATA();
1243
- }
1244
- else {
1245
- removeLiquidityBuilder.replaceClaimFeeTokenToSTA();
1246
- removeLiquidityBuilder.replaceClaimRewardToSTA();
1247
- }
1248
- // Re-deposit fees (TODO: How to re-deposit reward tokens that is not X or Y token?)
1249
- const initPositionAndAddLiquidityBuilder = yield dlmmPool.initializePositionAndAddLiquidityByStrategy(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1250
- positionPubKey: params.newPosition,
1251
- user: userPda,
1252
- totalXAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1253
- totalYAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1378
+ const mainInstructions = [
1379
+ ...claimBuilder.mainIxs,
1380
+ ];
1381
+ return (0, functions_1.createTransactionMeta)({
1382
+ payer: params.userWallet,
1383
+ description: 'Automation IX: Meteora Auto-claim instructions (claim fee, reward)',
1384
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1385
+ mainInstructions,
1386
+ });
1387
+ });
1388
+ }
1389
+ /**
1390
+ * Claim fees and rewards from a large Meteora DLMM position (up to 1400 bins).
1391
+ *
1392
+ * For ≤149 bins, delegates to the single-TX claimAutomationIx.
1393
+ * For ≥150 bins, chunks the bin range into ≤149-bin pieces and builds
1394
+ * claimFee2Automation + claimReward2Automation per chunk, returning multiple TXs.
1395
+ *
1396
+ * @param connection The Solana web3 connection object for blockchain interactions.
1397
+ * @param params Parameters required for claim (MeteoraCompound: userWallet, position)
1398
+ * @returns Array of TransactionMetadataResponse for each transaction
1399
+ */
1400
+ claimFromLargePositionAutomationIx(_a) {
1401
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1402
+ try {
1403
+ // Fetch position data
1404
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
1405
+ const positionData = yield program.account.positionV2.fetch(params.position);
1406
+ if (!positionData || !positionData.lbPair) {
1407
+ throw new Error(`Invalid position data: ${params.position.toString()}`);
1408
+ }
1409
+ const lbPair = positionData.lbPair;
1410
+ const lowerBinId = positionData.lowerBinId;
1411
+ const upperBinId = positionData.upperBinId;
1412
+ const binCount = upperBinId - lowerBinId + 1;
1413
+ // For ≤149 bins, delegate to existing single-TX claimAutomationIx
1414
+ if (binCount <= 149) {
1415
+ const singleResult = yield this.claimAutomationIx({ connection, params, fetch: undefined });
1416
+ return [singleResult];
1417
+ }
1418
+ // ≥150 bins: chunked multi-TX approach
1419
+ // Resolve pool data (tokens, programs, remaining accounts)
1420
+ const resolved = yield this._resolveWithdrawPoolData({ connection, lbPair });
1421
+ const { tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, remainingAccountsInfo, lbPairInfo } = resolved;
1422
+ // Get reward infos from lbPair state
1423
+ const rewardInfos = lbPairInfo.rewardInfos;
1424
+ // Chunk [lowerBinId, upperBinId] into ≤149-bin pieces
1425
+ const MAX_BINS_PER_CHUNK = 149;
1426
+ const chunks = [];
1427
+ let current = lowerBinId;
1428
+ while (current <= upperBinId) {
1429
+ const upper = Math.min(current + MAX_BINS_PER_CHUNK - 1, upperBinId);
1430
+ chunks.push({ lower: current, upper });
1431
+ current = upper + 1;
1432
+ }
1433
+ // Pre-resolve reward info (avoid repeated RPC calls)
1434
+ const rewardIxBuilders = [];
1435
+ for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
1436
+ const rewardInfo = rewardInfos[rewardIndex];
1437
+ if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default)) {
1438
+ continue;
1439
+ }
1440
+ const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [rewardInfo.mint]);
1441
+ const rewardTokenProgram = rewardTokenProgramMap[rewardInfo.mint.toString()];
1442
+ const rewardRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, rewardInfo.mint, rewardTokenProgram);
1443
+ rewardIxBuilders.push({
1444
+ rewardIndex,
1445
+ rewardMint: rewardInfo.mint,
1446
+ rewardVault: rewardInfo.vault,
1447
+ rewardTokenProgram,
1448
+ rewardRemainingAccountsInfo,
1449
+ });
1450
+ }
1451
+ // Build instructions per chunk
1452
+ const transactions = [];
1453
+ for (let i = 0; i < chunks.length; i++) {
1454
+ const chunk = chunks[i];
1455
+ const instructions = [];
1456
+ // claimFee2Automation for this chunk
1457
+ const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2Automation(connection, {
1458
+ userWallet: params.userWallet,
1459
+ lbPair,
1460
+ position: params.position,
1461
+ tokenMintX: tokenXMint,
1462
+ tokenMintY: tokenYMint,
1463
+ tokenProgramX: tokenXProgram,
1464
+ tokenProgramY: tokenYProgram,
1465
+ lowerBinId: chunk.lower,
1466
+ upperBinId: chunk.upper,
1467
+ pdaTokenType: types_1.TokenType.STA,
1468
+ remainingAccountsInfo,
1469
+ });
1470
+ instructions.push(claimFeeIx);
1471
+ // claimReward2Automation per chunk for each active reward
1472
+ for (const reward of rewardIxBuilders) {
1473
+ const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2Automation(connection, {
1474
+ userWallet: params.userWallet,
1475
+ lbPair,
1476
+ position: params.position,
1477
+ rewardIndex: reward.rewardIndex,
1478
+ rewardMint: reward.rewardMint,
1479
+ rewardVault: reward.rewardVault,
1480
+ tokenProgram: reward.rewardTokenProgram,
1481
+ lowerBinId: chunk.lower,
1482
+ upperBinId: chunk.upper,
1483
+ pdaTokenType: types_1.TokenType.STA,
1484
+ remainingAccountsInfo: reward.rewardRemainingAccountsInfo,
1485
+ });
1486
+ instructions.push(claimRewardIx);
1487
+ }
1488
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
1489
+ payer: params.userWallet,
1490
+ description: `Automation IX: Claim from large position (tx ${i + 1}/${chunks.length})`,
1491
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1492
+ mainInstructions: instructions,
1493
+ }));
1494
+ }
1495
+ return transactions;
1496
+ }
1497
+ catch (error) {
1498
+ throw error;
1499
+ }
1500
+ });
1501
+ }
1502
+ /**
1503
+ * Compound (claim + re-deposit) fees and rewards from a large Meteora DLMM position (up to 1400 bins).
1504
+ *
1505
+ * For ≤149 bins, delegates to the single-TX compoundAutomationIx.
1506
+ * For ≥150 bins:
1507
+ * Phase 1: Chunked claim (claimFee2Automation + claimReward2Automation per chunk, to ATA)
1508
+ * Phase 2: Chunked re-deposit (rebalanceLiquidityAutomation per chunk, back into same position)
1509
+ *
1510
+ * @param connection The Solana web3 connection object for blockchain interactions.
1511
+ * @param params MeteoraCompound parameters (userWallet, position, distribution)
1512
+ * @returns Array of TransactionMetadataResponse for each transaction
1513
+ */
1514
+ compoundFromLargePositionAutomationIx(_a) {
1515
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1516
+ var _b, _c;
1517
+ try {
1518
+ // Fetch position data
1519
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
1520
+ const positionData = yield program.account.positionV2.fetch(params.position);
1521
+ if (!positionData || !positionData.lbPair) {
1522
+ throw new Error(`Invalid position data: ${params.position.toString()}`);
1523
+ }
1524
+ const lbPair = positionData.lbPair;
1525
+ const lowerBinId = positionData.lowerBinId;
1526
+ const upperBinId = positionData.upperBinId;
1527
+ const binCount = upperBinId - lowerBinId + 1;
1528
+ // For ≤149 bins, delegate to existing single-TX compoundAutomationIx
1529
+ if (binCount <= 149) {
1530
+ const singleResult = yield this.compoundAutomationIx({ connection, params, fetch: undefined });
1531
+ return [singleResult];
1532
+ }
1533
+ // ≥150 bins: chunked multi-TX approach
1534
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
1535
+ // For compound, we use dummy equal amounts for deposit strategy calculation.
1536
+ // The on-chain RebalanceLiquidity overrides totalXAmount/totalYAmount with ATA balance,
1537
+ // so these values only affect the strategy ratio. Using equal amounts (like the single-TX
1538
+ // compoundAutomationIx does with 100_000) ensures the strategy distributes evenly and
1539
+ // doesn't try to transfer more of one token than is available from claimed fees.
1540
+ const totalXAmount = new bn_js_1.default(100000);
1541
+ const totalYAmount = new bn_js_1.default(100000);
1542
+ const lbPairState = dlmmPool.dlmm.lbPair;
1543
+ const tokenXMint = lbPairState.tokenXMint;
1544
+ const tokenYMint = lbPairState.tokenYMint;
1545
+ const rewardInfos = lbPairState.rewardInfos;
1546
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
1547
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
1548
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
1549
+ const remainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
1550
+ const lbPairInfo = yield (program.account.lbPair.fetch(lbPair));
1551
+ // =========================================================================
1552
+ // Phase 1: Chunked claim (to ATA for re-deposit)
1553
+ // =========================================================================
1554
+ const MAX_BINS_PER_CHUNK = 149;
1555
+ const chunks = [];
1556
+ let current = lowerBinId;
1557
+ while (current <= upperBinId) {
1558
+ const upper = Math.min(current + MAX_BINS_PER_CHUNK - 1, upperBinId);
1559
+ chunks.push({ lower: current, upper });
1560
+ current = upper + 1;
1561
+ }
1562
+ // Pre-resolve reward info
1563
+ const rewardIxBuilders = [];
1564
+ for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
1565
+ const rewardInfo = rewardInfos[rewardIndex];
1566
+ if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default)) {
1567
+ continue;
1568
+ }
1569
+ const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [rewardInfo.mint]);
1570
+ const rewardTokenProgram = rewardTokenProgramMap[rewardInfo.mint.toString()];
1571
+ const rewardRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, rewardInfo.mint, rewardTokenProgram);
1572
+ rewardIxBuilders.push({
1573
+ rewardIndex,
1574
+ rewardMint: rewardInfo.mint,
1575
+ rewardVault: rewardInfo.vault,
1576
+ rewardTokenProgram,
1577
+ rewardRemainingAccountsInfo,
1578
+ });
1579
+ }
1580
+ // Build claim instructions per chunk (to ATA for compound)
1581
+ const claimTxs = [];
1582
+ for (const chunk of chunks) {
1583
+ const instructions = [];
1584
+ const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2Automation(connection, {
1585
+ userWallet: params.userWallet,
1586
+ lbPair,
1587
+ position: params.position,
1588
+ tokenMintX: tokenXMint,
1589
+ tokenMintY: tokenYMint,
1590
+ tokenProgramX: tokenXProgram,
1591
+ tokenProgramY: tokenYProgram,
1592
+ lowerBinId: chunk.lower,
1593
+ upperBinId: chunk.upper,
1594
+ pdaTokenType: types_1.TokenType.ATA,
1595
+ remainingAccountsInfo,
1596
+ });
1597
+ instructions.push(claimFeeIx);
1598
+ for (const reward of rewardIxBuilders) {
1599
+ const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2Automation(connection, {
1600
+ userWallet: params.userWallet,
1601
+ lbPair,
1602
+ position: params.position,
1603
+ rewardIndex: reward.rewardIndex,
1604
+ rewardMint: reward.rewardMint,
1605
+ rewardVault: reward.rewardVault,
1606
+ tokenProgram: reward.rewardTokenProgram,
1607
+ lowerBinId: chunk.lower,
1608
+ upperBinId: chunk.upper,
1609
+ pdaTokenType: types_1.TokenType.ATA,
1610
+ remainingAccountsInfo: reward.rewardRemainingAccountsInfo,
1611
+ });
1612
+ instructions.push(claimRewardIx);
1613
+ }
1614
+ claimTxs.push(instructions);
1615
+ }
1616
+ // =========================================================================
1617
+ // Phase 2: Chunked re-deposit back into the same position
1618
+ // =========================================================================
1619
+ const distributionToStrategyType = {
1620
+ 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
1621
+ 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
1622
+ 'BID-ASK': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-IMBALANCED': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-ONE-SIDE': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-BALANCED': liquidityStrategy_1.StrategyType.BID_ASK,
1623
+ };
1624
+ const strategyType = (_c = distributionToStrategyType[(_b = params.distribution) !== null && _b !== void 0 ? _b : 'SPOT-IMBALANCED']) !== null && _c !== void 0 ? _c : liquidityStrategy_1.StrategyType.SPOT;
1625
+ const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
1626
+ const depositTxs = yield this._meteoraDepositToLargePositionAutomation({
1627
+ connection,
1628
+ userWallet: params.userWallet,
1629
+ lbPair,
1630
+ position: params.position,
1631
+ tokenXMint,
1632
+ tokenYMint,
1633
+ tokenXProgram,
1634
+ tokenYProgram,
1635
+ lowerBinId,
1636
+ upperBinId,
1637
+ strategyType,
1638
+ activeId,
1639
+ totalXAmount,
1640
+ totalYAmount,
1641
+ });
1642
+ // =========================================================================
1643
+ // Phase 3: Assemble transactions
1644
+ // =========================================================================
1645
+ const assembled = [
1646
+ ...claimTxs,
1647
+ ...depositTxs,
1648
+ ];
1649
+ const transactions = [];
1650
+ for (let i = 0; i < assembled.length; i++) {
1651
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
1652
+ payer: params.userWallet,
1653
+ description: `Automation IX: Compound large position (tx ${i + 1}/${assembled.length})`,
1654
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1655
+ mainInstructions: assembled[i],
1656
+ }));
1657
+ }
1658
+ return transactions;
1659
+ }
1660
+ catch (error) {
1661
+ throw error;
1662
+ }
1663
+ });
1664
+ }
1665
+ /**
1666
+ * @deprecated Use rebalanceLargerPositionAutomation instead
1667
+ *
1668
+ * @param connection The Solana web3 connection object for blockchain interactions.
1669
+ * @param params Parameters required for rebalance
1670
+ * @returns A ResponseWithStatus containing TransactionMetadataResponse.
1671
+ */
1672
+ rebalanceAutomationIx(_a) {
1673
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1674
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
1675
+ const position = yield program.account.positionV2.fetch(params.currentPosition);
1676
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, position.lbPair, this.ix);
1677
+ const userPda = (0, functions_1.generateUserPda)(params.userWallet);
1678
+ // Step 1: Claim all fees/rewards, remove all liquidity and close current position
1679
+ const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
1680
+ const userPosition = userPositions.find(userPosition => userPosition.publicKey.equals(params.currentPosition));
1681
+ if (userPosition === undefined) {
1682
+ throw new Error(`Position: ${params.currentPosition} does not exist.`);
1683
+ }
1684
+ const binIdsToRemove = userPosition.positionData.positionBinData.map(bin => bin.binId);
1685
+ const removeLiquidityBuilder = yield dlmmPool.removeLiquidity(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1686
+ user: userPda,
1687
+ position: params.currentPosition,
1688
+ fromBinId: position.lowerBinId,
1689
+ toBinId: position.upperBinId,
1690
+ bps: new bn_js_1.default(10000),
1691
+ shouldClaimAndClose: true,
1692
+ }, hsToMeteora_1.meteoraToHawksightAutomationIxs);
1693
+ if (!!params.useAta) {
1694
+ removeLiquidityBuilder.replaceClaimFeeTokenToATA();
1695
+ removeLiquidityBuilder.replaceClaimRewardToATA();
1696
+ }
1697
+ else {
1698
+ removeLiquidityBuilder.replaceClaimFeeTokenToSTA();
1699
+ removeLiquidityBuilder.replaceClaimRewardToSTA();
1700
+ }
1701
+ // Re-deposit fees (TODO: How to re-deposit reward tokens that is not X or Y token?)
1702
+ const initPositionAndAddLiquidityBuilder = yield dlmmPool.initializePositionAndAddLiquidityByStrategy(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1703
+ positionPubKey: params.newPosition,
1704
+ user: userPda,
1705
+ totalXAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1706
+ totalYAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1254
1707
  strategy: {
1255
1708
  maxBinId: params.binRange.upperRange,
1256
1709
  minBinId: params.binRange.lowerRange,
@@ -1274,6 +1727,13 @@ class Transactions {
1274
1727
  });
1275
1728
  });
1276
1729
  }
1730
+ /**
1731
+ * @deprecated Use rebalanceLargerPositionAutomation instaed
1732
+ *
1733
+ * @param connection The Solana web3 connection object for blockchain interactions.
1734
+ * @param params Parameters required for rebalance
1735
+ * @returns A ResponseWithStatus containing TransactionMetadataResponse.
1736
+ */
1277
1737
  rebalanceAutomationIx2(_a) {
1278
1738
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1279
1739
  var _b;
@@ -1597,20 +2057,6 @@ class Transactions {
1597
2057
  *
1598
2058
  * @param connection The Solana web3 connection object for blockchain interactions.
1599
2059
  * @param params Parameters required for rebalance (same as MeteoraRebalance)
1600
- * @returns A TransactionMetadataResponse containing the transaction metadata
1601
- */
1602
- /**
1603
- * Rebalance a Meteora DLMM position to a new bin range (supports up to 149 bins).
1604
- *
1605
- * This method chunks the rebalance into multiple transactions:
1606
- * - TX 1: Remove liquidity + claim fees + claim rewards + close position
1607
- * - TX 2: Initialize new position + extend position (if > 70 bins)
1608
- * - TX 3: Initialize bin array + add liquidity (if > 70 bins)
1609
- *
1610
- * For positions <= 70 bins, TX 2 and TX 3 are combined into a single transaction.
1611
- *
1612
- * @param connection - Solana connection
1613
- * @param params - MeteoraRebalance parameters
1614
2060
  * @returns Array of TransactionMetadataResponse for each transaction
1615
2061
  */
1616
2062
  rebalanceLargerPositionAutomation(_a) {
@@ -1870,65 +2316,829 @@ class Transactions {
1870
2316
  }
1871
2317
  });
1872
2318
  }
1873
- openAutomationIx(_a) {
1874
- return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1875
- const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.pool, this.ix);
1876
- const userPda = (0, functions_1.generateUserPda)(params.userWallet);
1877
- // Open new position
1878
- const initPositionAndAddLiquidityBuilder = yield dlmmPool.initializePositionAndAddLiquidityByStrategy(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
1879
- positionPubKey: params.position,
1880
- user: userPda,
1881
- slippage: params.slippage,
1882
- totalXAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1883
- totalYAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
1884
- strategy: {
1885
- maxBinId: params.binRange.upperRange,
1886
- minBinId: params.binRange.lowerRange,
1887
- strategyType: types_3.StrategyTypeMap[params.distribution],
1888
- },
1889
- skipInputTokenCheck: true, // Rebalance should be independent of user wallet TA
1890
- opt: {
1891
- pdaTokenType: params.opt.pdaTokenType,
1892
- withAmount: {
1893
- userTokenXAmount: params.opt.withAmount.userTokenXAmount,
1894
- userTokenYAmount: params.opt.withAmount.userTokenYAmount,
1895
- },
1896
- fuelAccount: params.opt.fuelAccount,
1897
- },
1898
- }, hsToMeteora_1.meteoraToHawksightAutomationIxs);
1899
- const mainInstructions = [...initPositionAndAddLiquidityBuilder.mainIxs];
1900
- return (0, functions_1.createTransactionMeta)({
1901
- payer: params.userWallet,
1902
- description: 'Automation IX: Meteora Open instruction (Open position)',
1903
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1904
- mainInstructions,
1905
- });
1906
- });
1907
- }
1908
- relativeOpenAutomationIx(_a) {
2319
+ /**
2320
+ * Rebalance a large Meteora DLMM position (up to 1400 bins) using automation instructions.
2321
+ *
2322
+ * For ≤149 bins, delegates to rebalanceLargerPositionAutomation.
2323
+ * For ≥150 bins, uses a chunked multi-TX approach:
2324
+ * Phase 1: Chunked withdraw from current position
2325
+ * Phase 2: Initialize new large position
2326
+ * Phase 3: Chunked deposit to new position
2327
+ *
2328
+ * @param connection The Solana web3 connection object for blockchain interactions.
2329
+ * @param params Parameters required for rebalance
2330
+ * @returns Array of TransactionMetadataResponse for each transaction
2331
+ */
2332
+ rebalanceLargePositionAutomation(_a) {
1909
2333
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
1910
- const { userWallet, pool, position, relativeBinRange, checkRange, distribution, targetActiveBin, fuelAccount, pdaTokenType, userTokenXAmount, userTokenYAmount } = params;
1911
- const openParams = {
1912
- userWallet,
1913
- lbPair: pool,
1914
- position,
1915
- relativeLowerBinId: relativeBinRange.lowerRange,
1916
- relativeUpperBinId: relativeBinRange.upperRange,
1917
- strategyType: types_3.StrategyTypeMap[distribution],
1918
- checkRange: {
1919
- minBinId: checkRange.lowerRange,
1920
- maxBinId: checkRange.upperRange,
1921
- },
1922
- targetActiveBin: targetActiveBin !== null && targetActiveBin !== void 0 ? targetActiveBin : undefined,
1923
- useFuelAccount: fuelAccount !== null && fuelAccount !== void 0 ? fuelAccount : false,
1924
- pdaTokenType,
1925
- userTokenXAmount,
1926
- userTokenYAmount,
1927
- };
1928
- const openIx = yield this.ix.meteoraDlmm.relativeOpenAutomation(connection, openParams);
1929
- return (0, functions_1.createTransactionMeta)({
1930
- payer: params.userWallet,
1931
- description: 'Automation IX: Meteora Open with relative bins',
2334
+ var _b;
2335
+ try {
2336
+ // Fetch position to get lbPair and bin range
2337
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
2338
+ const positionData = yield program.account.positionV2.fetch(params.currentPosition);
2339
+ if (!positionData || !positionData.lbPair) {
2340
+ throw new Error(`Invalid position data: ${params.currentPosition.toString()}`);
2341
+ }
2342
+ const lbPair = positionData.lbPair;
2343
+ const currentLowerBinId = positionData.lowerBinId;
2344
+ const currentUpperBinId = positionData.upperBinId;
2345
+ const currentBinCount = currentUpperBinId - currentLowerBinId + 1;
2346
+ // For ≤149 bins, delegate to existing rebalanceLargerPositionAutomation
2347
+ if (currentBinCount <= 149 && params.width <= 149) {
2348
+ return this.rebalanceLargerPositionAutomation({ connection, params, fetch: undefined });
2349
+ }
2350
+ // ≥150 bins: multi-TX chunked approach
2351
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
2352
+ const userPda = (0, functions_1.generateUserPda)(params.userWallet);
2353
+ // Get position's token amounts for deposit strategy calculation
2354
+ const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
2355
+ const userPosition = userPositions.find(pos => pos.publicKey.equals(params.currentPosition));
2356
+ if (!userPosition) {
2357
+ throw new Error(`Position ${params.currentPosition.toString()} not found`);
2358
+ }
2359
+ const positionBinData = userPosition.positionData.positionBinData;
2360
+ const { totalXAmount, totalYAmount } = positionBinData.reduce((acc, bin) => ({
2361
+ totalXAmount: acc.totalXAmount.add(new bn_js_1.default(bin.positionXAmount)),
2362
+ totalYAmount: acc.totalYAmount.add(new bn_js_1.default(bin.positionYAmount)),
2363
+ }), { totalXAmount: new bn_js_1.default(0), totalYAmount: new bn_js_1.default(0) });
2364
+ const lbPairState = dlmmPool.dlmm.lbPair;
2365
+ const tokenXMint = lbPairState.tokenXMint;
2366
+ const tokenYMint = lbPairState.tokenYMint;
2367
+ const rewardInfos = lbPairState.rewardInfos;
2368
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
2369
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
2370
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
2371
+ const remainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2372
+ const lbPairInfo = yield (program.account.lbPair.fetch(lbPair));
2373
+ // Whether to compound during rebalance, or nope.
2374
+ const pdaTokenTypeForClaimables = params.useAta ? types_1.TokenType.ATA : types_1.TokenType.STA;
2375
+ // =========================================================================
2376
+ // Merged approach: withdraw + init/extend + deposit per TX (~75 bins each)
2377
+ // =========================================================================
2378
+ const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2379
+ const distributionToStrategyType = {
2380
+ 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
2381
+ 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
2382
+ 'BID-ASK': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-IMBALANCED': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-ONE-SIDE': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-BALANCED': liquidityStrategy_1.StrategyType.BID_ASK,
2383
+ };
2384
+ const strategyType = (_b = distributionToStrategyType[params.distribution]) !== null && _b !== void 0 ? _b : liquidityStrategy_1.StrategyType.SPOT;
2385
+ const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
2386
+ const assembled = yield this._buildMergedRebalanceChunks({
2387
+ connection,
2388
+ userWallet: params.userWallet,
2389
+ lbPair,
2390
+ oldPosition: params.currentPosition,
2391
+ oldLowerBinId: currentLowerBinId,
2392
+ oldUpperBinId: currentUpperBinId,
2393
+ newPosition: params.newPosition,
2394
+ relativeLowerBinId: params.relativeLowerBin,
2395
+ width: params.width,
2396
+ tokenXMint,
2397
+ tokenYMint,
2398
+ tokenXProgram,
2399
+ tokenYProgram,
2400
+ remainingAccountsInfo,
2401
+ lbPairInfo,
2402
+ rewardInfos,
2403
+ pdaTokenTypeForClaimables,
2404
+ binStep,
2405
+ strategyType,
2406
+ activeId,
2407
+ totalXAmount,
2408
+ totalYAmount,
2409
+ });
2410
+ // Wrap each instruction array with createTransactionMeta
2411
+ const transactions = [];
2412
+ for (let i = 0; i < assembled.length; i++) {
2413
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
2414
+ payer: params.userWallet,
2415
+ description: `Automation IX: Rebalance large position (tx ${i + 1}/${assembled.length})`,
2416
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2417
+ mainInstructions: assembled[i],
2418
+ }));
2419
+ }
2420
+ return transactions;
2421
+ }
2422
+ catch (error) {
2423
+ console.error('=== REBALANCE LARGE POSITION AUTOMATION ERROR ===');
2424
+ console.error('Error type:', error instanceof Error ? error.constructor.name : typeof error);
2425
+ console.error('Error message:', error instanceof Error ? error.message : String(error));
2426
+ console.error('Error stack:', error instanceof Error ? error.stack : 'No stack trace');
2427
+ console.error('Full error object:', error);
2428
+ console.error('=== END ERROR LOG ===');
2429
+ throw error;
2430
+ }
2431
+ });
2432
+ }
2433
+ /**
2434
+ * Generates a single rebalanceLiquidityAutomation instruction for reshaping a Meteora DLMM position.
2435
+ *
2436
+ * This is a low-level building block that creates ONE instruction to:
2437
+ * - Remove liquidity from specified bins (removeLiquidityParams)
2438
+ * - Add liquidity to new bins (addLiquidityParams)
2439
+ *
2440
+ * Unlike meteoraRebalanceLargePositionAutomation2 which handles full position reshaping
2441
+ * with chunking and multiple TXs, this function returns a single instruction that can
2442
+ * be composed into custom transaction flows.
2443
+ *
2444
+ * Features:
2445
+ * - Token2022 transfer hook support
2446
+ * - No fee/reward claiming (shouldClaimFee: false, shouldClaimReward: false)
2447
+ * - Uses ATA token accounts
2448
+ * - NoShrinkBoth shrink mode
2449
+ *
2450
+ * Note: Not part of test suite yet. For remove + add liquidity params, please fork
2451
+ * hawk-api/src/meteora/liquidityStrategy.ts to generate the parameters.
2452
+ *
2453
+ * @param connection Solana web3 connection
2454
+ * @param params Reshape parameters including position, bin ranges, and liquidity params
2455
+ * @returns LabeledInstructions with single 'rebalance_liquidity' instruction
2456
+ */
2457
+ meteoraReshapePositionAutomation(_a) {
2458
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2459
+ var _b, _c;
2460
+ // Fetch pool data
2461
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.lbPair, this.ix);
2462
+ const lbPairState = dlmmPool.dlmm.lbPair;
2463
+ const tokenXMint = lbPairState.tokenXMint;
2464
+ const tokenYMint = lbPairState.tokenYMint;
2465
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
2466
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
2467
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
2468
+ // Fetch transfer hook accounts for token X and Y (Token2022 support)
2469
+ const baseRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2470
+ // Build combined remainingAccountsInfo with transfer hooks for X, Y, and rewards
2471
+ // The slices describe: TransferHookX, TransferHookY, TransferHookMultiReward(index) for each reward
2472
+ // IMPORTANT: Always include all slices, even with length=0, so Meteora knows the account structure
2473
+ const combinedSlices = [];
2474
+ const combinedAccounts = [];
2475
+ // Always add TransferHookX and TransferHookY slices (even if length=0)
2476
+ const xSlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookX);
2477
+ const ySlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookY);
2478
+ combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookX, length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0 });
2479
+ combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookY, length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0 });
2480
+ // Add transfer hook accounts from base (for X and Y)
2481
+ combinedAccounts.push(...baseRemainingAccountsInfo.accounts);
2482
+ const remainingAccountsInfo = {
2483
+ slices: combinedSlices,
2484
+ accounts: combinedAccounts,
2485
+ };
2486
+ return {
2487
+ instructions: [yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2488
+ connection,
2489
+ userWallet: params.userWallet,
2490
+ position: params.position,
2491
+ lbPair: params.lbPair,
2492
+ tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2493
+ activeId: params.activeId,
2494
+ pdaTokenType: types_1.TokenType.ATA,
2495
+ maxActiveBinSlippage: 300,
2496
+ shouldClaimFee: false,
2497
+ shouldClaimReward: false,
2498
+ minWithdrawXAmount: new bn_js_1.default(0),
2499
+ maxDepositXAmount: new bn_js_1.default(0),
2500
+ minWithdrawYAmount: new bn_js_1.default(0),
2501
+ maxDepositYAmount: new bn_js_1.default(0),
2502
+ removeLiquidityParams: params.removeLiquidityParams,
2503
+ addLiquidityParams: params.addLiquidityParams,
2504
+ shrinkMode: types_3.ShrinkMode.NoShrinkBoth,
2505
+ remainingAccountsInfo,
2506
+ })],
2507
+ labels: ['rebalance_liquidity'],
2508
+ };
2509
+ });
2510
+ }
2511
+ /**
2512
+ * @note DO NOT USE. STILL UNDER DEVELOPMENT. Tests still failing
2513
+ * Reshape position: withdraw from old bins and deposit to new bins on the SAME position.
2514
+ *
2515
+ * Uses only rebalanceLiquidityAutomation (one IX per TX):
2516
+ * Remove TXs: rebalanceLiquidityAutomation with removeLiquidityParams (~75 bins/TX)
2517
+ * Deposit TXs: rebalanceLiquidityAutomation with addLiquidityParams (~75 bins/TX)
2518
+ *
2519
+ * Meteora's rebalance_liquidity handles position extension and bin array
2520
+ * initialization internally — no separate IXs needed.
2521
+ *
2522
+ * Key differences from rebalanceLargePositionAutomation:
2523
+ * - Same position (no close/create, no new position keypair needed)
2524
+ * - Supports positions of any size (69 to 1400+ bins)
2525
+ */
2526
+ meteoraRebalanceLargePositionAutomation2(_a) {
2527
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2528
+ var _b, _c, _d;
2529
+ try {
2530
+ const WITHDRAW_CHUNK_SIZE = 260;
2531
+ const DEPOSIT_CHUNK_SIZE = 200;
2532
+ const DEPOSIT_CHUNK_INITIAL_SIZE = 150;
2533
+ // Always reserve a small portion of bins for the pivot TX to ensure
2534
+ // withdraw + deposit happen together (prevents ReallocExceedMaxLengthPerInstruction)
2535
+ const PIVOT_RESERVE = 160;
2536
+ // Fetch pool data
2537
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.lbPair, this.ix);
2538
+ const userPda = (0, functions_1.generateUserPda)(params.userWallet);
2539
+ const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2540
+ // Get position's token amounts for deposit strategy calculation
2541
+ const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
2542
+ const userPosition = userPositions.find(pos => pos.publicKey.equals(params.position));
2543
+ if (!userPosition) {
2544
+ throw new Error(`Position ${params.position.toString()} not found`);
2545
+ }
2546
+ const positionBinData = userPosition.positionData.positionBinData;
2547
+ // Use actual liquidity range (bins with non-zero amounts) instead of padded position struct range
2548
+ const binsWithLiquidity = positionBinData.filter(bin => !new bn_js_1.default(bin.positionXAmount).isZero() || !new bn_js_1.default(bin.positionYAmount).isZero());
2549
+ const oldLowerBinId = binsWithLiquidity.length > 0
2550
+ ? binsWithLiquidity[0].binId
2551
+ : userPosition.positionData.lowerBinId;
2552
+ const oldUpperBinId = binsWithLiquidity.length > 0
2553
+ ? binsWithLiquidity[binsWithLiquidity.length - 1].binId
2554
+ : userPosition.positionData.upperBinId;
2555
+ const { totalXAmount, totalYAmount } = positionBinData.reduce((acc, bin) => ({
2556
+ totalXAmount: acc.totalXAmount.add(new bn_js_1.default(bin.positionXAmount)),
2557
+ totalYAmount: acc.totalYAmount.add(new bn_js_1.default(bin.positionYAmount)),
2558
+ }), { totalXAmount: new bn_js_1.default(0), totalYAmount: new bn_js_1.default(0) });
2559
+ const newLowerBinId = activeId + params.relativeLowerBin;
2560
+ const newUpperBinId = newLowerBinId + params.width - 1;
2561
+ console.log(`Total chunk per tx (withdraw): ${WITHDRAW_CHUNK_SIZE} bins, total chunk per tx (deposit): ${DEPOSIT_CHUNK_SIZE} bins`);
2562
+ console.log(`old lower bin id: ${oldLowerBinId}, old upper bin id: ${oldUpperBinId}, old width: ${oldUpperBinId - oldLowerBinId + 1}`);
2563
+ console.log(`new lower bin id: ${newLowerBinId}, new upper bin id: ${newUpperBinId}, new width: ${newUpperBinId - newLowerBinId + 1}`);
2564
+ const lbPairState = dlmmPool.dlmm.lbPair;
2565
+ const tokenXMint = lbPairState.tokenXMint;
2566
+ const tokenYMint = lbPairState.tokenYMint;
2567
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
2568
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
2569
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
2570
+ // Fetch transfer hook accounts for token X and Y (Token2022 support)
2571
+ const baseRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2572
+ // Extract reward infos for claiming rewards during rebalance
2573
+ const rewardInfos = [];
2574
+ const rewardInfosFromPair = lbPairState.rewardInfos;
2575
+ if (rewardInfosFromPair && rewardInfosFromPair.length > 0) {
2576
+ // Collect reward mints that are active (non-default)
2577
+ const activeRewardMints = [];
2578
+ for (const reward of rewardInfosFromPair) {
2579
+ if (!reward.mint.equals(web3.PublicKey.default)) {
2580
+ activeRewardMints.push(reward.mint);
2581
+ }
2582
+ }
2583
+ // Get token programs for reward mints
2584
+ if (activeRewardMints.length > 0) {
2585
+ const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, activeRewardMints);
2586
+ for (let i = 0; i < rewardInfosFromPair.length; i++) {
2587
+ const reward = rewardInfosFromPair[i];
2588
+ if (!reward.mint.equals(web3.PublicKey.default)) {
2589
+ rewardInfos.push({
2590
+ rewardIndex: i,
2591
+ rewardVault: reward.vault,
2592
+ rewardMint: reward.mint,
2593
+ rewardTokenProgram: rewardTokenProgramMap[reward.mint.toString()],
2594
+ });
2595
+ }
2596
+ }
2597
+ }
2598
+ }
2599
+ console.log(`[Pipeline] Found ${rewardInfos.length} active reward(s) for this pool`);
2600
+ // Build combined remainingAccountsInfo with transfer hooks for X, Y, and rewards
2601
+ // The slices describe: TransferHookX, TransferHookY, TransferHookMultiReward(index) for each reward
2602
+ // IMPORTANT: Always include all slices, even with length=0, so Meteora knows the account structure
2603
+ const combinedSlices = [];
2604
+ const combinedAccounts = [];
2605
+ // Always add TransferHookX and TransferHookY slices (even if length=0)
2606
+ const xSlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookX);
2607
+ const ySlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookY);
2608
+ combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookX, length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0 });
2609
+ combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookY, length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0 });
2610
+ // Add transfer hook accounts from base (for X and Y)
2611
+ combinedAccounts.push(...baseRemainingAccountsInfo.accounts);
2612
+ // Fetch transfer hook accounts for each reward and add to combined info
2613
+ // IMPORTANT: Always add TransferHookMultiReward slice for each reward, even if length=0
2614
+ // This tells Meteora about the reward position in the remaining accounts
2615
+ for (const reward of rewardInfos) {
2616
+ const rewardTransferHookInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, reward.rewardMint, reward.rewardTokenProgram);
2617
+ // Always add TransferHookMultiReward slice (even if empty length for standard SPL tokens)
2618
+ const transferHookLength = rewardTransferHookInfo.slices.length > 0
2619
+ ? rewardTransferHookInfo.slices[0].length
2620
+ : 0;
2621
+ combinedSlices.push({
2622
+ accountsType: types_1.RemainingAccountsType.TransferHookMultiReward,
2623
+ length: transferHookLength,
2624
+ multiRewardIndex: reward.rewardIndex,
2625
+ });
2626
+ combinedAccounts.push(...rewardTransferHookInfo.accounts);
2627
+ }
2628
+ const remainingAccountsInfo = {
2629
+ slices: combinedSlices,
2630
+ accounts: combinedAccounts,
2631
+ };
2632
+ const distributionToStrategyType = {
2633
+ 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
2634
+ 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
2635
+ 'BID-ASK': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-IMBALANCED': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-ONE-SIDE': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-BALANCED': liquidityStrategy_1.StrategyType.BID_ASK,
2636
+ };
2637
+ const strategyType = (_d = distributionToStrategyType[params.distribution]) !== null && _d !== void 0 ? _d : liquidityStrategy_1.StrategyType.SPOT;
2638
+ const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
2639
+ // Build new-position deposit chunks
2640
+ const minDeltaId = new bn_js_1.default(newLowerBinId - activeId);
2641
+ const maxDeltaId = new bn_js_1.default(newUpperBinId - activeId);
2642
+ const favorXInActiveId = totalYAmount.isZero() && !totalXAmount.isZero();
2643
+ const strategyParams = (0, liquidityStrategy_1.buildStrategyParameters)(strategyType, totalXAmount, totalYAmount, minDeltaId, maxDeltaId, binStep, new bn_js_1.default(activeId), favorXInActiveId);
2644
+ // =====================================================================
2645
+ // Pipeline algorithm: pack withdraw + deposit work into fewer TXs.
2646
+ //
2647
+ // Given W old bins to withdraw and D new bins to deposit:
2648
+ // Phase 1: Pure withdraw TXs — all withdraw chunks except the last
2649
+ // Phase 2: Pivot TX — last withdraw chunk + extend + initBinArrays
2650
+ // + first deposit (if small enough to fit without CU issues)
2651
+ // Phase 3: Pure deposit TXs — remaining deposit bins by CHUNK_SIZE
2652
+ //
2653
+ // When the total extension is large or the deposit range spans many
2654
+ // bin arrays, the transition IXs (extend + initBinArrays) are placed
2655
+ // in a separate TX to avoid exceeding compute unit limits.
2656
+ // =====================================================================
2657
+ const txInstructions = [];
2658
+ // Helper: build on-chain deposit param from a ChunkedDepositParameters
2659
+ const buildDepositParam = (chunk) => {
2660
+ const p = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunk.params.x0, chunk.params.y0, chunk.params.deltaX, chunk.params.deltaY);
2661
+ return {
2662
+ minDeltaId: chunk.minDeltaId.toNumber(),
2663
+ maxDeltaId: chunk.maxDeltaId.toNumber(),
2664
+ x0: p.x0, y0: p.y0, deltaX: p.deltaX, deltaY: p.deltaY,
2665
+ bitFlag: p.bitFlag, favorXInActiveId,
2666
+ };
2667
+ };
2668
+ // Helper: build withdraw IX
2669
+ const buildWithdrawIx = (lower, upper) => __awaiter(this, void 0, void 0, function* () {
2670
+ const binArrayOverrides = this.ix.pda.meteora.deriveBinArrays(params.lbPair, lower, upper);
2671
+ return this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2672
+ connection,
2673
+ userWallet: params.userWallet,
2674
+ position: params.position,
2675
+ lbPair: params.lbPair,
2676
+ tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2677
+ activeId,
2678
+ pdaTokenType: types_1.TokenType.ATA,
2679
+ maxActiveBinSlippage: 300,
2680
+ shouldClaimFee: true,
2681
+ shouldClaimReward: rewardInfos.length > 0,
2682
+ minWithdrawXAmount: new bn_js_1.default(0),
2683
+ maxDepositXAmount: new bn_js_1.default(0),
2684
+ minWithdrawYAmount: new bn_js_1.default(0),
2685
+ maxDepositYAmount: new bn_js_1.default(0),
2686
+ removeLiquidityParams: [{ minBinId: lower, maxBinId: upper, bps: 10000 }],
2687
+ addLiquidityParams: [],
2688
+ binArrayOverrides,
2689
+ shrinkMode: types_3.ShrinkMode.Default,
2690
+ rewardInfos,
2691
+ remainingAccountsInfo,
2692
+ });
2693
+ });
2694
+ // Helper: build deposit IX from a deposit chunk
2695
+ const buildDepositIx = (chunk, removeLiquidityParams) => __awaiter(this, void 0, void 0, function* () {
2696
+ let trueMin = chunk.lowerBinId;
2697
+ let trueMax = chunk.upperBinId;
2698
+ if (removeLiquidityParams) {
2699
+ trueMin = Math.min(chunk.lowerBinId, removeLiquidityParams.minBinId);
2700
+ trueMax = Math.max(chunk.upperBinId, removeLiquidityParams.maxBinId);
2701
+ }
2702
+ const binArrayOverrides = this.ix.pda.meteora.deriveBinArrays(params.lbPair, trueMin, trueMax);
2703
+ return yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2704
+ connection,
2705
+ userWallet: params.userWallet,
2706
+ position: params.position,
2707
+ lbPair: params.lbPair,
2708
+ tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2709
+ activeId,
2710
+ pdaTokenType: types_1.TokenType.ATA,
2711
+ maxActiveBinSlippage: 300,
2712
+ shouldClaimFee: removeLiquidityParams ? true : false,
2713
+ shouldClaimReward: !!removeLiquidityParams && rewardInfos.length > 0,
2714
+ minWithdrawXAmount: new bn_js_1.default(0),
2715
+ maxDepositXAmount: chunk.maxAmountX,
2716
+ minWithdrawYAmount: new bn_js_1.default(0),
2717
+ maxDepositYAmount: chunk.maxAmountY,
2718
+ removeLiquidityParams: removeLiquidityParams ? [{ minBinId: removeLiquidityParams.minBinId, maxBinId: removeLiquidityParams.maxBinId, bps: 10000 }] : [],
2719
+ addLiquidityParams: [buildDepositParam(chunk)],
2720
+ binArrayOverrides,
2721
+ shrinkMode: removeLiquidityParams ? types_3.ShrinkMode.Default : types_3.ShrinkMode.NoShrinkBoth,
2722
+ rewardInfos: removeLiquidityParams ? rewardInfos : undefined,
2723
+ remainingAccountsInfo,
2724
+ });
2725
+ });
2726
+ // Build transition IXs: increasePositionLength + initBinArrays.
2727
+ // Bin arrays must be pre-initialized before rebalanceLiquidity deposits.
2728
+ const increasePositionLengthIxs = [];
2729
+ // Generate increasePositionLength IXs to extend position (assumption at the moment, I expect calculation to be wrong)
2730
+ let currentLower = newLowerBinId + WITHDRAW_CHUNK_SIZE;
2731
+ while (currentLower < newUpperBinId) {
2732
+ const currentWidth = newUpperBinId - currentLower + 1;
2733
+ const binsToAdd = Math.min(91, currentWidth);
2734
+ console.log('Increasing position length by', binsToAdd, 'bins at lower', currentLower);
2735
+ increasePositionLengthIxs.push(yield this.ix.meteoraDlmm.increasePositionLengthAutomation({
2736
+ connection,
2737
+ userWallet: params.userWallet,
2738
+ lbPair: params.lbPair,
2739
+ position: params.position,
2740
+ lengthToAdd: binsToAdd,
2741
+ side: types_1.MeteoraPositionSide.Upper,
2742
+ }));
2743
+ currentLower = currentLower + binsToAdd;
2744
+ }
2745
+ // Build all deposit chunks upfront
2746
+ const depositChunks = (0, liquidityStrategy_1.chunkDepositParametersWithInitialSize)(strategyParams, minDeltaId, maxDeltaId, new bn_js_1.default(activeId), binStep, DEPOSIT_CHUNK_INITIAL_SIZE, DEPOSIT_CHUNK_SIZE, favorXInActiveId);
2747
+ // Build old-position withdraw chunks, reserving PIVOT_RESERVE bins for pivot TX
2748
+ const oldWidth = oldUpperBinId - oldLowerBinId + 1;
2749
+ const oldChunks = [];
2750
+ let current = oldLowerBinId;
2751
+ // Build Phase 1 withdraw chunks (before pivot)
2752
+ while (current < oldUpperBinId) {
2753
+ const upper = Math.min(WITHDRAW_CHUNK_SIZE - 1, oldUpperBinId - current) + current;
2754
+ console.log(`Generating withdraw chunk: [${current}, ${upper}, ${upper - current + 1} bins]`);
2755
+ oldChunks.push({ lower: current, upper });
2756
+ current = upper + 1;
2757
+ }
2758
+ const remainder = oldWidth % WITHDRAW_CHUNK_SIZE;
2759
+ if (remainder === 0 || remainder > PIVOT_RESERVE) {
2760
+ // Pop last chunk to reserve for pivot
2761
+ const popped = oldChunks.pop();
2762
+ // Then insert bigger and final chunk for pivot
2763
+ const upper = popped.upper - PIVOT_RESERVE;
2764
+ oldChunks.push({ lower: popped.lower, upper });
2765
+ oldChunks.push({ lower: upper + 1, upper: popped.upper });
2766
+ }
2767
+ // =====================================================================
2768
+ // Phase 1: Pure withdraw TXs — all chunks in oldChunks (before pivot)
2769
+ // =====================================================================
2770
+ for (const chunk of oldChunks) {
2771
+ console.log(`Withdrawing from chunk: [${chunk.lower}, ${chunk.upper}]`);
2772
+ txInstructions.push([yield buildWithdrawIx(chunk.lower, chunk.upper)]);
2773
+ }
2774
+ // Pop the last one
2775
+ txInstructions.pop();
2776
+ // Get the last withdraw chunk for pivot
2777
+ const lastWithdrawChunk = oldChunks[oldChunks.length - 1];
2778
+ // =====================================================================
2779
+ // Phase 2 (Pivot TX): Withdraw pivot reserve + first deposit
2780
+ // This ensures bins "jump" to new position, preventing ReallocExceedMaxLengthPerInstruction
2781
+ // =====================================================================
2782
+ txInstructions.push([
2783
+ yield buildDepositIx(depositChunks[0], { minBinId: lastWithdrawChunk.lower, maxBinId: lastWithdrawChunk.upper }),
2784
+ ...increasePositionLengthIxs,
2785
+ ]);
2786
+ // =====================================================================
2787
+ // Phase 3: Remaining deposit TXs
2788
+ // - Second deposit (i=1): includes increasePositionLengthIxs if needed
2789
+ // - Subsequent deposits (i=2+): pure deposit
2790
+ // =====================================================================
2791
+ for (let i = 1; i < depositChunks.length; i++) {
2792
+ const chunk = depositChunks[i];
2793
+ txInstructions.push([yield buildDepositIx(chunk)]);
2794
+ }
2795
+ // Wrap each instruction array with createTransactionMeta
2796
+ const transactions = [];
2797
+ for (let i = 0; i < txInstructions.length; i++) {
2798
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
2799
+ payer: params.userWallet,
2800
+ description: `Automation IX: Reshape position (tx ${i + 1}/${txInstructions.length})`,
2801
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2802
+ mainInstructions: txInstructions[i],
2803
+ }));
2804
+ }
2805
+ return transactions;
2806
+ }
2807
+ catch (error) {
2808
+ throw error;
2809
+ }
2810
+ });
2811
+ }
2812
+ /**
2813
+ * Build raw instruction arrays for depositing liquidity to a large Meteora DLMM position
2814
+ * using rebalanceLiquidityAutomation (automation variant).
2815
+ * Skips depositMultipleTokenV2 since tokens are already in ATA from the withdraw phase.
2816
+ */
2817
+ _meteoraDepositToLargePositionAutomation(params) {
2818
+ return __awaiter(this, void 0, void 0, function* () {
2819
+ const MAX_BINS_PER_TX = 149;
2820
+ const { connection, userWallet, lbPair, position, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, lowerBinId, upperBinId, strategyType, activeId, totalXAmount, totalYAmount, } = params;
2821
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
2822
+ const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
2823
+ // Calculate delta IDs relative to active bin for entire position
2824
+ const minDeltaId = new bn_js_1.default(lowerBinId - activeId);
2825
+ const maxDeltaId = new bn_js_1.default(upperBinId - activeId);
2826
+ // Auto-determine favorXInActiveId from deposit amounts (matches Meteora SDK behavior)
2827
+ const favorXInActiveId = totalYAmount.isZero() && !totalXAmount.isZero();
2828
+ // Build strategy parameters ONCE for entire position using actual withdrawn amounts
2829
+ const strategyParams = (0, liquidityStrategy_1.buildStrategyParameters)(strategyType, totalXAmount, totalYAmount, minDeltaId, maxDeltaId, binStep, new bn_js_1.default(activeId), favorXInActiveId);
2830
+ // Chunk the deposit using the same strategy parameters
2831
+ const chunks = (0, liquidityStrategy_1.chunkDepositParameters)(strategyParams, minDeltaId, maxDeltaId, new bn_js_1.default(activeId), binStep, MAX_BINS_PER_TX, favorXInActiveId);
2832
+ const txInstructions = [];
2833
+ for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
2834
+ const chunk = chunks[chunkIndex];
2835
+ // Convert strategy parameters to on-chain format with bitFlag for negative values
2836
+ const onChainParams = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunk.params.x0, chunk.params.y0, chunk.params.deltaX, chunk.params.deltaY);
2837
+ const instructions = [];
2838
+ // Add initialize bin arrays instruction
2839
+ const initBinArraysIx = yield this.ix.meteoraDlmm.meteoraDlmmInitializeBinArray({
2840
+ connection,
2841
+ userWallet,
2842
+ lbPair,
2843
+ lowerBinId: chunk.lowerBinId,
2844
+ upperBinId: chunk.upperBinId,
2845
+ });
2846
+ instructions.push(initBinArraysIx);
2847
+ // Add liquidity via rebalanceLiquidityAutomation
2848
+ const depositIx = yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2849
+ connection,
2850
+ userWallet,
2851
+ position,
2852
+ lbPair,
2853
+ tokenXMint,
2854
+ tokenYMint,
2855
+ tokenXProgram,
2856
+ tokenYProgram,
2857
+ activeId,
2858
+ pdaTokenType: types_1.TokenType.ATA,
2859
+ maxActiveBinSlippage: 300,
2860
+ shouldClaimFee: false,
2861
+ shouldClaimReward: false,
2862
+ minWithdrawXAmount: new bn_js_1.default(0),
2863
+ maxDepositXAmount: chunk.maxAmountX,
2864
+ minWithdrawYAmount: new bn_js_1.default(0),
2865
+ maxDepositYAmount: chunk.maxAmountY,
2866
+ removeLiquidityParams: [],
2867
+ addLiquidityParams: [{
2868
+ minDeltaId: chunk.minDeltaId.toNumber(),
2869
+ maxDeltaId: chunk.maxDeltaId.toNumber(),
2870
+ x0: onChainParams.x0,
2871
+ y0: onChainParams.y0,
2872
+ deltaX: onChainParams.deltaX,
2873
+ deltaY: onChainParams.deltaY,
2874
+ bitFlag: onChainParams.bitFlag,
2875
+ favorXInActiveId,
2876
+ }],
2877
+ });
2878
+ instructions.push(depositIx);
2879
+ txInstructions.push(instructions);
2880
+ }
2881
+ return txInstructions;
2882
+ });
2883
+ }
2884
+ /**
2885
+ * Build merged rebalance chunks that combine withdraw + init/extend + deposit
2886
+ * into fewer transactions. Each TX handles ~75 bins of withdraw and deposit,
2887
+ * significantly reducing the total number of transactions needed.
2888
+ *
2889
+ * Per-chunk instructions (in order):
2890
+ * [First TX only] initializePositionRelativeAutomation (≤70 bins)
2891
+ * [If position not yet covers this chunk] increasePositionLengthAutomation (≤91 bins each)
2892
+ * removeLiquidityByRange2Automation (≤75 bins from old position)
2893
+ * claimFee2Automation (≤75 bins from old position)
2894
+ * claimReward2Automation × N (≤75 bins from old position, per active reward)
2895
+ * [Last old chunk only] closePosition2Automation
2896
+ * meteoraDlmmInitializeBinArray (≤75 bins for new position)
2897
+ * rebalanceLiquidityAutomation (≤75 bins deposit to new position)
2898
+ */
2899
+ _buildMergedRebalanceChunks(params) {
2900
+ return __awaiter(this, void 0, void 0, function* () {
2901
+ const CHUNK_SIZE = 75;
2902
+ const MAX_INIT_WIDTH = 70;
2903
+ const MAX_EXTEND_LENGTH = 91;
2904
+ const { connection, userWallet, lbPair, oldPosition, oldLowerBinId, oldUpperBinId, newPosition, relativeLowerBinId, width, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, remainingAccountsInfo, rewardInfos, pdaTokenTypeForClaimables, binStep, strategyType, activeId, totalXAmount, totalYAmount, } = params;
2905
+ // Pre-resolve reward info (avoid repeated RPC calls)
2906
+ const rewardIxBuilders = [];
2907
+ for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
2908
+ const rewardInfo = rewardInfos[rewardIndex];
2909
+ if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default)) {
2910
+ continue;
2911
+ }
2912
+ const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [rewardInfo.mint]);
2913
+ const rewardTokenProgram = rewardTokenProgramMap[rewardInfo.mint.toString()];
2914
+ const rewardRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, rewardInfo.mint, rewardTokenProgram);
2915
+ rewardIxBuilders.push({
2916
+ rewardIndex,
2917
+ rewardMint: rewardInfo.mint,
2918
+ rewardVault: rewardInfo.vault,
2919
+ rewardTokenProgram,
2920
+ rewardRemainingAccountsInfo,
2921
+ });
2922
+ }
2923
+ // Build old-position withdraw chunks (75 bins each)
2924
+ const oldChunks = [];
2925
+ let current = oldLowerBinId;
2926
+ while (current <= oldUpperBinId) {
2927
+ const upper = Math.min(current + CHUNK_SIZE - 1, oldUpperBinId);
2928
+ oldChunks.push({ lower: current, upper });
2929
+ current = upper + 1;
2930
+ }
2931
+ // Build new-position deposit chunks
2932
+ const newLowerBinId = activeId + relativeLowerBinId;
2933
+ const newUpperBinId = newLowerBinId + width - 1;
2934
+ const minDeltaId = new bn_js_1.default(newLowerBinId - activeId);
2935
+ const maxDeltaId = new bn_js_1.default(newUpperBinId - activeId);
2936
+ const favorXInActiveId = totalYAmount.isZero() && !totalXAmount.isZero();
2937
+ const strategyParams = (0, liquidityStrategy_1.buildStrategyParameters)(strategyType, totalXAmount, totalYAmount, minDeltaId, maxDeltaId, binStep, new bn_js_1.default(activeId), favorXInActiveId);
2938
+ const depositChunks = (0, liquidityStrategy_1.chunkDepositParameters)(strategyParams, minDeltaId, maxDeltaId, new bn_js_1.default(activeId), binStep, CHUNK_SIZE, favorXInActiveId);
2939
+ const totalChunks = Math.max(oldChunks.length, depositChunks.length);
2940
+ const txInstructions = [];
2941
+ let positionBinsAllocated = 0;
2942
+ for (let i = 0; i < totalChunks; i++) {
2943
+ const instructions = [];
2944
+ // === Init/extend new position for this chunk's deposit range ===
2945
+ if (i === 0) {
2946
+ const initWidth = Math.min(MAX_INIT_WIDTH, width);
2947
+ const initPositionIx = yield this.ix.meteoraDlmm.initializePositionRelativeAutomation(connection, {
2948
+ userWallet,
2949
+ lbPair,
2950
+ position: newPosition,
2951
+ relativeLowerBinId,
2952
+ width: initWidth,
2953
+ });
2954
+ instructions.push(initPositionIx);
2955
+ positionBinsAllocated = initWidth;
2956
+ }
2957
+ // Extend position to cover this chunk's deposit range
2958
+ if (i < depositChunks.length) {
2959
+ const binsNeeded = Math.min((i + 1) * CHUNK_SIZE, width);
2960
+ while (positionBinsAllocated < binsNeeded) {
2961
+ const toAdd = Math.min(MAX_EXTEND_LENGTH, binsNeeded - positionBinsAllocated);
2962
+ const extendIx = yield this.ix.meteoraDlmm.increasePositionLengthAutomation({
2963
+ connection,
2964
+ userWallet,
2965
+ lbPair,
2966
+ position: newPosition,
2967
+ lengthToAdd: toAdd,
2968
+ side: types_1.MeteoraPositionSide.Upper,
2969
+ });
2970
+ instructions.push(extendIx);
2971
+ positionBinsAllocated += toAdd;
2972
+ }
2973
+ }
2974
+ // === Withdraw from old position ===
2975
+ if (i < oldChunks.length) {
2976
+ const chunk = oldChunks[i];
2977
+ const isLastOldChunk = (i === oldChunks.length - 1);
2978
+ const removeLiquidityIx = yield this.ix.meteoraDlmm.removeLiquidityByRange2Automation({
2979
+ connection,
2980
+ userWallet,
2981
+ lbPair,
2982
+ position: oldPosition,
2983
+ tokenXMint,
2984
+ tokenYMint,
2985
+ tokenXProgram,
2986
+ tokenYProgram,
2987
+ fromBinId: chunk.lower,
2988
+ toBinId: chunk.upper,
2989
+ bpsToRemove: 10000, // 100%
2990
+ pdaTokenType: types_1.TokenType.ATA,
2991
+ remainingAccountsInfo,
2992
+ });
2993
+ instructions.push(removeLiquidityIx);
2994
+ const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2Automation(connection, {
2995
+ userWallet,
2996
+ lbPair,
2997
+ position: oldPosition,
2998
+ tokenMintX: tokenXMint,
2999
+ tokenMintY: tokenYMint,
3000
+ tokenProgramX: tokenXProgram,
3001
+ tokenProgramY: tokenYProgram,
3002
+ lowerBinId: chunk.lower,
3003
+ upperBinId: chunk.upper,
3004
+ pdaTokenType: pdaTokenTypeForClaimables,
3005
+ remainingAccountsInfo,
3006
+ });
3007
+ instructions.push(claimFeeIx);
3008
+ for (const reward of rewardIxBuilders) {
3009
+ const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2Automation(connection, {
3010
+ userWallet,
3011
+ lbPair,
3012
+ position: oldPosition,
3013
+ rewardIndex: reward.rewardIndex,
3014
+ rewardMint: reward.rewardMint,
3015
+ rewardVault: reward.rewardVault,
3016
+ tokenProgram: reward.rewardTokenProgram,
3017
+ lowerBinId: chunk.lower,
3018
+ upperBinId: chunk.upper,
3019
+ pdaTokenType: types_1.TokenType.STA,
3020
+ remainingAccountsInfo: reward.rewardRemainingAccountsInfo,
3021
+ });
3022
+ instructions.push(claimRewardIx);
3023
+ }
3024
+ if (isLastOldChunk) {
3025
+ const closePositionIx = yield this.ix.meteoraDlmm.closePosition2Automation({
3026
+ connection,
3027
+ userWallet,
3028
+ position: oldPosition,
3029
+ lbPair,
3030
+ });
3031
+ instructions.push(closePositionIx);
3032
+ }
3033
+ }
3034
+ // === Deposit to new position ===
3035
+ if (i < depositChunks.length) {
3036
+ const chunk = depositChunks[i];
3037
+ const onChainParams = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunk.params.x0, chunk.params.y0, chunk.params.deltaX, chunk.params.deltaY);
3038
+ const initBinArraysIx = yield this.ix.meteoraDlmm.meteoraDlmmInitializeBinArray({
3039
+ connection,
3040
+ userWallet,
3041
+ lbPair,
3042
+ lowerBinId: chunk.lowerBinId,
3043
+ upperBinId: chunk.upperBinId,
3044
+ });
3045
+ instructions.push(initBinArraysIx);
3046
+ const depositIx = yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
3047
+ connection,
3048
+ userWallet,
3049
+ position: newPosition,
3050
+ lbPair,
3051
+ tokenXMint,
3052
+ tokenYMint,
3053
+ tokenXProgram,
3054
+ tokenYProgram,
3055
+ activeId,
3056
+ pdaTokenType: types_1.TokenType.ATA,
3057
+ maxActiveBinSlippage: 300,
3058
+ shouldClaimFee: false,
3059
+ shouldClaimReward: false,
3060
+ minWithdrawXAmount: new bn_js_1.default(0),
3061
+ maxDepositXAmount: chunk.maxAmountX,
3062
+ minWithdrawYAmount: new bn_js_1.default(0),
3063
+ maxDepositYAmount: chunk.maxAmountY,
3064
+ removeLiquidityParams: [],
3065
+ addLiquidityParams: [{
3066
+ minDeltaId: chunk.minDeltaId.toNumber(),
3067
+ maxDeltaId: chunk.maxDeltaId.toNumber(),
3068
+ x0: onChainParams.x0,
3069
+ y0: onChainParams.y0,
3070
+ deltaX: onChainParams.deltaX,
3071
+ deltaY: onChainParams.deltaY,
3072
+ bitFlag: onChainParams.bitFlag,
3073
+ favorXInActiveId,
3074
+ }],
3075
+ });
3076
+ instructions.push(depositIx);
3077
+ }
3078
+ txInstructions.push(instructions);
3079
+ }
3080
+ return txInstructions;
3081
+ });
3082
+ }
3083
+ openAutomationIx(_a) {
3084
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
3085
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.pool, this.ix);
3086
+ const userPda = (0, functions_1.generateUserPda)(params.userWallet);
3087
+ // Open new position
3088
+ const initPositionAndAddLiquidityBuilder = yield dlmmPool.initializePositionAndAddLiquidityByStrategy(connection, params.userWallet, addresses_1.HS_AUTHORITY, {
3089
+ positionPubKey: params.position,
3090
+ user: userPda,
3091
+ slippage: params.slippage,
3092
+ totalXAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
3093
+ totalYAmount: new bn_js_1.default(100000), // This is overriden on-chain, so value here do not matter
3094
+ strategy: {
3095
+ maxBinId: params.binRange.upperRange,
3096
+ minBinId: params.binRange.lowerRange,
3097
+ strategyType: types_3.StrategyTypeMap[params.distribution],
3098
+ },
3099
+ skipInputTokenCheck: true, // Rebalance should be independent of user wallet TA
3100
+ opt: {
3101
+ pdaTokenType: params.opt.pdaTokenType,
3102
+ withAmount: {
3103
+ userTokenXAmount: params.opt.withAmount.userTokenXAmount,
3104
+ userTokenYAmount: params.opt.withAmount.userTokenYAmount,
3105
+ },
3106
+ fuelAccount: params.opt.fuelAccount,
3107
+ },
3108
+ }, hsToMeteora_1.meteoraToHawksightAutomationIxs);
3109
+ const mainInstructions = [...initPositionAndAddLiquidityBuilder.mainIxs];
3110
+ return (0, functions_1.createTransactionMeta)({
3111
+ payer: params.userWallet,
3112
+ description: 'Automation IX: Meteora Open instruction (Open position)',
3113
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
3114
+ mainInstructions,
3115
+ });
3116
+ });
3117
+ }
3118
+ relativeOpenAutomationIx(_a) {
3119
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
3120
+ const { userWallet, pool, position, relativeBinRange, checkRange, distribution, targetActiveBin, fuelAccount, pdaTokenType, userTokenXAmount, userTokenYAmount } = params;
3121
+ const openParams = {
3122
+ userWallet,
3123
+ lbPair: pool,
3124
+ position,
3125
+ relativeLowerBinId: relativeBinRange.lowerRange,
3126
+ relativeUpperBinId: relativeBinRange.upperRange,
3127
+ strategyType: types_3.StrategyTypeMap[distribution],
3128
+ checkRange: {
3129
+ minBinId: checkRange.lowerRange,
3130
+ maxBinId: checkRange.upperRange,
3131
+ },
3132
+ targetActiveBin: targetActiveBin !== null && targetActiveBin !== void 0 ? targetActiveBin : undefined,
3133
+ useFuelAccount: fuelAccount !== null && fuelAccount !== void 0 ? fuelAccount : false,
3134
+ pdaTokenType,
3135
+ userTokenXAmount,
3136
+ userTokenYAmount,
3137
+ };
3138
+ const openIx = yield this.ix.meteoraDlmm.relativeOpenAutomation(connection, openParams);
3139
+ return (0, functions_1.createTransactionMeta)({
3140
+ payer: params.userWallet,
3141
+ description: 'Automation IX: Meteora Open with relative bins',
1932
3142
  addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
1933
3143
  mainInstructions: [openIx],
1934
3144
  });
@@ -2330,25 +3540,32 @@ class Transactions {
2330
3540
  throw new Error(`Unexpected error: Cannot find "RemoveLiquidityByRange" or "RemoveLiquidityByRange2" instruction from instructions`);
2331
3541
  }
2332
3542
  /**
2333
- * Creates a large position with more than 69 bins
2334
- * - Known limitation: Can create a position with 1344 bins in a single transaction
3543
+ * Creates a large position with more than 69 bins.
3544
+ * Splits into multiple transactions if needed (max 1344 bins per tx, max 1400 bins total).
2335
3545
  *
2336
3546
  * @param connection - Solana connection
2337
3547
  * @param params - Parameters containing userWallet, lbPair, position, lowerBinId, upperBinId
2338
- * @returns Array of TransactionInstructions for initializing and extending the position
3548
+ * @returns Array of TransactionMetadataResponse (one per transaction)
2339
3549
  */
2340
- meteoraInitializeLargePosition(_a) {
3550
+ /**
3551
+ * Build raw instruction arrays for initializing a large Meteora DLMM position.
3552
+ * Returns a 2D array where each inner array is one transaction's worth of instructions.
3553
+ */
3554
+ _meteoraInitializeLargePosition(_a) {
2341
3555
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2342
3556
  const MAX_INIT_WIDTH = 70; // Maximum bins for initialize position
2343
3557
  const MAX_EXTEND_LENGTH = 91; // Maximum bins per increasePositionLength call
3558
+ const MAX_BINS_PER_TX = 1344; // Maximum bins that fit in a single transaction
2344
3559
  const { userWallet, lbPair, position, lowerBinId, upperBinId } = params;
2345
3560
  // Calculate total bins needed
2346
3561
  const totalBins = upperBinId - lowerBinId + 1;
2347
- // Validate bin count (max 1344 supported by Meteora)
2348
- if (totalBins > 1344) {
2349
- throw new Error(`Position size ${totalBins} bins exceeds maximum of 1344 bins`);
3562
+ // Validate bin count (max 1400 supported by Meteora)
3563
+ if (totalBins > 1400) {
3564
+ throw new Error(`Position size ${totalBins} bins exceeds maximum of 1400 bins`);
2350
3565
  }
2351
- const instructions = [];
3566
+ const txInstructions = [];
3567
+ let instructions = [];
3568
+ let binsInCurrentTx = 0;
2352
3569
  // Step 1: Create initialize position (from lowerBinId with max 70 bins)
2353
3570
  const initWidth = Math.min(totalBins, MAX_INIT_WIDTH);
2354
3571
  const initializePositionIx = yield this.ix.meteoraDlmm.initializePosition({
@@ -2360,46 +3577,63 @@ class Transactions {
2360
3577
  width: initWidth,
2361
3578
  });
2362
3579
  instructions.push(initializePositionIx);
3580
+ binsInCurrentTx += initWidth;
2363
3581
  // Step 2: Extend to the right in chunks of 91 bins if needed
2364
- // After init, we have bins from lowerBinId to lowerBinId + initWidth - 1
2365
- // We need to extend up to upperBinId
2366
3582
  let currentUpperBinId = lowerBinId + initWidth - 1;
2367
3583
  while (currentUpperBinId < upperBinId) {
2368
- // Calculate how many bins to add (max 91)
2369
3584
  const binsRemaining = upperBinId - currentUpperBinId;
2370
3585
  const binsToAdd = Math.min(binsRemaining, MAX_EXTEND_LENGTH);
3586
+ // Check if adding this extension would exceed max bins per tx
3587
+ if (binsInCurrentTx + binsToAdd > MAX_BINS_PER_TX) {
3588
+ txInstructions.push(instructions);
3589
+ instructions = [];
3590
+ binsInCurrentTx = 0;
3591
+ }
2371
3592
  const extendIx = yield this.ix.meteoraDlmm.increasePositionLength({
2372
3593
  connection,
2373
3594
  userWallet,
2374
3595
  lbPair,
2375
3596
  position,
2376
3597
  lengthToAdd: binsToAdd,
2377
- side: types_1.MeteoraPositionSide.Upper, // Extend to the right (upper side)
3598
+ side: types_1.MeteoraPositionSide.Upper,
2378
3599
  });
2379
3600
  instructions.push(extendIx);
3601
+ binsInCurrentTx += binsToAdd;
2380
3602
  currentUpperBinId += binsToAdd;
2381
3603
  }
2382
- return (0, functions_1.createTransactionMeta)({
2383
- payer: params.userWallet,
2384
- description: 'Initialize large Meteora DLMM Position',
2385
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2386
- mainInstructions: instructions,
2387
- });
3604
+ // Finalize remaining instructions
3605
+ if (instructions.length > 0) {
3606
+ txInstructions.push(instructions);
3607
+ }
3608
+ return txInstructions;
3609
+ });
3610
+ }
3611
+ meteoraInitializeLargePosition(_a) {
3612
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
3613
+ const txInstructions = yield this._meteoraInitializeLargePosition({ connection, params });
3614
+ const transactions = [];
3615
+ for (const instructions of txInstructions) {
3616
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
3617
+ payer: params.userWallet,
3618
+ description: 'Initialize large Meteora DLMM Position',
3619
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
3620
+ mainInstructions: instructions,
3621
+ }));
3622
+ }
3623
+ return transactions;
2388
3624
  });
2389
3625
  }
2390
3626
  /**
2391
- * Deposit liquidity to a large Meteora DLMM position using rebalanceLiquidity.
2392
- * Splits the deposit into multiple transactions (one per chunk of bins)
2393
- * to stay within Solana's account limit per transaction.
2394
- *
2395
- * @param connection - Solana connection
2396
- * @param params - MeteoraDepositToLargePosition parameters
2397
- * @returns Array of TransactionMetadataResponse, one per chunk
3627
+ * Build raw instruction arrays for depositing liquidity to a large Meteora DLMM position.
3628
+ * Returns a 2D array where each inner array is one transaction's worth of instructions.
2398
3629
  */
2399
- meteoraDepositToLargePosition(_a) {
3630
+ _meteoraDepositToLargePosition(_a) {
2400
3631
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2401
3632
  const MAX_BINS_PER_TX = 149;
2402
- const { userWallet, lbPair, position, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, lowerBinId, upperBinId, totalXAmount, totalYAmount, strategyType = liquidityStrategy_1.StrategyType.SPOT, favorXInActiveId = false, pdaTokenType, } = params;
3633
+ const { userWallet, lbPair, position, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, lowerBinId, upperBinId, totalXAmount, totalYAmount, strategyType = liquidityStrategy_1.StrategyType.SPOT, pdaTokenType, } = params;
3634
+ // Auto-determine favorXInActiveId from deposit amounts (matches Meteora SDK behavior):
3635
+ // Single-sided X deposit (Y is zero) → favor X in active bin
3636
+ const favorXInActiveId = totalYAmount.isZero() && !totalXAmount.isZero();
2403
3637
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
2404
3638
  const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2405
3639
  const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
@@ -2413,7 +3647,7 @@ class Transactions {
2413
3647
  // Chunk the deposit using the same strategy parameters
2414
3648
  const chunks = (0, liquidityStrategy_1.chunkDepositParameters)(strategyParams, minDeltaId, maxDeltaId, new bn_js_1.default(activeId), binStep, MAX_BINS_PER_TX, favorXInActiveId);
2415
3649
  console.log(`Total chunks: ${chunks.length}`);
2416
- const transactions = [];
3650
+ const txInstructions = [];
2417
3651
  // === TRANSACTION 1: Create LTA accounts and deposit tokens ===
2418
3652
  const depositInstructions = [];
2419
3653
  // Build deposit array for tokens with non-zero amounts
@@ -2456,7 +3690,6 @@ class Transactions {
2456
3690
  });
2457
3691
  instructions.push(initBinArraysIx);
2458
3692
  // Add liquidity via rebalanceLiquidity
2459
- // Note: Always use TokenType.LTA since we deposit to LTA in the first transaction
2460
3693
  const depositIx = yield this.ix.meteoraDlmm.rebalanceLiquidity({
2461
3694
  connection,
2462
3695
  userWallet,
@@ -2489,14 +3722,213 @@ class Transactions {
2489
3722
  }],
2490
3723
  });
2491
3724
  instructions.push(depositIx);
2492
- // Create transaction for this chunk
2493
- const txMeta = yield (0, functions_1.createTransactionMeta)({
2494
- payer: userWallet,
2495
- description: `Deposit to large Meteora DLMM Position (chunk ${chunkIndex + 1}/${chunks.length})`,
3725
+ txInstructions.push(instructions);
3726
+ }
3727
+ return txInstructions;
3728
+ });
3729
+ }
3730
+ /**
3731
+ * Deposit liquidity to a large Meteora DLMM position using rebalanceLiquidity.
3732
+ * Splits the deposit into multiple transactions (one per chunk of bins)
3733
+ * to stay within Solana's account limit per transaction.
3734
+ *
3735
+ * @param connection - Solana connection
3736
+ * @param params - MeteoraDepositToLargePosition parameters
3737
+ * @returns Array of TransactionMetadataResponse, one per chunk
3738
+ */
3739
+ meteoraDepositToLargePosition(_a) {
3740
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
3741
+ var _b;
3742
+ let lbPair, upperBinId, lowerBinId;
3743
+ if (params.fastGeneration !== undefined) {
3744
+ lbPair = params.fastGeneration.pool;
3745
+ upperBinId = params.fastGeneration.upperBinId;
3746
+ lowerBinId = params.fastGeneration.lowerBinId;
3747
+ }
3748
+ else {
3749
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
3750
+ const position = yield program.account.positionV2.fetch(params.position);
3751
+ lbPair = position.lbPair;
3752
+ upperBinId = position.upperBinId;
3753
+ lowerBinId = position.lowerBinId;
3754
+ }
3755
+ const totalBins = upperBinId - lowerBinId + 1;
3756
+ // ≤149 bins: single-tx path via meteoraDepositLargerPosition
3757
+ if (totalBins <= 149) {
3758
+ const result = yield this.meteoraDepositLargerPosition({
3759
+ connection,
3760
+ params: {
3761
+ userWallet: params.userWallet,
3762
+ lbPair,
3763
+ position: params.position,
3764
+ lowerBinId,
3765
+ upperBinId,
3766
+ totalXAmount: params.totalXAmount,
3767
+ totalYAmount: params.totalYAmount,
3768
+ distribution: params.distribution,
3769
+ slippage: params.slippage,
3770
+ skipInputTokenCheck: params.skipInputTokenCheck,
3771
+ pdaTokenType: params.pdaTokenType,
3772
+ initializePosition: false,
3773
+ },
3774
+ fetch: undefined,
3775
+ });
3776
+ return [result];
3777
+ }
3778
+ // ≥150 bins: multi-tx chunked deposit path
3779
+ // Resolve token mints and programs from lbPair
3780
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
3781
+ const lbPairState = dlmmPool.dlmm.lbPair;
3782
+ const tokenXMint = lbPairState.tokenXMint;
3783
+ const tokenYMint = lbPairState.tokenYMint;
3784
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
3785
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
3786
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
3787
+ // Convert Distribution to liquidityStrategy.StrategyType
3788
+ const distributionToStrategyType = {
3789
+ 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
3790
+ 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
3791
+ 'BID-ASK': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-IMBALANCED': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-ONE-SIDE': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-BALANCED': liquidityStrategy_1.StrategyType.BID_ASK,
3792
+ };
3793
+ const strategyType = (_b = distributionToStrategyType[params.distribution]) !== null && _b !== void 0 ? _b : liquidityStrategy_1.StrategyType.SPOT;
3794
+ const txInstructions = yield this._meteoraDepositToLargePosition({ connection, params: {
3795
+ userWallet: params.userWallet,
3796
+ lbPair,
3797
+ position: params.position,
3798
+ tokenXMint,
3799
+ tokenYMint,
3800
+ tokenXProgram,
3801
+ tokenYProgram,
3802
+ lowerBinId,
3803
+ upperBinId,
3804
+ totalXAmount: params.totalXAmount,
3805
+ totalYAmount: params.totalYAmount,
3806
+ strategyType,
3807
+ pdaTokenType: params.pdaTokenType,
3808
+ } });
3809
+ const transactions = [];
3810
+ for (let i = 0; i < txInstructions.length; i++) {
3811
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
3812
+ payer: params.userWallet,
3813
+ description: `Deposit to large Meteora DLMM Position (chunk ${i + 1}/${txInstructions.length})`,
2496
3814
  addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2497
- mainInstructions: instructions,
3815
+ mainInstructions: txInstructions[i],
3816
+ }));
3817
+ }
3818
+ return transactions;
3819
+ });
3820
+ }
3821
+ /**
3822
+ * Create a position and deposit liquidity for any bin count.
3823
+ *
3824
+ * - For ≤149 bins: delegates to meteoraDepositLargerPosition (single tx with position init)
3825
+ * - For ≥150 bins: uses _meteoraInitializeLargePosition + _meteoraDepositToLargePosition (multi-tx)
3826
+ * When init produces 2 TXs (>1344 bins), the 2nd init TX is merged into the 1st deposit TX.
3827
+ */
3828
+ meteoraCreatePositionAndDepositToLargePosition(_a) {
3829
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
3830
+ var _b;
3831
+ const totalBins = params.binRange.upperRange - params.binRange.lowerRange + 1;
3832
+ // ≤149 bins: single-tx path via meteoraDepositLargerPosition
3833
+ if (totalBins <= 149) {
3834
+ const result = yield this.meteoraDepositLargerPosition({
3835
+ connection,
3836
+ params: {
3837
+ userWallet: params.userWallet,
3838
+ lbPair: params.pool,
3839
+ position: params.position,
3840
+ lowerBinId: params.binRange.lowerRange,
3841
+ upperBinId: params.binRange.upperRange,
3842
+ totalXAmount: params.totalXAmount,
3843
+ totalYAmount: params.totalYAmount,
3844
+ distribution: params.distribution,
3845
+ slippage: params.slippage,
3846
+ skipInputTokenCheck: params.skipInputTokenCheck,
3847
+ pdaTokenType: params.pdaTokenType,
3848
+ initializePosition: true,
3849
+ },
3850
+ fetch: undefined,
2498
3851
  });
2499
- transactions.push(txMeta);
3852
+ return [result];
3853
+ }
3854
+ // ≥150 bins: multi-tx path
3855
+ // Convert Distribution string to liquidityStrategy.StrategyType number for chunked deposit
3856
+ const distributionToStrategyType = {
3857
+ 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
3858
+ 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
3859
+ 'BID-ASK': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-IMBALANCED': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-ONE-SIDE': liquidityStrategy_1.StrategyType.BID_ASK, 'BID-ASK-BALANCED': liquidityStrategy_1.StrategyType.BID_ASK,
3860
+ };
3861
+ const strategyType = (_b = distributionToStrategyType[params.distribution]) !== null && _b !== void 0 ? _b : liquidityStrategy_1.StrategyType.SPOT;
3862
+ // Step 1: Initialize position
3863
+ const initTxs = yield this._meteoraInitializeLargePosition({
3864
+ connection,
3865
+ params: {
3866
+ userWallet: params.userWallet,
3867
+ lbPair: params.pool,
3868
+ position: params.position,
3869
+ lowerBinId: params.binRange.lowerRange,
3870
+ upperBinId: params.binRange.upperRange,
3871
+ },
3872
+ });
3873
+ // Step 2: Resolve token mints and programs from lbPair
3874
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.pool, this.ix);
3875
+ const lbPairState = dlmmPool.dlmm.lbPair;
3876
+ const tokenXMint = lbPairState.tokenXMint;
3877
+ const tokenYMint = lbPairState.tokenYMint;
3878
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
3879
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
3880
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
3881
+ // Step 3: Build deposit instructions
3882
+ const depositTxs = yield this._meteoraDepositToLargePosition({
3883
+ connection,
3884
+ params: {
3885
+ userWallet: params.userWallet,
3886
+ lbPair: params.pool,
3887
+ position: params.position,
3888
+ tokenXMint,
3889
+ tokenYMint,
3890
+ tokenXProgram,
3891
+ tokenYProgram,
3892
+ lowerBinId: params.binRange.lowerRange,
3893
+ upperBinId: params.binRange.upperRange,
3894
+ totalXAmount: params.totalXAmount,
3895
+ totalYAmount: params.totalYAmount,
3896
+ strategyType,
3897
+ pdaTokenType: params.pdaTokenType,
3898
+ },
3899
+ });
3900
+ // Step 4: Assemble — merge init's last TX into deposit's first TX if init has >1 TX
3901
+ const assembled = [];
3902
+ if (initTxs.length > 1) {
3903
+ // Add all init TXs except the last
3904
+ for (let i = 0; i < initTxs.length - 1; i++) {
3905
+ assembled.push(initTxs[i]);
3906
+ }
3907
+ // Merge last init TX into first deposit TX
3908
+ const lastInitTx = initTxs[initTxs.length - 1];
3909
+ const firstDepositTx = depositTxs[0];
3910
+ assembled.push([...lastInitTx, ...firstDepositTx]);
3911
+ // Add remaining deposit TXs
3912
+ for (let i = 1; i < depositTxs.length; i++) {
3913
+ assembled.push(depositTxs[i]);
3914
+ }
3915
+ }
3916
+ else {
3917
+ // Single init TX — no merge needed
3918
+ assembled.push(initTxs[0]);
3919
+ for (const tx of depositTxs) {
3920
+ assembled.push(tx);
3921
+ }
3922
+ }
3923
+ // Step 5: Wrap each instruction array with createTransactionMeta
3924
+ const transactions = [];
3925
+ for (let i = 0; i < assembled.length; i++) {
3926
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
3927
+ payer: params.userWallet,
3928
+ description: `Create position and deposit to large Meteora DLMM Position (tx ${i + 1}/${assembled.length})`,
3929
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
3930
+ mainInstructions: assembled[i],
3931
+ }));
2500
3932
  }
2501
3933
  return transactions;
2502
3934
  });