@hawksightco/hawk-sdk 1.3.218 → 1.3.220

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.
@@ -1484,13 +1484,17 @@ class Transactions {
1484
1484
  }
1485
1485
  // ≥150 bins: chunked multi-TX approach
1486
1486
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
1487
- // For compound, we use dummy equal amounts for deposit strategy calculation.
1488
- // The on-chain RebalanceLiquidity overrides totalXAmount/totalYAmount with ATA balance,
1489
- // so these values only affect the strategy ratio. Using equal amounts (like the single-TX
1490
- // compoundAutomationIx does with 100_000) ensures the strategy distributes evenly and
1491
- // doesn't try to transfer more of one token than is available from claimed fees.
1492
- const totalXAmount = new bn_js_1.default(100000);
1493
- const totalYAmount = new bn_js_1.default(100000);
1487
+ // Compute expected post-claim ATA amounts for accurate strategy parameters.
1488
+ // TX0 claims fees to ATA, minus 20% protocol fee sent to treasury on-chain.
1489
+ // TX1 deposit must use strategy params that match actual post-claim ATA balance.
1490
+ // Fee computation uses raw account parsing (avoids expensive getPositionsByUserAndLbPair).
1491
+ const claimableFees = yield this._computeClaimableFees(connection, params.position, lbPair, lowerBinId, upperBinId);
1492
+ const PROTOCOL_FEE_BPS = 2000; // 20% protocol fee deducted during claim_fee on-chain
1493
+ const totalXAmount = claimableFees.feeX.sub(claimableFees.feeX.mul(new bn_js_1.default(PROTOCOL_FEE_BPS)).div(new bn_js_1.default(10000)));
1494
+ const totalYAmount = claimableFees.feeY.sub(claimableFees.feeY.mul(new bn_js_1.default(PROTOCOL_FEE_BPS)).div(new bn_js_1.default(10000)));
1495
+ if (totalXAmount.isZero() && totalYAmount.isZero()) {
1496
+ throw new Error('No claimable fees to compound');
1497
+ }
1494
1498
  const lbPairState = dlmmPool.dlmm.lbPair;
1495
1499
  const tokenXMint = lbPairState.tokenXMint;
1496
1500
  const tokenYMint = lbPairState.tokenYMint;
@@ -1590,6 +1594,7 @@ class Transactions {
1590
1594
  activeId,
1591
1595
  totalXAmount,
1592
1596
  totalYAmount,
1597
+ skipInitBinArrays: true, // compound: position already exists, bin arrays are already initialized
1593
1598
  });
1594
1599
  // =========================================================================
1595
1600
  // Phase 3: Assemble transactions
@@ -1615,7 +1620,6 @@ class Transactions {
1615
1620
  });
1616
1621
  }
1617
1622
  /**
1618
- * @deprecated Use rebalanceLargerPositionAutomation instead
1619
1623
  *
1620
1624
  * @param connection The Solana web3 connection object for blockchain interactions.
1621
1625
  * @param params Parameters required for rebalance
@@ -1680,7 +1684,6 @@ class Transactions {
1680
1684
  });
1681
1685
  }
1682
1686
  /**
1683
- * @deprecated Use rebalanceLargerPositionAutomation instaed
1684
1687
  *
1685
1688
  * @param connection The Solana web3 connection object for blockchain interactions.
1686
1689
  * @param params Parameters required for rebalance
@@ -1983,35 +1986,7 @@ class Transactions {
1983
1986
  }
1984
1987
  });
1985
1988
  }
1986
- /**
1987
- * Rebalance a Meteora DLMM position with support for larger positions.
1988
- *
1989
- * This is a backwards-compatible implementation of the rebalance operation that handles
1990
- * positions of any size. The method automatically splits operations into 2-dimensional
1991
- * instruction arrays (where each dimension represents a transaction) when dealing with
1992
- * large bin arrays that would exceed single transaction limits.
1993
- *
1994
- * This rebalance method performs the following steps:
1995
- * 1. Removes liquidity from the current position (supports larger bin ranges, not limited to 70-bin chunks, max 149-bin)
1996
- * 2. Claims fees from the current position
1997
- * 3. Claims rewards from the current position (if any)
1998
- * 4. Closes the current position
1999
- * 5. Initializes a new position
2000
- * 6. Extends the new position length if needed (for larger positions)
2001
- * 7. Adds liquidity to the new position using deposit automation
2002
- *
2003
- * Key benefits:
2004
- * - Backwards-compatible with existing rebalance implementations
2005
- * - Supports large bin arrays through automatic transaction splitting into multiple transactions
2006
- * - Does NOT depend on Meteora SDK
2007
- * - Handles positions that exceed single transaction size limits
2008
- * - Uses increasePositionLengthAutomation for larger new positions
2009
- *
2010
- * @param connection The Solana web3 connection object for blockchain interactions.
2011
- * @param params Parameters required for rebalance (same as MeteoraRebalance)
2012
- * @returns Array of TransactionMetadataResponse for each transaction
2013
- */
2014
- rebalanceLargerPositionAutomation(_a) {
1989
+ rebalanceSmallPositionAutomation(_a) {
2015
1990
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2016
1991
  // Current theoretical limit (149-bin)
2017
1992
  const MAX_POSITION_WIDTH = 149;
@@ -2267,6 +2242,7 @@ class Transactions {
2267
2242
  }
2268
2243
  redepositForLargePositionAutomationIx(_a) {
2269
2244
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2245
+ var _b;
2270
2246
  try {
2271
2247
  const program = yield meteora_1.MeteoraDLMM.program(connection);
2272
2248
  const positionData = yield program.account.positionV2.fetch(params.position);
@@ -2292,7 +2268,6 @@ class Transactions {
2292
2268
  const remainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2293
2269
  const transactions = [];
2294
2270
  const withdrawIxs = [];
2295
- const depositIxs = [];
2296
2271
  const removeLiquidityIx = yield this.ix.meteoraDlmm.removeLiquidityByRange2Automation({
2297
2272
  connection,
2298
2273
  userWallet: params.userWallet,
@@ -2310,9 +2285,20 @@ class Transactions {
2310
2285
  });
2311
2286
  withdrawIxs.push(removeLiquidityIx);
2312
2287
  const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2313
- const relativeLowerBin = currentLowerBinId - activeId;
2314
- const relativeUpperBin = currentUpperBinId - activeId;
2315
- const addLiquidityIx = yield this.ix.meteoraDlmm.meteoraDlmmDepositRelativeAutomation({
2288
+ // Compute total token amounts from position bin data for strategy parameter calculation
2289
+ const positionBinData = userPosition.positionData.positionBinData;
2290
+ const { totalXAmount, totalYAmount } = positionBinData.reduce((acc, bin) => ({
2291
+ totalXAmount: acc.totalXAmount.add(new bn_js_1.default(bin.positionXAmount)),
2292
+ totalYAmount: acc.totalYAmount.add(new bn_js_1.default(bin.positionYAmount)),
2293
+ }), { totalXAmount: new bn_js_1.default(0), totalYAmount: new bn_js_1.default(0) });
2294
+ const distributionToStrategyType = {
2295
+ 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
2296
+ 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
2297
+ '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,
2298
+ };
2299
+ const strategyType = (_b = distributionToStrategyType[params.distribution]) !== null && _b !== void 0 ? _b : liquidityStrategy_1.StrategyType.SPOT;
2300
+ // Deposit using chunked rebalanceLiquidityAutomation (handles >70 bins)
2301
+ const depositIxArrays = yield this._meteoraDepositToLargePositionAutomation({
2316
2302
  connection,
2317
2303
  userWallet: params.userWallet,
2318
2304
  lbPair,
@@ -2321,38 +2307,28 @@ class Transactions {
2321
2307
  tokenYMint,
2322
2308
  tokenXProgram,
2323
2309
  tokenYProgram,
2310
+ lowerBinId: currentLowerBinId,
2311
+ upperBinId: currentUpperBinId,
2312
+ strategyType,
2324
2313
  activeId,
2325
- relativeBinRange: {
2326
- lowerRange: relativeLowerBin,
2327
- upperRange: relativeUpperBin,
2328
- },
2329
- strategyType: types_3.StrategyTypeMap[params.distribution],
2330
- pdaTokenType: types_1.TokenType.ATA,
2331
- remainingAccountsInfo,
2332
- positionIsSigner: false,
2314
+ totalXAmount,
2315
+ totalYAmount,
2316
+ skipInitBinArrays: true,
2333
2317
  });
2334
- depositIxs.push(addLiquidityIx);
2335
- const positionWidth = currentUpperBinId - currentLowerBinId + 1;
2336
- if (positionWidth <= 70) {
2337
- transactions.push(yield (0, functions_1.createTransactionMeta)({
2338
- payer: params.userWallet,
2339
- description: 'Automation IX: Meteora Redeposit: Remove liquidity + add liquidity',
2340
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2341
- mainInstructions: [...withdrawIxs, ...depositIxs],
2342
- }));
2343
- }
2344
- else {
2345
- transactions.push(yield (0, functions_1.createTransactionMeta)({
2346
- payer: params.userWallet,
2347
- description: 'Automation IX: Meteora Redeposit TX1: Remove liquidity',
2348
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2349
- mainInstructions: withdrawIxs,
2350
- }));
2318
+ // TX1: withdraw (full range)
2319
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
2320
+ payer: params.userWallet,
2321
+ description: 'Automation IX: Meteora Redeposit TX1: Remove liquidity',
2322
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2323
+ mainInstructions: withdrawIxs,
2324
+ }));
2325
+ // TX2..N: deposit chunks
2326
+ for (let i = 0; i < depositIxArrays.length; i++) {
2351
2327
  transactions.push(yield (0, functions_1.createTransactionMeta)({
2352
2328
  payer: params.userWallet,
2353
- description: 'Automation IX: Meteora Redeposit TX2: Add liquidity',
2329
+ description: `Automation IX: Meteora Redeposit TX${i + 2}: Add liquidity`,
2354
2330
  addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2355
- mainInstructions: depositIxs,
2331
+ mainInstructions: depositIxArrays[i],
2356
2332
  }));
2357
2333
  }
2358
2334
  return transactions;
@@ -2366,10 +2342,213 @@ class Transactions {
2366
2342
  }
2367
2343
  });
2368
2344
  }
2345
+ /**
2346
+ * Phased rebalance for Meteora DLMM positions (71-149 bins).
2347
+ *
2348
+ * Produces exactly 2 TXs:
2349
+ * TX1: removeLiquidity + claimFee (with fee splitting) + claimRewards + closePosition
2350
+ * TX2: initPosition + extendPosition + initBinArrays + deposit (rebalanceLiquidityAutomation)
2351
+ *
2352
+ * Uses rebalanceLiquidityAutomation for deposit (handles 149 bins reliably),
2353
+ * unlike rebalanceSmallPositionAutomation which uses meteoraDlmmDepositRelativeAutomation.
2354
+ * Separate withdraw/deposit TXs enable Jupiter swap injection by the caller.
2355
+ */
2356
+ rebalancePhasedPositionAutomation(_a) {
2357
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2358
+ var _b, _c, _d;
2359
+ const MAX_POSITION_WIDTH = 149;
2360
+ const MAX_INIT_WIDTH = 70;
2361
+ const MAX_EXTEND_LENGTH = 91;
2362
+ try {
2363
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
2364
+ const positionData = yield program.account.positionV2.fetch(params.currentPosition);
2365
+ if (!positionData || !positionData.lbPair) {
2366
+ throw new Error(`Invalid position data: ${params.currentPosition.toString()}`);
2367
+ }
2368
+ const lbPair = positionData.lbPair;
2369
+ const currentLowerBinId = positionData.lowerBinId;
2370
+ const currentUpperBinId = positionData.upperBinId;
2371
+ if (params.width > MAX_POSITION_WIDTH) {
2372
+ throw new Error(`Position width ${params.width} exceeds maximum ${MAX_POSITION_WIDTH}`);
2373
+ }
2374
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
2375
+ const userPda = (0, functions_1.generateUserPda)(params.userWallet);
2376
+ const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
2377
+ const userPosition = userPositions.find(pos => pos.publicKey.equals(params.currentPosition));
2378
+ if (!userPosition) {
2379
+ throw new Error(`Position ${params.currentPosition.toString()} not found`);
2380
+ }
2381
+ const positionBinData = userPosition.positionData.positionBinData;
2382
+ const { totalXAmount, totalYAmount } = positionBinData.reduce((acc, bin) => ({
2383
+ totalXAmount: acc.totalXAmount.add(new bn_js_1.default(bin.positionXAmount)),
2384
+ totalYAmount: acc.totalYAmount.add(new bn_js_1.default(bin.positionYAmount)),
2385
+ }), { totalXAmount: new bn_js_1.default(0), totalYAmount: new bn_js_1.default(0) });
2386
+ const lbPairState = dlmmPool.dlmm.lbPair;
2387
+ const tokenXMint = lbPairState.tokenXMint;
2388
+ const tokenYMint = lbPairState.tokenYMint;
2389
+ const rewardInfos = lbPairState.rewardInfos;
2390
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
2391
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
2392
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
2393
+ const remainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2394
+ const pdaTokenTypeForClaimables = params.useAta ? types_1.TokenType.ATA : types_1.TokenType.STA;
2395
+ const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2396
+ const distributionToStrategyType = {
2397
+ 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
2398
+ 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
2399
+ '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,
2400
+ };
2401
+ const strategyType = (_b = distributionToStrategyType[params.distribution]) !== null && _b !== void 0 ? _b : liquidityStrategy_1.StrategyType.SPOT;
2402
+ // =========================================================================
2403
+ // TX1: Withdraw + Claim + Close (separate IXs — preserves fee splitting)
2404
+ // =========================================================================
2405
+ const group1Ixs = [];
2406
+ const removeLiquidityIx = yield this.ix.meteoraDlmm.removeLiquidityByRange2Automation({
2407
+ connection,
2408
+ userWallet: params.userWallet,
2409
+ lbPair,
2410
+ position: params.currentPosition,
2411
+ tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2412
+ fromBinId: currentLowerBinId,
2413
+ toBinId: currentUpperBinId,
2414
+ bpsToRemove: 10000,
2415
+ pdaTokenType: types_1.TokenType.ATA,
2416
+ remainingAccountsInfo,
2417
+ });
2418
+ group1Ixs.push(removeLiquidityIx);
2419
+ const claimFeeIx = yield this.ix.meteoraDlmm.claimFee2Automation(connection, {
2420
+ userWallet: params.userWallet,
2421
+ lbPair,
2422
+ position: params.currentPosition,
2423
+ tokenMintX: tokenXMint, tokenMintY: tokenYMint,
2424
+ tokenProgramX: tokenXProgram, tokenProgramY: tokenYProgram,
2425
+ lowerBinId: currentLowerBinId, upperBinId: currentUpperBinId,
2426
+ pdaTokenType: pdaTokenTypeForClaimables,
2427
+ remainingAccountsInfo,
2428
+ });
2429
+ group1Ixs.push(claimFeeIx);
2430
+ for (let rewardIndex = 0; rewardIndex < 2; rewardIndex++) {
2431
+ const rewardInfo = rewardInfos[rewardIndex];
2432
+ if (!rewardInfo || rewardInfo.mint.equals(web3.PublicKey.default))
2433
+ continue;
2434
+ const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [rewardInfo.mint]);
2435
+ const rewardTokenProgram = rewardTokenProgramMap[rewardInfo.mint.toString()];
2436
+ const rewardRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, rewardInfo.mint, rewardTokenProgram);
2437
+ const claimRewardIx = yield this.ix.meteoraDlmm.claimReward2Automation(connection, {
2438
+ userWallet: params.userWallet,
2439
+ lbPair,
2440
+ position: params.currentPosition,
2441
+ rewardIndex,
2442
+ rewardMint: rewardInfo.mint,
2443
+ rewardVault: rewardInfo.vault,
2444
+ tokenProgram: rewardTokenProgram,
2445
+ lowerBinId: currentLowerBinId, upperBinId: currentUpperBinId,
2446
+ pdaTokenType: types_1.TokenType.STA,
2447
+ remainingAccountsInfo: rewardRemainingAccountsInfo,
2448
+ });
2449
+ group1Ixs.push(claimRewardIx);
2450
+ }
2451
+ const closePositionIx = yield this.ix.meteoraDlmm.closePosition2Automation({
2452
+ connection,
2453
+ userWallet: params.userWallet,
2454
+ position: params.currentPosition,
2455
+ lbPair,
2456
+ });
2457
+ group1Ixs.push(closePositionIx);
2458
+ // =========================================================================
2459
+ // TX2: Init position + Extend + InitBinArrays + Deposit (rebalanceLiquidityAutomation)
2460
+ // =========================================================================
2461
+ const group2Ixs = [];
2462
+ const initialWidth = Math.min(MAX_INIT_WIDTH, params.width);
2463
+ const initPositionIx = yield this.ix.meteoraDlmm.initializePositionRelativeAutomation(connection, {
2464
+ userWallet: params.userWallet,
2465
+ lbPair,
2466
+ position: params.newPosition,
2467
+ relativeLowerBinId: params.relativeLowerBin,
2468
+ width: initialWidth,
2469
+ });
2470
+ group2Ixs.push(initPositionIx);
2471
+ let positionBinsAllocated = initialWidth;
2472
+ while (positionBinsAllocated < params.width) {
2473
+ const toAdd = Math.min(MAX_EXTEND_LENGTH, params.width - positionBinsAllocated);
2474
+ const extendIx = yield this.ix.meteoraDlmm.increasePositionLengthAutomation({
2475
+ connection,
2476
+ userWallet: params.userWallet,
2477
+ lbPair,
2478
+ position: params.newPosition,
2479
+ lengthToAdd: toAdd,
2480
+ side: types_1.MeteoraPositionSide.Upper,
2481
+ });
2482
+ group2Ixs.push(extendIx);
2483
+ positionBinsAllocated += toAdd;
2484
+ }
2485
+ const newLowerBinId = activeId + params.relativeLowerBin;
2486
+ const newUpperBinId = newLowerBinId + params.width - 1;
2487
+ // Only initialize bin arrays that don't exist yet (avoids bloating TX with redundant inits)
2488
+ const binArraysRequired = yield (0, dlmm_1.getBinArraysRequiredByPositionRange)(lbPair, new bn_js_1.default(newLowerBinId), new bn_js_1.default(newUpperBinId), dlmmPool.dlmm.program.programId);
2489
+ if (binArraysRequired.length > 0) {
2490
+ const initBinArraysIx = yield dlmmPool.dlmm.initializeBinArrays(binArraysRequired.map(b => b.index), addresses_1.HS_AUTHORITY);
2491
+ group2Ixs.push(...initBinArraysIx);
2492
+ }
2493
+ // Use adjusted amounts for strategy computation if provided (post-swap prediction).
2494
+ // When a Jupiter swap occurs between withdraw and deposit, the ATA balances change.
2495
+ // Strategy parameters (x0, y0) must match what will actually be in the ATA at deposit time.
2496
+ const depositXAmount = (_c = params.adjustedTotalXAmount) !== null && _c !== void 0 ? _c : totalXAmount;
2497
+ const depositYAmount = (_d = params.adjustedTotalYAmount) !== null && _d !== void 0 ? _d : totalYAmount;
2498
+ // Skip bin array init inside deposit helper since we handled it above.
2499
+ // Allow active bin slippage of 10 bins to tolerate price movement from the
2500
+ // Jupiter swap that may occur between the withdraw TX and this deposit TX.
2501
+ const depositIxArrays = yield this._meteoraDepositToLargePositionAutomation({
2502
+ connection,
2503
+ userWallet: params.userWallet,
2504
+ lbPair,
2505
+ position: params.newPosition,
2506
+ tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2507
+ lowerBinId: newLowerBinId,
2508
+ upperBinId: newUpperBinId,
2509
+ strategyType,
2510
+ activeId,
2511
+ totalXAmount: depositXAmount,
2512
+ totalYAmount: depositYAmount,
2513
+ skipInitBinArrays: true,
2514
+ maxActiveBinSlippage: 10,
2515
+ });
2516
+ // For ≤149 bins, depositIxArrays has exactly 1 chunk
2517
+ group2Ixs.push(...depositIxArrays[0]);
2518
+ // =========================================================================
2519
+ // Assemble TXs
2520
+ // =========================================================================
2521
+ const transactions = [];
2522
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
2523
+ payer: params.userWallet,
2524
+ description: 'Automation IX: Meteora Phased Rebalance TX1: Withdraw + Claim + Close',
2525
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2526
+ mainInstructions: group1Ixs,
2527
+ }));
2528
+ transactions.push(yield (0, functions_1.createTransactionMeta)({
2529
+ payer: params.userWallet,
2530
+ description: 'Automation IX: Meteora Phased Rebalance TX2: Init + Deposit',
2531
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2532
+ mainInstructions: group2Ixs,
2533
+ }));
2534
+ return transactions;
2535
+ }
2536
+ catch (error) {
2537
+ console.error('=== REBALANCE PHASED POSITION AUTOMATION ERROR ===');
2538
+ console.error('Error type:', error instanceof Error ? error.constructor.name : typeof error);
2539
+ console.error('Error message:', error instanceof Error ? error.message : String(error));
2540
+ console.error('Error stack:', error instanceof Error ? error.stack : 'No stack trace');
2541
+ console.error('Full error object:', error);
2542
+ console.error('=== END ERROR LOG ===');
2543
+ throw error;
2544
+ }
2545
+ });
2546
+ }
2369
2547
  /**
2370
2548
  * Rebalance a large Meteora DLMM position (up to 1400 bins) using automation instructions.
2371
2549
  *
2372
- * For ≤149 bins, delegates to rebalanceLargerPositionAutomation.
2550
+ * For ≤70 bins, delegates to rebalanceSmallerPositionAutomation.
2551
+ * For 71-149 bins, delegates to rebalancePhasedPositionAutomation.
2373
2552
  * For ≥150 bins, uses a chunked multi-TX approach:
2374
2553
  * Phase 1: Chunked withdraw from current position
2375
2554
  * Phase 2: Initialize new large position
@@ -2393,9 +2572,13 @@ class Transactions {
2393
2572
  const currentLowerBinId = positionData.lowerBinId;
2394
2573
  const currentUpperBinId = positionData.upperBinId;
2395
2574
  const currentBinCount = currentUpperBinId - currentLowerBinId + 1;
2396
- // For ≤149 bins, delegate to existing rebalanceLargerPositionAutomation
2575
+ // For ≤70 bins, delegate to existing rebalanceSmallPositionAutomation
2576
+ if (currentBinCount <= 70 && params.width <= 70) {
2577
+ return this.rebalanceSmallPositionAutomation({ connection, params, fetch: undefined });
2578
+ }
2579
+ // For 71-149 bins, use phased approach (separate withdraw/deposit TXs)
2397
2580
  if (currentBinCount <= 149 && params.width <= 149) {
2398
- return this.rebalanceLargerPositionAutomation({ connection, params, fetch: undefined });
2581
+ return this.rebalancePhasedPositionAutomation({ connection, params, fetch: undefined });
2399
2582
  }
2400
2583
  // ≥150 bins: multi-TX chunked approach
2401
2584
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
@@ -2543,7 +2726,7 @@ class Transactions {
2543
2726
  tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2544
2727
  activeId: params.activeId,
2545
2728
  pdaTokenType: types_1.TokenType.ATA,
2546
- maxActiveBinSlippage: 300,
2729
+ maxActiveBinSlippage: 0,
2547
2730
  shouldClaimFee: false,
2548
2731
  shouldClaimReward: false,
2549
2732
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -2560,304 +2743,121 @@ class Transactions {
2560
2743
  });
2561
2744
  }
2562
2745
  /**
2563
- * @note DO NOT USE. STILL UNDER DEVELOPMENT. Tests still failing
2564
- * Reshape position: withdraw from old bins and deposit to new bins on the SAME position.
2565
- *
2566
- * Uses only rebalanceLiquidityAutomation (one IX per TX):
2567
- * Remove TXs: rebalanceLiquidityAutomation with removeLiquidityParams (~75 bins/TX)
2568
- * Deposit TXs: rebalanceLiquidityAutomation with addLiquidityParams (~75 bins/TX)
2569
- *
2570
- * Meteora's rebalance_liquidity handles position extension and bin array
2571
- * initialization internally — no separate IXs needed.
2572
- *
2573
- * Key differences from rebalanceLargePositionAutomation:
2574
- * - Same position (no close/create, no new position keypair needed)
2575
- * - Supports positions of any size (69 to 1400+ bins)
2746
+ * Compute claimable fees for a position directly from on-chain account data.
2747
+ * Avoids expensive getPositionsByUserAndLbPair by parsing raw buffers.
2748
+ * Handles extended positions (>70 bins) by reading extended data after reserved bytes.
2749
+ * Reference: data/tvl/src/meteoraFunctions.ts:getBatchedFees
2576
2750
  */
2577
- meteoraRebalanceLargePositionAutomation2(_a) {
2578
- return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2579
- var _b, _c, _d;
2580
- try {
2581
- const WITHDRAW_CHUNK_SIZE = 200;
2582
- const DEPOSIT_CHUNK_SIZE = 200;
2583
- const DEPOSIT_CHUNK_INITIAL_SIZE = 100;
2584
- // Always reserve a small portion of bins for the pivot TX to ensure
2585
- // withdraw + deposit happen together (prevents ReallocExceedMaxLengthPerInstruction)
2586
- const PIVOT_RESERVE = 160;
2587
- // Fetch pool data
2588
- const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.lbPair, this.ix);
2589
- const userPda = (0, functions_1.generateUserPda)(params.userWallet);
2590
- const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2591
- // Get position's token amounts for deposit strategy calculation
2592
- const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
2593
- const userPosition = userPositions.find(pos => pos.publicKey.equals(params.position));
2594
- if (!userPosition) {
2595
- throw new Error(`Position ${params.position.toString()} not found`);
2596
- }
2597
- const positionBinData = userPosition.positionData.positionBinData;
2598
- // Use actual liquidity range (bins with non-zero amounts) instead of padded position struct range
2599
- const binsWithLiquidity = positionBinData.filter(bin => !new bn_js_1.default(bin.positionXAmount).isZero() || !new bn_js_1.default(bin.positionYAmount).isZero());
2600
- const oldLowerBinId = binsWithLiquidity.length > 0
2601
- ? binsWithLiquidity[0].binId
2602
- : userPosition.positionData.lowerBinId;
2603
- const oldUpperBinId = binsWithLiquidity.length > 0
2604
- ? binsWithLiquidity[binsWithLiquidity.length - 1].binId
2605
- : userPosition.positionData.upperBinId;
2606
- const { totalXAmount, totalYAmount } = positionBinData.reduce((acc, bin) => ({
2607
- totalXAmount: acc.totalXAmount.add(new bn_js_1.default(bin.positionXAmount)),
2608
- totalYAmount: acc.totalYAmount.add(new bn_js_1.default(bin.positionYAmount)),
2609
- }), { totalXAmount: new bn_js_1.default(0), totalYAmount: new bn_js_1.default(0) });
2610
- const newLowerBinId = activeId + params.relativeLowerBin;
2611
- const newUpperBinId = newLowerBinId + params.width - 1;
2612
- console.log(`Total chunk per tx (withdraw): ${WITHDRAW_CHUNK_SIZE} bins, total chunk per tx (deposit): ${DEPOSIT_CHUNK_SIZE} bins`);
2613
- console.log(`old lower bin id: ${oldLowerBinId}, old upper bin id: ${oldUpperBinId}, old width: ${oldUpperBinId - oldLowerBinId + 1}`);
2614
- console.log(`new lower bin id: ${newLowerBinId}, new upper bin id: ${newUpperBinId}, new width: ${newUpperBinId - newLowerBinId + 1}`);
2615
- const lbPairState = dlmmPool.dlmm.lbPair;
2616
- const tokenXMint = lbPairState.tokenXMint;
2617
- const tokenYMint = lbPairState.tokenYMint;
2618
- const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
2619
- const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
2620
- const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
2621
- // Fetch transfer hook accounts for token X and Y (Token2022 support)
2622
- const baseRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2623
- // Extract reward infos for claiming rewards during rebalance
2624
- const rewardInfos = [];
2625
- const rewardInfosFromPair = lbPairState.rewardInfos;
2626
- if (rewardInfosFromPair && rewardInfosFromPair.length > 0) {
2627
- // Collect reward mints that are active (non-default)
2628
- const activeRewardMints = [];
2629
- for (const reward of rewardInfosFromPair) {
2630
- if (!reward.mint.equals(web3.PublicKey.default)) {
2631
- activeRewardMints.push(reward.mint);
2632
- }
2633
- }
2634
- // Get token programs for reward mints
2635
- if (activeRewardMints.length > 0) {
2636
- const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, activeRewardMints);
2637
- for (let i = 0; i < rewardInfosFromPair.length; i++) {
2638
- const reward = rewardInfosFromPair[i];
2639
- if (!reward.mint.equals(web3.PublicKey.default)) {
2640
- rewardInfos.push({
2641
- rewardIndex: i,
2642
- rewardVault: reward.vault,
2643
- rewardMint: reward.mint,
2644
- rewardTokenProgram: rewardTokenProgramMap[reward.mint.toString()],
2645
- });
2646
- }
2647
- }
2648
- }
2649
- }
2650
- console.log(`[Pipeline] Found ${rewardInfos.length} active reward(s) for this pool`);
2651
- // Build combined remainingAccountsInfo with transfer hooks for X, Y, and rewards
2652
- // The slices describe: TransferHookX, TransferHookY, TransferHookMultiReward(index) for each reward
2653
- // IMPORTANT: Always include all slices, even with length=0, so Meteora knows the account structure
2654
- const combinedSlices = [];
2655
- const combinedAccounts = [];
2656
- // Always add TransferHookX and TransferHookY slices (even if length=0)
2657
- const xSlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookX);
2658
- const ySlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookY);
2659
- combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookX, length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0 });
2660
- combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookY, length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0 });
2661
- // Add transfer hook accounts from base (for X and Y)
2662
- combinedAccounts.push(...baseRemainingAccountsInfo.accounts);
2663
- // Fetch transfer hook accounts for each reward and add to combined info
2664
- // IMPORTANT: Always add TransferHookMultiReward slice for each reward, even if length=0
2665
- // This tells Meteora about the reward position in the remaining accounts
2666
- for (const reward of rewardInfos) {
2667
- const rewardTransferHookInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, reward.rewardMint, reward.rewardTokenProgram);
2668
- // Always add TransferHookMultiReward slice (even if empty length for standard SPL tokens)
2669
- const transferHookLength = rewardTransferHookInfo.slices.length > 0
2670
- ? rewardTransferHookInfo.slices[0].length
2671
- : 0;
2672
- combinedSlices.push({
2673
- accountsType: types_1.RemainingAccountsType.TransferHookMultiReward,
2674
- length: transferHookLength,
2675
- multiRewardIndex: reward.rewardIndex,
2676
- });
2677
- combinedAccounts.push(...rewardTransferHookInfo.accounts);
2678
- }
2679
- const remainingAccountsInfo = {
2680
- slices: combinedSlices,
2681
- accounts: combinedAccounts,
2682
- };
2683
- const distributionToStrategyType = {
2684
- 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
2685
- 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
2686
- '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,
2687
- };
2688
- const strategyType = (_d = distributionToStrategyType[params.distribution]) !== null && _d !== void 0 ? _d : liquidityStrategy_1.StrategyType.SPOT;
2689
- const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
2690
- // Build new-position deposit chunks
2691
- const minDeltaId = new bn_js_1.default(newLowerBinId - activeId);
2692
- const maxDeltaId = new bn_js_1.default(newUpperBinId - activeId);
2693
- const favorXInActiveId = totalYAmount.isZero() && !totalXAmount.isZero();
2694
- const strategyParams = (0, liquidityStrategy_1.buildStrategyParameters)(strategyType, totalXAmount, totalYAmount, minDeltaId, maxDeltaId, binStep, new bn_js_1.default(activeId), favorXInActiveId);
2695
- // =====================================================================
2696
- // Pipeline algorithm: pack withdraw + deposit work into fewer TXs.
2697
- //
2698
- // Given W old bins to withdraw and D new bins to deposit:
2699
- // Phase 1: Pure withdraw TXs — all withdraw chunks except the last
2700
- // Phase 2: Pivot TX — last withdraw chunk + extend + initBinArrays
2701
- // + first deposit (if small enough to fit without CU issues)
2702
- // Phase 3: Pure deposit TXs — remaining deposit bins by CHUNK_SIZE
2703
- //
2704
- // When the total extension is large or the deposit range spans many
2705
- // bin arrays, the transition IXs (extend + initBinArrays) are placed
2706
- // in a separate TX to avoid exceeding compute unit limits.
2707
- // =====================================================================
2708
- const txInstructions = [];
2709
- // Helper: build on-chain deposit param from a ChunkedDepositParameters
2710
- const buildDepositParam = (chunk) => {
2711
- const p = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunk.params.x0, chunk.params.y0, chunk.params.deltaX, chunk.params.deltaY);
2712
- return {
2713
- minDeltaId: chunk.minDeltaId.toNumber(),
2714
- maxDeltaId: chunk.maxDeltaId.toNumber(),
2715
- x0: p.x0, y0: p.y0, deltaX: p.deltaX, deltaY: p.deltaY,
2716
- bitFlag: p.bitFlag, favorXInActiveId,
2717
- };
2718
- };
2719
- // Helper: build withdraw IX
2720
- const buildWithdrawIx = (lower, upper) => __awaiter(this, void 0, void 0, function* () {
2721
- const binArrayOverrides = this.ix.pda.meteora.deriveBinArrays(params.lbPair, lower, upper);
2722
- return this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2723
- connection,
2724
- userWallet: params.userWallet,
2725
- position: params.position,
2726
- lbPair: params.lbPair,
2727
- tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2728
- activeId,
2729
- pdaTokenType: types_1.TokenType.ATA,
2730
- maxActiveBinSlippage: 300,
2731
- shouldClaimFee: true,
2732
- shouldClaimReward: rewardInfos.length > 0,
2733
- minWithdrawXAmount: new bn_js_1.default(0),
2734
- maxDepositXAmount: new bn_js_1.default(0),
2735
- minWithdrawYAmount: new bn_js_1.default(0),
2736
- maxDepositYAmount: new bn_js_1.default(0),
2737
- removeLiquidityParams: [{ minBinId: lower, maxBinId: upper, bps: 10000 }],
2738
- addLiquidityParams: [],
2739
- binArrayOverrides,
2740
- shrinkMode: types_3.ShrinkMode.Default,
2741
- rewardInfos,
2742
- remainingAccountsInfo,
2743
- });
2751
+ _computeClaimableFees(connection, position, lbPair, lowerBinId, upperBinId) {
2752
+ return __awaiter(this, void 0, void 0, function* () {
2753
+ const MAX_BIN_PER_ARRAY = 70;
2754
+ const DLMM_PROGRAM_ID = new web3.PublicKey('LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo');
2755
+ const positionAccountInfo = yield connection.getAccountInfo(position);
2756
+ if (!positionAccountInfo || !positionAccountInfo.data) {
2757
+ throw new Error(`Failed to fetch position account: ${position.toString()}`);
2758
+ }
2759
+ const posBuffer = positionAccountInfo.data;
2760
+ const binCount = upperBinId - lowerBinId + 1;
2761
+ // PositionV2 struct layout offsets
2762
+ const LIQUIDITY_OFFSET = 72; // 8 discriminator + 32 lbPair + 32 owner
2763
+ const REWARD_OFFSET = LIQUIDITY_OFFSET + 70 * 16; // liquidityShares: u128[70]
2764
+ const FEE_OFFSET = REWARD_OFFSET + 70 * 48; // rewardInfos: UserRewardInfo[70], 48 bytes each
2765
+ // After feeInfos[70]: lowerBinId(4) + upperBinId(4) + lastUpdatedAt(8) + totalClaimedFeeX(8) + totalClaimedFeeY(8) + totalClaimedRewards(16) + reserved(160)
2766
+ const EXTENDED_OFFSET = FEE_OFFSET + 70 * 48 + 4 + 4 + 8 + 8 + 8 + 16 + 160;
2767
+ function readU64(buf, off) {
2768
+ return buf.readBigUInt64LE(off);
2769
+ }
2770
+ function readU128(buf, off) {
2771
+ const low = buf.readBigUInt64LE(off);
2772
+ const high = buf.readBigUInt64LE(off + 8);
2773
+ return low + (high << BigInt(64));
2774
+ }
2775
+ const liquidityShares = [];
2776
+ const feeInfos = [];
2777
+ const binsInFixed = Math.min(binCount, 70);
2778
+ for (let i = 0; i < binsInFixed; i++) {
2779
+ liquidityShares.push(readU128(posBuffer, LIQUIDITY_OFFSET + i * 16));
2780
+ const feeStart = FEE_OFFSET + i * 48;
2781
+ feeInfos.push({
2782
+ feeXPerTokenComplete: readU128(posBuffer, feeStart),
2783
+ feeYPerTokenComplete: readU128(posBuffer, feeStart + 16),
2784
+ feeXPending: readU64(posBuffer, feeStart + 32),
2785
+ feeYPending: readU64(posBuffer, feeStart + 40),
2744
2786
  });
2745
- // Helper: build deposit IX from a deposit chunk
2746
- const buildDepositIx = (chunk, removeLiquidityParams) => __awaiter(this, void 0, void 0, function* () {
2747
- let trueMin = chunk.lowerBinId;
2748
- let trueMax = chunk.upperBinId;
2749
- if (removeLiquidityParams) {
2750
- trueMin = Math.min(chunk.lowerBinId, removeLiquidityParams.minBinId);
2751
- trueMax = Math.max(chunk.upperBinId, removeLiquidityParams.maxBinId);
2752
- }
2753
- const binArrayOverrides = this.ix.pda.meteora.deriveBinArrays(params.lbPair, trueMin, trueMax);
2754
- return yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2755
- connection,
2756
- userWallet: params.userWallet,
2757
- position: params.position,
2758
- lbPair: params.lbPair,
2759
- tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2760
- activeId,
2761
- pdaTokenType: types_1.TokenType.ATA,
2762
- maxActiveBinSlippage: 300,
2763
- shouldClaimFee: removeLiquidityParams ? true : false,
2764
- shouldClaimReward: !!removeLiquidityParams && rewardInfos.length > 0,
2765
- minWithdrawXAmount: new bn_js_1.default(0),
2766
- maxDepositXAmount: chunk.maxAmountX,
2767
- minWithdrawYAmount: new bn_js_1.default(0),
2768
- maxDepositYAmount: chunk.maxAmountY,
2769
- removeLiquidityParams: removeLiquidityParams ? [{ minBinId: removeLiquidityParams.minBinId, maxBinId: removeLiquidityParams.maxBinId, bps: 10000 }] : [],
2770
- addLiquidityParams: [buildDepositParam(chunk)],
2771
- binArrayOverrides,
2772
- shrinkMode: removeLiquidityParams ? types_3.ShrinkMode.Default : types_3.ShrinkMode.NoShrinkBoth,
2773
- rewardInfos: removeLiquidityParams ? rewardInfos : undefined,
2774
- remainingAccountsInfo,
2787
+ }
2788
+ // Extended bins (>70) appended after reserved bytes
2789
+ if (binCount > 70) {
2790
+ let offset = EXTENDED_OFFSET;
2791
+ for (let i = 70; i < binCount; i++) {
2792
+ liquidityShares.push(readU128(posBuffer, offset));
2793
+ offset += 16;
2794
+ offset += 48; // skip rewardInfo
2795
+ feeInfos.push({
2796
+ feeXPerTokenComplete: readU128(posBuffer, offset),
2797
+ feeYPerTokenComplete: readU128(posBuffer, offset + 16),
2798
+ feeXPending: readU64(posBuffer, offset + 32),
2799
+ feeYPending: readU64(posBuffer, offset + 40),
2775
2800
  });
2776
- });
2777
- // Build transition IXs: increasePositionLength + initBinArrays.
2778
- // Bin arrays must be pre-initialized before rebalanceLiquidity deposits.
2779
- const increasePositionLengthIxs = [];
2780
- // Generate increasePositionLength IXs to extend position (assumption at the moment, I expect calculation to be wrong)
2781
- let currentLower = newLowerBinId + WITHDRAW_CHUNK_SIZE;
2782
- while (currentLower < newUpperBinId) {
2783
- const currentWidth = newUpperBinId - currentLower + 1;
2784
- const binsToAdd = Math.min(91, currentWidth);
2785
- console.log('Increasing position length by', binsToAdd, 'bins at lower', currentLower);
2786
- increasePositionLengthIxs.push(yield this.ix.meteoraDlmm.increasePositionLengthAutomation({
2787
- connection,
2788
- userWallet: params.userWallet,
2789
- lbPair: params.lbPair,
2790
- position: params.position,
2791
- lengthToAdd: binsToAdd,
2792
- side: types_1.MeteoraPositionSide.Upper,
2793
- }));
2794
- currentLower = currentLower + binsToAdd;
2795
- }
2796
- // Build all deposit chunks upfront
2797
- const depositChunks = (0, liquidityStrategy_1.chunkDepositParametersWithInitialSize)(strategyParams, minDeltaId, maxDeltaId, new bn_js_1.default(activeId), binStep, DEPOSIT_CHUNK_INITIAL_SIZE, DEPOSIT_CHUNK_SIZE, favorXInActiveId);
2798
- // Build old-position withdraw chunks, reserving PIVOT_RESERVE bins for pivot TX
2799
- const oldWidth = oldUpperBinId - oldLowerBinId + 1;
2800
- const oldChunks = [];
2801
- let current = oldLowerBinId;
2802
- // Build Phase 1 withdraw chunks (before pivot)
2803
- while (current < oldUpperBinId) {
2804
- const upper = Math.min(WITHDRAW_CHUNK_SIZE - 1, oldUpperBinId - current) + current;
2805
- console.log(`Generating withdraw chunk: [${current}, ${upper}, ${upper - current + 1} bins]`);
2806
- oldChunks.push({ lower: current, upper });
2807
- current = upper + 1;
2808
- }
2809
- const remainder = oldWidth % WITHDRAW_CHUNK_SIZE;
2810
- if (remainder === 0 || remainder > PIVOT_RESERVE) {
2811
- // Pop last chunk to reserve for pivot
2812
- const popped = oldChunks.pop();
2813
- // Then insert bigger and final chunk for pivot
2814
- const upper = popped.upper - PIVOT_RESERVE;
2815
- oldChunks.push({ lower: popped.lower, upper });
2816
- oldChunks.push({ lower: upper + 1, upper: popped.upper });
2801
+ offset += 48;
2817
2802
  }
2818
- // =====================================================================
2819
- // Phase 1: Pure withdraw TXs — all chunks in oldChunks (before pivot)
2820
- // =====================================================================
2821
- for (const chunk of oldChunks) {
2822
- console.log(`Withdrawing from chunk: [${chunk.lower}, ${chunk.upper}]`);
2823
- txInstructions.push([yield buildWithdrawIx(chunk.lower, chunk.upper)]);
2824
- }
2825
- // Pop the last one
2826
- txInstructions.pop();
2827
- // Get the last withdraw chunk for pivot
2828
- const lastWithdrawChunk = oldChunks[oldChunks.length - 1];
2829
- // =====================================================================
2830
- // Phase 2 (Pivot TX): Withdraw pivot reserve + first deposit
2831
- // This ensures bins "jump" to new position, preventing ReallocExceedMaxLengthPerInstruction
2832
- // =====================================================================
2833
- txInstructions.push([
2834
- yield buildDepositIx(depositChunks[0], { minBinId: lastWithdrawChunk.lower, maxBinId: lastWithdrawChunk.upper }),
2835
- ...increasePositionLengthIxs,
2836
- ]);
2837
- // =====================================================================
2838
- // Phase 3: Remaining deposit TXs
2839
- // - Second deposit (i=1): includes increasePositionLengthIxs if needed
2840
- // - Subsequent deposits (i=2+): pure deposit
2841
- // =====================================================================
2842
- for (let i = 1; i < depositChunks.length; i++) {
2843
- const chunk = depositChunks[i];
2844
- txInstructions.push([yield buildDepositIx(chunk)]);
2803
+ }
2804
+ // Derive and fetch bin array accounts
2805
+ const binArrayIndices = new Set();
2806
+ for (let i = 0; i < binCount; i++) {
2807
+ binArrayIndices.add(Math.floor((lowerBinId + i) / MAX_BIN_PER_ARRAY));
2808
+ }
2809
+ const binArrayIndexList = Array.from(binArrayIndices);
2810
+ const binArrayPDAs = binArrayIndexList.map(index => {
2811
+ const buf = Buffer.alloc(8);
2812
+ buf.writeBigInt64LE(BigInt(index));
2813
+ const [pda] = web3.PublicKey.findProgramAddressSync([Buffer.from('bin_array'), lbPair.toBytes(), buf], DLMM_PROGRAM_ID);
2814
+ return pda;
2815
+ });
2816
+ const binArrayAccounts = yield connection.getMultipleAccountsInfo(binArrayPDAs);
2817
+ // Parse bin array fee accumulators
2818
+ const BIN_ARRAY_HEADER = 56;
2819
+ const BIN_SIZE = 144;
2820
+ const binArrayFeeMap = new Map();
2821
+ for (let a = 0; a < binArrayIndexList.length; a++) {
2822
+ const account = binArrayAccounts[a];
2823
+ if (!account || !account.data)
2824
+ continue;
2825
+ const feeMap = new Map();
2826
+ for (let b = 0; b < MAX_BIN_PER_ARRAY; b++) {
2827
+ const binStart = BIN_ARRAY_HEADER + b * BIN_SIZE;
2828
+ feeMap.set(b, {
2829
+ feeXStored: readU128(account.data, binStart + 80),
2830
+ feeYStored: readU128(account.data, binStart + 96),
2831
+ });
2845
2832
  }
2846
- // Wrap each instruction array with createTransactionMeta
2847
- const transactions = [];
2848
- for (let i = 0; i < txInstructions.length; i++) {
2849
- transactions.push(yield (0, functions_1.createTransactionMeta)({
2850
- payer: params.userWallet,
2851
- description: `Automation IX: Reshape position (tx ${i + 1}/${txInstructions.length})`,
2852
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2853
- mainInstructions: txInstructions[i],
2854
- }));
2833
+ binArrayFeeMap.set(binArrayIndexList[a], feeMap);
2834
+ }
2835
+ // Compute total claimable fees
2836
+ let totalFeeX = BigInt(0);
2837
+ let totalFeeY = BigInt(0);
2838
+ for (let i = 0; i < binCount; i++) {
2839
+ const binId = lowerBinId + i;
2840
+ const arrayIndex = Math.floor(binId / MAX_BIN_PER_ARRAY);
2841
+ const binIndexInArray = binId - arrayIndex * MAX_BIN_PER_ARRAY;
2842
+ let feeX = feeInfos[i].feeXPending;
2843
+ let feeY = feeInfos[i].feeYPending;
2844
+ const binArray = binArrayFeeMap.get(arrayIndex);
2845
+ if (binArray && liquidityShares[i] > BigInt(0)) {
2846
+ const binData = binArray.get(binIndexInArray);
2847
+ if (binData) {
2848
+ const deltaX = binData.feeXStored - feeInfos[i].feeXPerTokenComplete;
2849
+ const deltaY = binData.feeYStored - feeInfos[i].feeYPerTokenComplete;
2850
+ feeX += (liquidityShares[i] * deltaX) >> BigInt(128);
2851
+ feeY += (liquidityShares[i] * deltaY) >> BigInt(128);
2852
+ }
2855
2853
  }
2856
- return transactions;
2857
- }
2858
- catch (error) {
2859
- throw error;
2854
+ totalFeeX += feeX;
2855
+ totalFeeY += feeY;
2860
2856
  }
2857
+ return {
2858
+ feeX: new bn_js_1.default(totalFeeX.toString()),
2859
+ feeY: new bn_js_1.default(totalFeeY.toString()),
2860
+ };
2861
2861
  });
2862
2862
  }
2863
2863
  /**
@@ -2868,7 +2868,8 @@ class Transactions {
2868
2868
  _meteoraDepositToLargePositionAutomation(params) {
2869
2869
  return __awaiter(this, void 0, void 0, function* () {
2870
2870
  const MAX_BINS_PER_TX = 149;
2871
- const { connection, userWallet, lbPair, position, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, lowerBinId, upperBinId, strategyType, activeId, totalXAmount, totalYAmount, } = params;
2871
+ const { connection, userWallet, lbPair, position, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, lowerBinId, upperBinId, strategyType, activeId, totalXAmount, totalYAmount, skipInitBinArrays, maxActiveBinSlippage: maxActiveBinSlippageParam, } = params;
2872
+ const maxActiveBinSlippage = maxActiveBinSlippageParam !== null && maxActiveBinSlippageParam !== void 0 ? maxActiveBinSlippageParam : 0;
2872
2873
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
2873
2874
  const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
2874
2875
  // Calculate delta IDs relative to active bin for entire position
@@ -2886,16 +2887,20 @@ class Transactions {
2886
2887
  // Convert strategy parameters to on-chain format with bitFlag for negative values
2887
2888
  const onChainParams = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunk.params.x0, chunk.params.y0, chunk.params.deltaX, chunk.params.deltaY);
2888
2889
  const instructions = [];
2889
- // Add initialize bin arrays instruction
2890
- // Use HS_AUTHORITY as funder since this is a raw Meteora IX and the automation worker signs with this key
2891
- const initBinArraysIx = yield this.ix.meteoraDlmm.meteoraDlmmInitializeBinArrayDefault({
2892
- connection,
2893
- userWallet: addresses_1.HS_AUTHORITY,
2894
- lbPair,
2895
- lowerBinId: chunk.lowerBinId,
2896
- upperBinId: chunk.upperBinId,
2897
- });
2898
- instructions.push(...initBinArraysIx);
2890
+ // Add initialize bin arrays instruction only when bin arrays may not yet exist.
2891
+ // For compound operations the position already exists, so bin arrays are already
2892
+ // initialized skipping these saves TX space.
2893
+ if (!skipInitBinArrays) {
2894
+ // Use HS_AUTHORITY as funder since this is a raw Meteora IX and the automation worker signs with this key
2895
+ const initBinArraysIx = yield this.ix.meteoraDlmm.meteoraDlmmInitializeBinArrayDefault({
2896
+ connection,
2897
+ userWallet: addresses_1.HS_AUTHORITY,
2898
+ lbPair,
2899
+ lowerBinId: chunk.lowerBinId,
2900
+ upperBinId: chunk.upperBinId,
2901
+ });
2902
+ instructions.push(...initBinArraysIx);
2903
+ }
2899
2904
  // Add liquidity via rebalanceLiquidityAutomation
2900
2905
  // Use u64::MAX for maxDeposit amounts so they don't cap the deposit.
2901
2906
  // The on-chain program uses ATA balance for actual amounts; these are just safety ceilings.
@@ -2911,7 +2916,7 @@ class Transactions {
2911
2916
  tokenYProgram,
2912
2917
  activeId,
2913
2918
  pdaTokenType: types_1.TokenType.ATA,
2914
- maxActiveBinSlippage: 300,
2919
+ maxActiveBinSlippage,
2915
2920
  shouldClaimFee: false,
2916
2921
  shouldClaimReward: false,
2917
2922
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -3110,7 +3115,7 @@ class Transactions {
3110
3115
  tokenYProgram,
3111
3116
  activeId,
3112
3117
  pdaTokenType: types_1.TokenType.ATA,
3113
- maxActiveBinSlippage: 300,
3118
+ maxActiveBinSlippage: 0,
3114
3119
  shouldClaimFee: false,
3115
3120
  shouldClaimReward: false,
3116
3121
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -3856,7 +3861,7 @@ class Transactions {
3856
3861
  activeId,
3857
3862
  pdaTokenType,
3858
3863
  // RebalanceLiquidityParams
3859
- maxActiveBinSlippage: 300,
3864
+ maxActiveBinSlippage: 0,
3860
3865
  shouldClaimFee: false,
3861
3866
  shouldClaimReward: false,
3862
3867
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -5909,6 +5914,377 @@ class Transactions {
5909
5914
  });
5910
5915
  });
5911
5916
  }
5917
+ /**
5918
+ * Hybrid liquidity rebalance for automation: teardown old position and rebuild
5919
+ * with independent X/Y distributions per layer using rebalanceLiquidityAutomation.
5920
+ *
5921
+ * Scope: 70-bin positions only. No increasePositionLength needed.
5922
+ */
5923
+ meteoraRebalanceHybridLiquidityAutomation(_a) {
5924
+ return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
5925
+ var _b, _c;
5926
+ try {
5927
+ // --- Validate layers ---
5928
+ const layers = params.layers;
5929
+ if (layers.length === 0 || layers.length > 3) {
5930
+ throw new Error('layers must have 1-3 entries');
5931
+ }
5932
+ const sumX = layers.reduce((s, l) => s + l.x.percentage, 0);
5933
+ const sumY = layers.reduce((s, l) => s + l.y.percentage, 0);
5934
+ if (sumX !== 100 || sumY !== 100) {
5935
+ throw new Error(`Layer percentages must sum to 100 per side (got X=${sumX}, Y=${sumY})`);
5936
+ }
5937
+ const { lbPair, lbPairState, lowerBinId: currentLowerBinId, upperBinId: currentUpperBinId, estimatedTotalX, estimatedTotalY, activeId, withdrawFn, depositFn, } = yield this.resolvePositionContext({
5938
+ connection,
5939
+ userWallet: params.userWallet,
5940
+ position: params.currentPosition,
5941
+ compound: params.compound,
5942
+ targetActiveBin: params.targetActiveBin,
5943
+ });
5944
+ // checkRange validation
5945
+ if (activeId < params.checkRange.lowerRange || activeId > params.checkRange.upperRange) {
5946
+ throw new Error(`Active bin ${activeId} outside checkRange [${params.checkRange.lowerRange}, ${params.checkRange.upperRange}]`);
5947
+ }
5948
+ const newLowerBinId = activeId + params.relativeBinRange.lowerRange;
5949
+ const newUpperBinId = activeId + params.relativeBinRange.upperRange;
5950
+ const binStep = new bn_js_1.default(lbPairState.binStep);
5951
+ // --- Build TX1 (teardown) ---
5952
+ // Generate rebalance_liquidity instruction meant for withdrawing liquidity, fees, and rewards, and
5953
+ // shrinking position prior to closing
5954
+ const tx1Instructions = [
5955
+ // Withdraw + claim fees + claim rewards using rebalanceLiquidity
5956
+ ...yield withdrawFn({
5957
+ position: params.currentPosition,
5958
+ minBinId: currentLowerBinId,
5959
+ maxBinId: currentUpperBinId,
5960
+ compound: params.compound,
5961
+ origin: `meteoraRebalanceHybridLiquidityAutomation`
5962
+ }),
5963
+ // Close position
5964
+ {
5965
+ label: 'close_position',
5966
+ class: 'meteoraRebalanceHybridLiquidityAutomation',
5967
+ instruction: yield this.ix.meteoraDlmm.closePosition2Automation({
5968
+ connection,
5969
+ userWallet: params.userWallet,
5970
+ position: params.currentPosition,
5971
+ lbPair,
5972
+ })
5973
+ }
5974
+ ];
5975
+ // --- Build TX2+ (rebuild) ---
5976
+ const CLASS = 'meteoraRebalanceHybridLiquidityAutomation';
5977
+ const txInstructions = [tx1Instructions];
5978
+ // New position bin arrays
5979
+ const newWidth = newUpperBinId - newLowerBinId + 1;
5980
+ // TX2: initializePositionRelativeAutomation + first deposit batch
5981
+ const initIx = {
5982
+ label: 'initialize_position_relative',
5983
+ class: CLASS,
5984
+ instruction: yield this.ix.meteoraDlmm.initializePositionRelativeAutomation(connection, {
5985
+ userWallet: params.userWallet,
5986
+ lbPair,
5987
+ position: params.newPosition,
5988
+ relativeLowerBinId: params.relativeBinRange.lowerRange,
5989
+ width: newWidth,
5990
+ }),
5991
+ };
5992
+ // --- Build addLiquidityParams per layer ---
5993
+ const minDeltaId = newLowerBinId - activeId;
5994
+ const maxDeltaId = newUpperBinId - activeId;
5995
+ const effectiveAmountX = (_b = params.amountXOverride) !== null && _b !== void 0 ? _b : estimatedTotalX;
5996
+ const effectiveAmountY = (_c = params.amountYOverride) !== null && _c !== void 0 ? _c : estimatedTotalY;
5997
+ const favorXInActiveId = effectiveAmountY.isZero() && !effectiveAmountX.isZero();
5998
+ const strategyResults = (0, liquidityStrategy_1.distributionToHybridStrategy)({
5999
+ hybridDistribution: layers,
6000
+ amountX: effectiveAmountX,
6001
+ amountY: effectiveAmountY,
6002
+ minDeltaId: new bn_js_1.default(minDeltaId),
6003
+ maxDeltaId: new bn_js_1.default(maxDeltaId),
6004
+ binStep,
6005
+ activeId: new bn_js_1.default(activeId),
6006
+ });
6007
+ const allAddLiquidityParams = strategyResults.map(mergedParams => {
6008
+ const p = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(mergedParams.x0, mergedParams.y0, mergedParams.deltaX, mergedParams.deltaY);
6009
+ return {
6010
+ minDeltaId,
6011
+ maxDeltaId,
6012
+ x0: p.x0, y0: p.y0, deltaX: p.deltaX, deltaY: p.deltaY,
6013
+ bitFlag: p.bitFlag,
6014
+ favorXInActiveId,
6015
+ maxAmountX: mergedParams.maxAmountX,
6016
+ maxAmountY: mergedParams.maxAmountY,
6017
+ };
6018
+ });
6019
+ // One deposit IX per addLiquidityParams
6020
+ const depositIxs = [];
6021
+ for (const p of allAddLiquidityParams) {
6022
+ depositIxs.push(yield depositFn({
6023
+ position: params.newPosition,
6024
+ shouldClaimFee: false,
6025
+ shouldClaimReward: false,
6026
+ maxDepositXAmount: p.maxAmountX,
6027
+ maxDepositYAmount: p.maxAmountY,
6028
+ pdaTokenType: types_1.TokenType.ATA,
6029
+ addLiquidityParams: [{
6030
+ minDeltaId: p.minDeltaId,
6031
+ maxDeltaId: p.maxDeltaId,
6032
+ x0: p.x0, y0: p.y0, deltaX: p.deltaX, deltaY: p.deltaY,
6033
+ bitFlag: p.bitFlag,
6034
+ favorXInActiveId: p.favorXInActiveId,
6035
+ }],
6036
+ origin: CLASS,
6037
+ }));
6038
+ }
6039
+ // TX2: init + first deposit
6040
+ txInstructions.push([initIx, depositIxs[0]]);
6041
+ // TX3+: remaining deposit IXs
6042
+ for (let i = 1; i < depositIxs.length; i++) {
6043
+ txInstructions.push([depositIxs[i]]);
6044
+ }
6045
+ // --- Wrap in TransactionMetadataResponse2 ---
6046
+ const transactions = [];
6047
+ for (let i = 0; i < txInstructions.length; i++) {
6048
+ transactions.push(yield (0, functions_1.createTransactionMeta2)({
6049
+ payer: params.userWallet,
6050
+ addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
6051
+ mainInstructions: txInstructions[i],
6052
+ }));
6053
+ }
6054
+ return transactions;
6055
+ }
6056
+ catch (error) {
6057
+ console.error('=== REBALANCE HYBRID LIQUIDITY AUTOMATION ERROR ===');
6058
+ console.error('Error:', error instanceof Error ? error.message : String(error));
6059
+ console.error('Stack:', error instanceof Error ? error.stack : 'No stack trace');
6060
+ console.error('=== END ERROR LOG ===');
6061
+ throw error;
6062
+ }
6063
+ });
6064
+ }
6065
+ /**
6066
+ * Fetches a DLMM position's on-chain state and resolves all associated context
6067
+ * needed for downstream instructions: pool state, token mints/programs,
6068
+ * transfer hook remaining accounts, and reward hook remaining accounts.
6069
+ */
6070
+ resolvePositionContext(_a) {
6071
+ return __awaiter(this, arguments, void 0, function* ({ connection, userWallet, position, compound, targetActiveBin, }) {
6072
+ var _b, _c;
6073
+ // --- Fetch position + pool state ---
6074
+ const program = yield meteora_1.MeteoraDLMM.program(connection);
6075
+ const positionOnChain = yield program.account.positionV2.fetch(position);
6076
+ const lbPair = positionOnChain.lbPair;
6077
+ const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
6078
+ const userPda = (0, functions_1.generateUserPda)(userWallet);
6079
+ const lowerBinId = positionOnChain.lowerBinId;
6080
+ const upperBinId = positionOnChain.upperBinId;
6081
+ const lbPairState = dlmmPool.dlmm.lbPair;
6082
+ const tokenXMint = lbPairState.tokenXMint;
6083
+ const tokenYMint = lbPairState.tokenYMint;
6084
+ const activeId = targetActiveBin !== undefined ? targetActiveBin : lbPairState.activeId;
6085
+ // Position data. (techdebt, needs not to call this in the future)
6086
+ // AI note, just keep it. we'll work on this later.
6087
+ const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
6088
+ const userPosition = userPositions.find(p => p.publicKey.equals(position));
6089
+ if (userPosition === undefined) {
6090
+ throw new Error(`Unexpected error: Position (${position}) doesn't exist on-chain`);
6091
+ }
6092
+ const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
6093
+ const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
6094
+ const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
6095
+ const baseRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
6096
+ // --- Build combined remainingAccountsInfo with rewards ---
6097
+ const rewardInfos = [];
6098
+ const rewardInfosFromPair = lbPairState.rewardInfos;
6099
+ if (rewardInfosFromPair && rewardInfosFromPair.length > 0) {
6100
+ const activeRewardMints = [];
6101
+ for (const reward of rewardInfosFromPair) {
6102
+ if (!reward.mint.equals(web3.PublicKey.default)) {
6103
+ activeRewardMints.push(reward.mint);
6104
+ }
6105
+ }
6106
+ if (activeRewardMints.length > 0) {
6107
+ const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, activeRewardMints);
6108
+ for (let i = 0; i < rewardInfosFromPair.length; i++) {
6109
+ const reward = rewardInfosFromPair[i];
6110
+ if (!reward.mint.equals(web3.PublicKey.default)) {
6111
+ rewardInfos.push({
6112
+ rewardIndex: i,
6113
+ rewardVault: reward.vault,
6114
+ rewardMint: reward.mint,
6115
+ rewardTokenProgram: rewardTokenProgramMap[reward.mint.toString()],
6116
+ });
6117
+ }
6118
+ }
6119
+ }
6120
+ }
6121
+ const combinedSlices = [];
6122
+ const combinedAccounts = [];
6123
+ const xSlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookX);
6124
+ const ySlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookY);
6125
+ combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookX, length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0 });
6126
+ combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookY, length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0 });
6127
+ combinedAccounts.push(...baseRemainingAccountsInfo.accounts);
6128
+ for (const reward of rewardInfos) {
6129
+ const rewardTransferHookInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, reward.rewardMint, reward.rewardTokenProgram);
6130
+ const transferHookLength = rewardTransferHookInfo.slices.length > 0
6131
+ ? rewardTransferHookInfo.slices[0].length
6132
+ : 0;
6133
+ combinedSlices.push({
6134
+ accountsType: types_1.RemainingAccountsType.TransferHookMultiReward,
6135
+ length: transferHookLength,
6136
+ multiRewardIndex: reward.rewardIndex,
6137
+ });
6138
+ combinedAccounts.push(...rewardTransferHookInfo.accounts);
6139
+ }
6140
+ const remainingAccountsInfo = {
6141
+ slices: combinedSlices,
6142
+ accounts: combinedAccounts,
6143
+ };
6144
+ // --- Estimate total amounts ---
6145
+ const positionData = userPosition.positionData;
6146
+ const feeX = positionData.feeX;
6147
+ const feeY = positionData.feeY;
6148
+ const estimatedTotalX = compound
6149
+ ? new bn_js_1.default(positionData.totalXAmount).add(feeX)
6150
+ : new bn_js_1.default(positionData.totalXAmount);
6151
+ const estimatedTotalY = compound
6152
+ ? new bn_js_1.default(positionData.totalYAmount).add(feeY)
6153
+ : new bn_js_1.default(positionData.totalYAmount);
6154
+ const _rebalanceLiquidityAutomation = (_a) => __awaiter(this, [_a], void 0, function* ({ position, maxDepositXAmount, maxDepositYAmount, pdaTokenType, shrinkMode, shouldClaimFee, shouldClaimReward, removeLiquidityParams, addLiquidityParams, }) {
6155
+ return yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
6156
+ connection,
6157
+ userWallet: userWallet,
6158
+ position,
6159
+ lbPair,
6160
+ tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
6161
+ activeId,
6162
+ pdaTokenType,
6163
+ maxActiveBinSlippage: 0,
6164
+ shouldClaimFee,
6165
+ shouldClaimReward,
6166
+ minWithdrawXAmount: new bn_js_1.default(0),
6167
+ maxDepositXAmount,
6168
+ minWithdrawYAmount: new bn_js_1.default(0),
6169
+ maxDepositYAmount,
6170
+ removeLiquidityParams,
6171
+ addLiquidityParams,
6172
+ shrinkMode,
6173
+ rewardInfos,
6174
+ remainingAccountsInfo,
6175
+ });
6176
+ });
6177
+ const _withdrawFn = (_a) => __awaiter(this, [_a], void 0, function* ({ position, minBinId, maxBinId, shrinkMode, shouldClaimFee, shouldClaimReward, pdaTokenType, }) {
6178
+ return yield _rebalanceLiquidityAutomation({
6179
+ position,
6180
+ pdaTokenType,
6181
+ shouldClaimFee,
6182
+ shouldClaimReward,
6183
+ maxDepositXAmount: new bn_js_1.default(0),
6184
+ maxDepositYAmount: new bn_js_1.default(0),
6185
+ removeLiquidityParams: [{ minBinId, maxBinId, bps: 10000 }],
6186
+ addLiquidityParams: [],
6187
+ shrinkMode,
6188
+ });
6189
+ });
6190
+ const withdrawFn = (_a) => __awaiter(this, [_a], void 0, function* ({ position, minBinId, maxBinId, compound, origin, }) {
6191
+ if (compound) {
6192
+ // Withdraw + Claim Fee + Claim Reward
6193
+ return [
6194
+ {
6195
+ label: 'compound_withdraw_using_rbl',
6196
+ class: origin,
6197
+ instruction: yield _withdrawFn({
6198
+ position,
6199
+ minBinId,
6200
+ maxBinId,
6201
+ shouldClaimReward: true,
6202
+ shrinkMode: types_3.ShrinkMode.Default,
6203
+ shouldClaimFee: true,
6204
+ pdaTokenType: types_1.TokenType.ATA,
6205
+ })
6206
+ }
6207
+ ];
6208
+ }
6209
+ return [
6210
+ // Withdraw + claim reward from position
6211
+ {
6212
+ label: 'non_compound_withdraw_using_rbl',
6213
+ class: 'withdrawFn',
6214
+ instruction: yield _withdrawFn({
6215
+ position,
6216
+ minBinId,
6217
+ maxBinId,
6218
+ shouldClaimReward: true,
6219
+ shrinkMode: types_3.ShrinkMode.NoShrinkBoth,
6220
+ shouldClaimFee: false,
6221
+ // Note:
6222
+ // User Reward Token is not affected by this parameter. It's always STA regardless.
6223
+ // pdaTokenType only affects token deposits (which essentially are fees as well)
6224
+ pdaTokenType: types_1.TokenType.ATA,
6225
+ })
6226
+ },
6227
+ // Claim fees and shrink position
6228
+ {
6229
+ label: 'claim_fees_using_rbl',
6230
+ class: 'withdrawFn',
6231
+ instruction: yield _withdrawFn({
6232
+ position,
6233
+ minBinId,
6234
+ maxBinId,
6235
+ shouldClaimReward: false,
6236
+ // We shrink position at claim fees where we have zero deposits on given min ~ max binId
6237
+ // at this point
6238
+ shrinkMode: types_3.ShrinkMode.Default,
6239
+ shouldClaimFee: true,
6240
+ // Note (continuation):
6241
+ // That is why we split it to 2 ix, because we want fees to be transfered to STA if
6242
+ // compound is off
6243
+ pdaTokenType: types_1.TokenType.STA,
6244
+ })
6245
+ }
6246
+ ];
6247
+ });
6248
+ const depositFn = (_a) => __awaiter(this, [_a], void 0, function* ({ position, maxDepositXAmount, maxDepositYAmount, pdaTokenType, addLiquidityParams, origin, }) {
6249
+ return {
6250
+ label: 'deposit_using_rbl',
6251
+ class: origin,
6252
+ instruction: yield _rebalanceLiquidityAutomation({
6253
+ position,
6254
+ maxDepositXAmount,
6255
+ maxDepositYAmount,
6256
+ pdaTokenType,
6257
+ shrinkMode: types_3.ShrinkMode.NoShrinkBoth,
6258
+ shouldClaimFee: false,
6259
+ shouldClaimReward: false,
6260
+ removeLiquidityParams: [],
6261
+ addLiquidityParams,
6262
+ })
6263
+ };
6264
+ });
6265
+ return {
6266
+ program,
6267
+ lbPair,
6268
+ lbPairState,
6269
+ activeId,
6270
+ userPosition,
6271
+ dlmmPool,
6272
+ userPda,
6273
+ lowerBinId,
6274
+ upperBinId,
6275
+ tokenXMint,
6276
+ tokenYMint,
6277
+ tokenXProgram,
6278
+ tokenYProgram,
6279
+ remainingAccountsInfo,
6280
+ rewardInfos,
6281
+ estimatedTotalX,
6282
+ estimatedTotalY,
6283
+ withdrawFn,
6284
+ depositFn,
6285
+ };
6286
+ });
6287
+ }
5912
6288
  }
5913
6289
  exports.Transactions = Transactions;
5914
6290
  exports.txgen = Transactions.getInstance();