@hawksightco/hawk-sdk 1.3.219 → 1.3.221

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;
@@ -1616,7 +1620,6 @@ class Transactions {
1616
1620
  });
1617
1621
  }
1618
1622
  /**
1619
- * @deprecated Use rebalanceLargerPositionAutomation instead
1620
1623
  *
1621
1624
  * @param connection The Solana web3 connection object for blockchain interactions.
1622
1625
  * @param params Parameters required for rebalance
@@ -1681,7 +1684,6 @@ class Transactions {
1681
1684
  });
1682
1685
  }
1683
1686
  /**
1684
- * @deprecated Use rebalanceLargerPositionAutomation instaed
1685
1687
  *
1686
1688
  * @param connection The Solana web3 connection object for blockchain interactions.
1687
1689
  * @param params Parameters required for rebalance
@@ -1984,35 +1986,7 @@ class Transactions {
1984
1986
  }
1985
1987
  });
1986
1988
  }
1987
- /**
1988
- * Rebalance a Meteora DLMM position with support for larger positions.
1989
- *
1990
- * This is a backwards-compatible implementation of the rebalance operation that handles
1991
- * positions of any size. The method automatically splits operations into 2-dimensional
1992
- * instruction arrays (where each dimension represents a transaction) when dealing with
1993
- * large bin arrays that would exceed single transaction limits.
1994
- *
1995
- * This rebalance method performs the following steps:
1996
- * 1. Removes liquidity from the current position (supports larger bin ranges, not limited to 70-bin chunks, max 149-bin)
1997
- * 2. Claims fees from the current position
1998
- * 3. Claims rewards from the current position (if any)
1999
- * 4. Closes the current position
2000
- * 5. Initializes a new position
2001
- * 6. Extends the new position length if needed (for larger positions)
2002
- * 7. Adds liquidity to the new position using deposit automation
2003
- *
2004
- * Key benefits:
2005
- * - Backwards-compatible with existing rebalance implementations
2006
- * - Supports large bin arrays through automatic transaction splitting into multiple transactions
2007
- * - Does NOT depend on Meteora SDK
2008
- * - Handles positions that exceed single transaction size limits
2009
- * - Uses increasePositionLengthAutomation for larger new positions
2010
- *
2011
- * @param connection The Solana web3 connection object for blockchain interactions.
2012
- * @param params Parameters required for rebalance (same as MeteoraRebalance)
2013
- * @returns Array of TransactionMetadataResponse for each transaction
2014
- */
2015
- rebalanceLargerPositionAutomation(_a) {
1989
+ rebalanceSmallPositionAutomation(_a) {
2016
1990
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2017
1991
  // Current theoretical limit (149-bin)
2018
1992
  const MAX_POSITION_WIDTH = 149;
@@ -2268,6 +2242,7 @@ class Transactions {
2268
2242
  }
2269
2243
  redepositForLargePositionAutomationIx(_a) {
2270
2244
  return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2245
+ var _b;
2271
2246
  try {
2272
2247
  const program = yield meteora_1.MeteoraDLMM.program(connection);
2273
2248
  const positionData = yield program.account.positionV2.fetch(params.position);
@@ -2293,7 +2268,6 @@ class Transactions {
2293
2268
  const remainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2294
2269
  const transactions = [];
2295
2270
  const withdrawIxs = [];
2296
- const depositIxs = [];
2297
2271
  const removeLiquidityIx = yield this.ix.meteoraDlmm.removeLiquidityByRange2Automation({
2298
2272
  connection,
2299
2273
  userWallet: params.userWallet,
@@ -2311,9 +2285,20 @@ class Transactions {
2311
2285
  });
2312
2286
  withdrawIxs.push(removeLiquidityIx);
2313
2287
  const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2314
- const relativeLowerBin = currentLowerBinId - activeId;
2315
- const relativeUpperBin = currentUpperBinId - activeId;
2316
- 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({
2317
2302
  connection,
2318
2303
  userWallet: params.userWallet,
2319
2304
  lbPair,
@@ -2322,38 +2307,28 @@ class Transactions {
2322
2307
  tokenYMint,
2323
2308
  tokenXProgram,
2324
2309
  tokenYProgram,
2310
+ lowerBinId: currentLowerBinId,
2311
+ upperBinId: currentUpperBinId,
2312
+ strategyType,
2325
2313
  activeId,
2326
- relativeBinRange: {
2327
- lowerRange: relativeLowerBin,
2328
- upperRange: relativeUpperBin,
2329
- },
2330
- strategyType: types_3.StrategyTypeMap[params.distribution],
2331
- pdaTokenType: types_1.TokenType.ATA,
2332
- remainingAccountsInfo,
2333
- positionIsSigner: false,
2314
+ totalXAmount,
2315
+ totalYAmount,
2316
+ skipInitBinArrays: true,
2334
2317
  });
2335
- depositIxs.push(addLiquidityIx);
2336
- const positionWidth = currentUpperBinId - currentLowerBinId + 1;
2337
- if (positionWidth <= 70) {
2338
- transactions.push(yield (0, functions_1.createTransactionMeta)({
2339
- payer: params.userWallet,
2340
- description: 'Automation IX: Meteora Redeposit: Remove liquidity + add liquidity',
2341
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2342
- mainInstructions: [...withdrawIxs, ...depositIxs],
2343
- }));
2344
- }
2345
- else {
2346
- transactions.push(yield (0, functions_1.createTransactionMeta)({
2347
- payer: params.userWallet,
2348
- description: 'Automation IX: Meteora Redeposit TX1: Remove liquidity',
2349
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2350
- mainInstructions: withdrawIxs,
2351
- }));
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++) {
2352
2327
  transactions.push(yield (0, functions_1.createTransactionMeta)({
2353
2328
  payer: params.userWallet,
2354
- description: 'Automation IX: Meteora Redeposit TX2: Add liquidity',
2329
+ description: `Automation IX: Meteora Redeposit TX${i + 2}: Add liquidity`,
2355
2330
  addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2356
- mainInstructions: depositIxs,
2331
+ mainInstructions: depositIxArrays[i],
2357
2332
  }));
2358
2333
  }
2359
2334
  return transactions;
@@ -2367,10 +2342,213 @@ class Transactions {
2367
2342
  }
2368
2343
  });
2369
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
+ }
2370
2547
  /**
2371
2548
  * Rebalance a large Meteora DLMM position (up to 1400 bins) using automation instructions.
2372
2549
  *
2373
- * For ≤149 bins, delegates to rebalanceLargerPositionAutomation.
2550
+ * For ≤70 bins, delegates to rebalanceSmallerPositionAutomation.
2551
+ * For 71-149 bins, delegates to rebalancePhasedPositionAutomation.
2374
2552
  * For ≥150 bins, uses a chunked multi-TX approach:
2375
2553
  * Phase 1: Chunked withdraw from current position
2376
2554
  * Phase 2: Initialize new large position
@@ -2394,9 +2572,13 @@ class Transactions {
2394
2572
  const currentLowerBinId = positionData.lowerBinId;
2395
2573
  const currentUpperBinId = positionData.upperBinId;
2396
2574
  const currentBinCount = currentUpperBinId - currentLowerBinId + 1;
2397
- // 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)
2398
2580
  if (currentBinCount <= 149 && params.width <= 149) {
2399
- return this.rebalanceLargerPositionAutomation({ connection, params, fetch: undefined });
2581
+ return this.rebalancePhasedPositionAutomation({ connection, params, fetch: undefined });
2400
2582
  }
2401
2583
  // ≥150 bins: multi-TX chunked approach
2402
2584
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
@@ -2544,7 +2726,7 @@ class Transactions {
2544
2726
  tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2545
2727
  activeId: params.activeId,
2546
2728
  pdaTokenType: types_1.TokenType.ATA,
2547
- maxActiveBinSlippage: 300,
2729
+ maxActiveBinSlippage: 0,
2548
2730
  shouldClaimFee: false,
2549
2731
  shouldClaimReward: false,
2550
2732
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -2561,304 +2743,121 @@ class Transactions {
2561
2743
  });
2562
2744
  }
2563
2745
  /**
2564
- * @note DO NOT USE. STILL UNDER DEVELOPMENT. Tests still failing
2565
- * Reshape position: withdraw from old bins and deposit to new bins on the SAME position.
2566
- *
2567
- * Uses only rebalanceLiquidityAutomation (one IX per TX):
2568
- * Remove TXs: rebalanceLiquidityAutomation with removeLiquidityParams (~75 bins/TX)
2569
- * Deposit TXs: rebalanceLiquidityAutomation with addLiquidityParams (~75 bins/TX)
2570
- *
2571
- * Meteora's rebalance_liquidity handles position extension and bin array
2572
- * initialization internally — no separate IXs needed.
2573
- *
2574
- * Key differences from rebalanceLargePositionAutomation:
2575
- * - Same position (no close/create, no new position keypair needed)
2576
- * - 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
2577
2750
  */
2578
- meteoraRebalanceLargePositionAutomation2(_a) {
2579
- return __awaiter(this, arguments, void 0, function* ({ connection, params, }) {
2580
- var _b, _c, _d;
2581
- try {
2582
- const WITHDRAW_CHUNK_SIZE = 200;
2583
- const DEPOSIT_CHUNK_SIZE = 200;
2584
- const DEPOSIT_CHUNK_INITIAL_SIZE = 100;
2585
- // Always reserve a small portion of bins for the pivot TX to ensure
2586
- // withdraw + deposit happen together (prevents ReallocExceedMaxLengthPerInstruction)
2587
- const PIVOT_RESERVE = 160;
2588
- // Fetch pool data
2589
- const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, params.lbPair, this.ix);
2590
- const userPda = (0, functions_1.generateUserPda)(params.userWallet);
2591
- const { binId: activeId } = yield dlmmPool.dlmm.getActiveBin();
2592
- // Get position's token amounts for deposit strategy calculation
2593
- const { userPositions } = yield dlmmPool.getPositionsByUserAndLbPair(userPda);
2594
- const userPosition = userPositions.find(pos => pos.publicKey.equals(params.position));
2595
- if (!userPosition) {
2596
- throw new Error(`Position ${params.position.toString()} not found`);
2597
- }
2598
- const positionBinData = userPosition.positionData.positionBinData;
2599
- // Use actual liquidity range (bins with non-zero amounts) instead of padded position struct range
2600
- const binsWithLiquidity = positionBinData.filter(bin => !new bn_js_1.default(bin.positionXAmount).isZero() || !new bn_js_1.default(bin.positionYAmount).isZero());
2601
- const oldLowerBinId = binsWithLiquidity.length > 0
2602
- ? binsWithLiquidity[0].binId
2603
- : userPosition.positionData.lowerBinId;
2604
- const oldUpperBinId = binsWithLiquidity.length > 0
2605
- ? binsWithLiquidity[binsWithLiquidity.length - 1].binId
2606
- : userPosition.positionData.upperBinId;
2607
- const { totalXAmount, totalYAmount } = positionBinData.reduce((acc, bin) => ({
2608
- totalXAmount: acc.totalXAmount.add(new bn_js_1.default(bin.positionXAmount)),
2609
- totalYAmount: acc.totalYAmount.add(new bn_js_1.default(bin.positionYAmount)),
2610
- }), { totalXAmount: new bn_js_1.default(0), totalYAmount: new bn_js_1.default(0) });
2611
- const newLowerBinId = activeId + params.relativeLowerBin;
2612
- const newUpperBinId = newLowerBinId + params.width - 1;
2613
- console.log(`Total chunk per tx (withdraw): ${WITHDRAW_CHUNK_SIZE} bins, total chunk per tx (deposit): ${DEPOSIT_CHUNK_SIZE} bins`);
2614
- console.log(`old lower bin id: ${oldLowerBinId}, old upper bin id: ${oldUpperBinId}, old width: ${oldUpperBinId - oldLowerBinId + 1}`);
2615
- console.log(`new lower bin id: ${newLowerBinId}, new upper bin id: ${newUpperBinId}, new width: ${newUpperBinId - newLowerBinId + 1}`);
2616
- const lbPairState = dlmmPool.dlmm.lbPair;
2617
- const tokenXMint = lbPairState.tokenXMint;
2618
- const tokenYMint = lbPairState.tokenYMint;
2619
- const tokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, [tokenXMint, tokenYMint]);
2620
- const tokenXProgram = tokenProgramMap[tokenXMint.toString()];
2621
- const tokenYProgram = tokenProgramMap[tokenYMint.toString()];
2622
- // Fetch transfer hook accounts for token X and Y (Token2022 support)
2623
- const baseRemainingAccountsInfo = yield (0, functions_1.fetchRemainingAccountsInfo)(connection, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram);
2624
- // Extract reward infos for claiming rewards during rebalance
2625
- const rewardInfos = [];
2626
- const rewardInfosFromPair = lbPairState.rewardInfos;
2627
- if (rewardInfosFromPair && rewardInfosFromPair.length > 0) {
2628
- // Collect reward mints that are active (non-default)
2629
- const activeRewardMints = [];
2630
- for (const reward of rewardInfosFromPair) {
2631
- if (!reward.mint.equals(web3.PublicKey.default)) {
2632
- activeRewardMints.push(reward.mint);
2633
- }
2634
- }
2635
- // Get token programs for reward mints
2636
- if (activeRewardMints.length > 0) {
2637
- const rewardTokenProgramMap = yield (0, functions_1.getTokenProgramMapForMints)(connection, activeRewardMints);
2638
- for (let i = 0; i < rewardInfosFromPair.length; i++) {
2639
- const reward = rewardInfosFromPair[i];
2640
- if (!reward.mint.equals(web3.PublicKey.default)) {
2641
- rewardInfos.push({
2642
- rewardIndex: i,
2643
- rewardVault: reward.vault,
2644
- rewardMint: reward.mint,
2645
- rewardTokenProgram: rewardTokenProgramMap[reward.mint.toString()],
2646
- });
2647
- }
2648
- }
2649
- }
2650
- }
2651
- console.log(`[Pipeline] Found ${rewardInfos.length} active reward(s) for this pool`);
2652
- // Build combined remainingAccountsInfo with transfer hooks for X, Y, and rewards
2653
- // The slices describe: TransferHookX, TransferHookY, TransferHookMultiReward(index) for each reward
2654
- // IMPORTANT: Always include all slices, even with length=0, so Meteora knows the account structure
2655
- const combinedSlices = [];
2656
- const combinedAccounts = [];
2657
- // Always add TransferHookX and TransferHookY slices (even if length=0)
2658
- const xSlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookX);
2659
- const ySlice = baseRemainingAccountsInfo.slices.find(s => s.accountsType === types_1.RemainingAccountsType.TransferHookY);
2660
- combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookX, length: (_b = xSlice === null || xSlice === void 0 ? void 0 : xSlice.length) !== null && _b !== void 0 ? _b : 0 });
2661
- combinedSlices.push({ accountsType: types_1.RemainingAccountsType.TransferHookY, length: (_c = ySlice === null || ySlice === void 0 ? void 0 : ySlice.length) !== null && _c !== void 0 ? _c : 0 });
2662
- // Add transfer hook accounts from base (for X and Y)
2663
- combinedAccounts.push(...baseRemainingAccountsInfo.accounts);
2664
- // Fetch transfer hook accounts for each reward and add to combined info
2665
- // IMPORTANT: Always add TransferHookMultiReward slice for each reward, even if length=0
2666
- // This tells Meteora about the reward position in the remaining accounts
2667
- for (const reward of rewardInfos) {
2668
- const rewardTransferHookInfo = yield (0, functions_1.fetchRemainingAccountsInfoForReward)(connection, reward.rewardMint, reward.rewardTokenProgram);
2669
- // Always add TransferHookMultiReward slice (even if empty length for standard SPL tokens)
2670
- const transferHookLength = rewardTransferHookInfo.slices.length > 0
2671
- ? rewardTransferHookInfo.slices[0].length
2672
- : 0;
2673
- combinedSlices.push({
2674
- accountsType: types_1.RemainingAccountsType.TransferHookMultiReward,
2675
- length: transferHookLength,
2676
- multiRewardIndex: reward.rewardIndex,
2677
- });
2678
- combinedAccounts.push(...rewardTransferHookInfo.accounts);
2679
- }
2680
- const remainingAccountsInfo = {
2681
- slices: combinedSlices,
2682
- accounts: combinedAccounts,
2683
- };
2684
- const distributionToStrategyType = {
2685
- 'SPOT': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-IMBALANCED': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-ONE-SIDE': liquidityStrategy_1.StrategyType.SPOT, 'SPOT-BALANCED': liquidityStrategy_1.StrategyType.SPOT,
2686
- 'CURVE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-IMBALANCED': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-ONE-SIDE': liquidityStrategy_1.StrategyType.CURVE, 'CURVE-BALANCED': liquidityStrategy_1.StrategyType.CURVE,
2687
- '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,
2688
- };
2689
- const strategyType = (_d = distributionToStrategyType[params.distribution]) !== null && _d !== void 0 ? _d : liquidityStrategy_1.StrategyType.SPOT;
2690
- const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
2691
- // Build new-position deposit chunks
2692
- const minDeltaId = new bn_js_1.default(newLowerBinId - activeId);
2693
- const maxDeltaId = new bn_js_1.default(newUpperBinId - activeId);
2694
- const favorXInActiveId = totalYAmount.isZero() && !totalXAmount.isZero();
2695
- const strategyParams = (0, liquidityStrategy_1.buildStrategyParameters)(strategyType, totalXAmount, totalYAmount, minDeltaId, maxDeltaId, binStep, new bn_js_1.default(activeId), favorXInActiveId);
2696
- // =====================================================================
2697
- // Pipeline algorithm: pack withdraw + deposit work into fewer TXs.
2698
- //
2699
- // Given W old bins to withdraw and D new bins to deposit:
2700
- // Phase 1: Pure withdraw TXs — all withdraw chunks except the last
2701
- // Phase 2: Pivot TX — last withdraw chunk + extend + initBinArrays
2702
- // + first deposit (if small enough to fit without CU issues)
2703
- // Phase 3: Pure deposit TXs — remaining deposit bins by CHUNK_SIZE
2704
- //
2705
- // When the total extension is large or the deposit range spans many
2706
- // bin arrays, the transition IXs (extend + initBinArrays) are placed
2707
- // in a separate TX to avoid exceeding compute unit limits.
2708
- // =====================================================================
2709
- const txInstructions = [];
2710
- // Helper: build on-chain deposit param from a ChunkedDepositParameters
2711
- const buildDepositParam = (chunk) => {
2712
- const p = (0, liquidityStrategy_1.buildBitFlagAndNegateStrategyParameters)(chunk.params.x0, chunk.params.y0, chunk.params.deltaX, chunk.params.deltaY);
2713
- return {
2714
- minDeltaId: chunk.minDeltaId.toNumber(),
2715
- maxDeltaId: chunk.maxDeltaId.toNumber(),
2716
- x0: p.x0, y0: p.y0, deltaX: p.deltaX, deltaY: p.deltaY,
2717
- bitFlag: p.bitFlag, favorXInActiveId,
2718
- };
2719
- };
2720
- // Helper: build withdraw IX
2721
- const buildWithdrawIx = (lower, upper) => __awaiter(this, void 0, void 0, function* () {
2722
- const binArrayOverrides = this.ix.pda.meteora.deriveBinArrays(params.lbPair, lower, upper);
2723
- return this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2724
- connection,
2725
- userWallet: params.userWallet,
2726
- position: params.position,
2727
- lbPair: params.lbPair,
2728
- tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2729
- activeId,
2730
- pdaTokenType: types_1.TokenType.ATA,
2731
- maxActiveBinSlippage: 300,
2732
- shouldClaimFee: true,
2733
- shouldClaimReward: rewardInfos.length > 0,
2734
- minWithdrawXAmount: new bn_js_1.default(0),
2735
- maxDepositXAmount: new bn_js_1.default(0),
2736
- minWithdrawYAmount: new bn_js_1.default(0),
2737
- maxDepositYAmount: new bn_js_1.default(0),
2738
- removeLiquidityParams: [{ minBinId: lower, maxBinId: upper, bps: 10000 }],
2739
- addLiquidityParams: [],
2740
- binArrayOverrides,
2741
- shrinkMode: types_3.ShrinkMode.Default,
2742
- rewardInfos,
2743
- remainingAccountsInfo,
2744
- });
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),
2745
2786
  });
2746
- // Helper: build deposit IX from a deposit chunk
2747
- const buildDepositIx = (chunk, removeLiquidityParams) => __awaiter(this, void 0, void 0, function* () {
2748
- let trueMin = chunk.lowerBinId;
2749
- let trueMax = chunk.upperBinId;
2750
- if (removeLiquidityParams) {
2751
- trueMin = Math.min(chunk.lowerBinId, removeLiquidityParams.minBinId);
2752
- trueMax = Math.max(chunk.upperBinId, removeLiquidityParams.maxBinId);
2753
- }
2754
- const binArrayOverrides = this.ix.pda.meteora.deriveBinArrays(params.lbPair, trueMin, trueMax);
2755
- return yield this.ix.meteoraDlmm.rebalanceLiquidityAutomation({
2756
- connection,
2757
- userWallet: params.userWallet,
2758
- position: params.position,
2759
- lbPair: params.lbPair,
2760
- tokenXMint, tokenYMint, tokenXProgram, tokenYProgram,
2761
- activeId,
2762
- pdaTokenType: types_1.TokenType.ATA,
2763
- maxActiveBinSlippage: 300,
2764
- shouldClaimFee: removeLiquidityParams ? true : false,
2765
- shouldClaimReward: !!removeLiquidityParams && rewardInfos.length > 0,
2766
- minWithdrawXAmount: new bn_js_1.default(0),
2767
- maxDepositXAmount: chunk.maxAmountX,
2768
- minWithdrawYAmount: new bn_js_1.default(0),
2769
- maxDepositYAmount: chunk.maxAmountY,
2770
- removeLiquidityParams: removeLiquidityParams ? [{ minBinId: removeLiquidityParams.minBinId, maxBinId: removeLiquidityParams.maxBinId, bps: 10000 }] : [],
2771
- addLiquidityParams: [buildDepositParam(chunk)],
2772
- binArrayOverrides,
2773
- shrinkMode: removeLiquidityParams ? types_3.ShrinkMode.Default : types_3.ShrinkMode.NoShrinkBoth,
2774
- rewardInfos: removeLiquidityParams ? rewardInfos : undefined,
2775
- 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),
2776
2800
  });
2777
- });
2778
- // Build transition IXs: increasePositionLength + initBinArrays.
2779
- // Bin arrays must be pre-initialized before rebalanceLiquidity deposits.
2780
- const increasePositionLengthIxs = [];
2781
- // Generate increasePositionLength IXs to extend position (assumption at the moment, I expect calculation to be wrong)
2782
- let currentLower = newLowerBinId + WITHDRAW_CHUNK_SIZE;
2783
- while (currentLower < newUpperBinId) {
2784
- const currentWidth = newUpperBinId - currentLower + 1;
2785
- const binsToAdd = Math.min(91, currentWidth);
2786
- console.log('Increasing position length by', binsToAdd, 'bins at lower', currentLower);
2787
- increasePositionLengthIxs.push(yield this.ix.meteoraDlmm.increasePositionLengthAutomation({
2788
- connection,
2789
- userWallet: params.userWallet,
2790
- lbPair: params.lbPair,
2791
- position: params.position,
2792
- lengthToAdd: binsToAdd,
2793
- side: types_1.MeteoraPositionSide.Upper,
2794
- }));
2795
- currentLower = currentLower + binsToAdd;
2796
- }
2797
- // Build all deposit chunks upfront
2798
- const depositChunks = (0, liquidityStrategy_1.chunkDepositParametersWithInitialSize)(strategyParams, minDeltaId, maxDeltaId, new bn_js_1.default(activeId), binStep, DEPOSIT_CHUNK_INITIAL_SIZE, DEPOSIT_CHUNK_SIZE, favorXInActiveId);
2799
- // Build old-position withdraw chunks, reserving PIVOT_RESERVE bins for pivot TX
2800
- const oldWidth = oldUpperBinId - oldLowerBinId + 1;
2801
- const oldChunks = [];
2802
- let current = oldLowerBinId;
2803
- // Build Phase 1 withdraw chunks (before pivot)
2804
- while (current < oldUpperBinId) {
2805
- const upper = Math.min(WITHDRAW_CHUNK_SIZE - 1, oldUpperBinId - current) + current;
2806
- console.log(`Generating withdraw chunk: [${current}, ${upper}, ${upper - current + 1} bins]`);
2807
- oldChunks.push({ lower: current, upper });
2808
- current = upper + 1;
2801
+ offset += 48;
2809
2802
  }
2810
- const remainder = oldWidth % WITHDRAW_CHUNK_SIZE;
2811
- if (remainder === 0 || remainder > PIVOT_RESERVE) {
2812
- // Pop last chunk to reserve for pivot
2813
- const popped = oldChunks.pop();
2814
- // Then insert bigger and final chunk for pivot
2815
- const upper = popped.upper - PIVOT_RESERVE;
2816
- oldChunks.push({ lower: popped.lower, upper });
2817
- oldChunks.push({ lower: upper + 1, upper: popped.upper });
2818
- }
2819
- // =====================================================================
2820
- // Phase 1: Pure withdraw TXs — all chunks in oldChunks (before pivot)
2821
- // =====================================================================
2822
- for (const chunk of oldChunks) {
2823
- console.log(`Withdrawing from chunk: [${chunk.lower}, ${chunk.upper}]`);
2824
- txInstructions.push([yield buildWithdrawIx(chunk.lower, chunk.upper)]);
2825
- }
2826
- // Pop the last one
2827
- txInstructions.pop();
2828
- // Get the last withdraw chunk for pivot
2829
- const lastWithdrawChunk = oldChunks[oldChunks.length - 1];
2830
- // =====================================================================
2831
- // Phase 2 (Pivot TX): Withdraw pivot reserve + first deposit
2832
- // This ensures bins "jump" to new position, preventing ReallocExceedMaxLengthPerInstruction
2833
- // =====================================================================
2834
- txInstructions.push([
2835
- yield buildDepositIx(depositChunks[0], { minBinId: lastWithdrawChunk.lower, maxBinId: lastWithdrawChunk.upper }),
2836
- ...increasePositionLengthIxs,
2837
- ]);
2838
- // =====================================================================
2839
- // Phase 3: Remaining deposit TXs
2840
- // - Second deposit (i=1): includes increasePositionLengthIxs if needed
2841
- // - Subsequent deposits (i=2+): pure deposit
2842
- // =====================================================================
2843
- for (let i = 1; i < depositChunks.length; i++) {
2844
- const chunk = depositChunks[i];
2845
- 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
+ });
2846
2832
  }
2847
- // Wrap each instruction array with createTransactionMeta
2848
- const transactions = [];
2849
- for (let i = 0; i < txInstructions.length; i++) {
2850
- transactions.push(yield (0, functions_1.createTransactionMeta)({
2851
- payer: params.userWallet,
2852
- description: `Automation IX: Reshape position (tx ${i + 1}/${txInstructions.length})`,
2853
- addressLookupTableAddresses: addresses_1.GLOBAL_ALT,
2854
- mainInstructions: txInstructions[i],
2855
- }));
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
+ }
2856
2853
  }
2857
- return transactions;
2858
- }
2859
- catch (error) {
2860
- throw error;
2854
+ totalFeeX += feeX;
2855
+ totalFeeY += feeY;
2861
2856
  }
2857
+ return {
2858
+ feeX: new bn_js_1.default(totalFeeX.toString()),
2859
+ feeY: new bn_js_1.default(totalFeeY.toString()),
2860
+ };
2862
2861
  });
2863
2862
  }
2864
2863
  /**
@@ -2869,7 +2868,8 @@ class Transactions {
2869
2868
  _meteoraDepositToLargePositionAutomation(params) {
2870
2869
  return __awaiter(this, void 0, void 0, function* () {
2871
2870
  const MAX_BINS_PER_TX = 149;
2872
- const { connection, userWallet, lbPair, position, tokenXMint, tokenYMint, tokenXProgram, tokenYProgram, lowerBinId, upperBinId, strategyType, activeId, totalXAmount, totalYAmount, skipInitBinArrays, } = 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;
2873
2873
  const dlmmPool = yield meteora_1.MeteoraDLMM.create(connection, lbPair, this.ix);
2874
2874
  const binStep = new bn_js_1.default(dlmmPool.dlmm.lbPair.binStep);
2875
2875
  // Calculate delta IDs relative to active bin for entire position
@@ -2916,7 +2916,7 @@ class Transactions {
2916
2916
  tokenYProgram,
2917
2917
  activeId,
2918
2918
  pdaTokenType: types_1.TokenType.ATA,
2919
- maxActiveBinSlippage: 300,
2919
+ maxActiveBinSlippage,
2920
2920
  shouldClaimFee: false,
2921
2921
  shouldClaimReward: false,
2922
2922
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -3115,7 +3115,7 @@ class Transactions {
3115
3115
  tokenYProgram,
3116
3116
  activeId,
3117
3117
  pdaTokenType: types_1.TokenType.ATA,
3118
- maxActiveBinSlippage: 300,
3118
+ maxActiveBinSlippage: 0,
3119
3119
  shouldClaimFee: false,
3120
3120
  shouldClaimReward: false,
3121
3121
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -3861,7 +3861,7 @@ class Transactions {
3861
3861
  activeId,
3862
3862
  pdaTokenType,
3863
3863
  // RebalanceLiquidityParams
3864
- maxActiveBinSlippage: 300,
3864
+ maxActiveBinSlippage: 0,
3865
3865
  shouldClaimFee: false,
3866
3866
  shouldClaimReward: false,
3867
3867
  minWithdrawXAmount: new bn_js_1.default(0),
@@ -5914,6 +5914,377 @@ class Transactions {
5914
5914
  });
5915
5915
  });
5916
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
+ }
5917
6288
  }
5918
6289
  exports.Transactions = Transactions;
5919
6290
  exports.txgen = Transactions.getInstance();