@strkfarm/sdk 1.1.59 → 1.1.61

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.
@@ -80220,7 +80220,7 @@ spurious results.`);
80220
80220
  }
80221
80221
  };
80222
80222
  }
80223
- async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4) {
80223
+ async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
80224
80224
  const poolKey = await this.getPoolKey();
80225
80225
  const unusedBalances = await this.unusedBalances(poolKey);
80226
80226
  const { amount: token0Bal1, usdValue: token0PriceUsd } = unusedBalances.token0;
@@ -80260,7 +80260,8 @@ spurious results.`);
80260
80260
  token1Bal,
80261
80261
  ekuboBounds,
80262
80262
  maxIterations,
80263
- priceRatioPrecision
80263
+ priceRatioPrecision,
80264
+ getQuoteCallback
80264
80265
  );
80265
80266
  }
80266
80267
  assertValidBounds(bounds) {
@@ -80305,7 +80306,7 @@ spurious results.`);
80305
80306
  * @returns {Promise<SwapInfo>}
80306
80307
  *
80307
80308
  */
80308
- async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4) {
80309
+ async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
80309
80310
  logger2.verbose(
80310
80311
  `${_EkuboCLVault.name}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
80311
80312
  );
@@ -80340,12 +80341,7 @@ spurious results.`);
80340
80341
  if (amountToSell.eq(0)) {
80341
80342
  return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
80342
80343
  }
80343
- const quote = await this.avnu.getQuotes(
80344
- tokenToSell.address,
80345
- tokenToBuy.address,
80346
- amountToSell.toWei(),
80347
- this.address.address
80348
- );
80344
+ const quote = await getQuoteCallback(tokenToSell.address, tokenToBuy.address, amountToSell.toWei(), this.address.address);
80349
80345
  if (remainingSellAmount.eq(0)) {
80350
80346
  const minAmountOut = Web3Number.fromWei(
80351
80347
  quote.buyAmount.toString(),
@@ -80428,13 +80424,20 @@ spurious results.`);
80428
80424
  * @param retry - Current retry attempt number (default 0)
80429
80425
  * @param adjustmentFactor - Percentage to adjust swap amount by (default 1)
80430
80426
  * @param isToken0Deficit - Whether token0 balance needs increasing (default true)
80427
+ * @param MAX_RETRIES - Maximum number of retries (default 40)
80428
+ * @param sameErrorCount - For certain errors, we just retry with same amount again. This is the count of such retries (default { count: 0, error: null })
80429
+ * @param MAX_SAME_ERROR_COUNT - For certain errors, we just retry with same amount again. This limits such retries (default 10)
80431
80430
  * @returns Array of contract calls needed for rebalancing
80432
- * @throws Error if max retries reached without successful rebalance
80431
+ * @throws Error if max retries reached without successful rebalance or max same errors reached
80433
80432
  */
80434
- async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40) {
80433
+ async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40, sameErrorCount = { count: 0, error: null }, MAX_SAME_ERROR_COUNT = 10) {
80435
80434
  logger2.verbose(
80436
- `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}`
80435
+ `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}, MAX_RETRIES=${MAX_RETRIES}, sameErrorCount=${sameErrorCount.error} (${sameErrorCount.count})`
80437
80436
  );
80437
+ if (sameErrorCount.count >= MAX_SAME_ERROR_COUNT) {
80438
+ logger2.error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
80439
+ throw new Error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
80440
+ }
80438
80441
  const fromAmount = uint256_exports.uint256ToBN(swapInfo.token_from_amount);
80439
80442
  logger2.verbose(
80440
80443
  `Selling ${fromAmount.toString()} of token ${swapInfo.token_from_address}`
@@ -80453,7 +80456,7 @@ spurious results.`);
80453
80456
  );
80454
80457
  const newSwapInfo = { ...swapInfo };
80455
80458
  const currentAmount = Web3Number.fromWei(fromAmount.toString(), 18);
80456
- logger2.verbose(`Current amount: ${currentAmount.toString()}`);
80459
+ logger2.verbose(`Current amount: ${currentAmount.toString()}, lowerLimit: ${lowerLimit.toString()}, upperLimit: ${upperLimit.toString()}`);
80457
80460
  if (err2.message.includes("invalid token0 balance") || err2.message.includes("invalid token0 amount")) {
80458
80461
  if (!isSellTokenToken0) {
80459
80462
  logger2.verbose("Reducing swap amount - excess token0");
@@ -80500,6 +80503,30 @@ spurious results.`);
80500
80503
  }
80501
80504
  newSwapInfo.token_from_amount = uint256_exports.bnToUint256(nextAmount);
80502
80505
  }
80506
+ } else if (err2.message.includes("Residual tokens")) {
80507
+ logger2.error("Residual tokens");
80508
+ if (sameErrorCount.error == "Residual tokens") {
80509
+ sameErrorCount.count++;
80510
+ } else {
80511
+ sameErrorCount.error = "Residual tokens";
80512
+ sameErrorCount.count = 1;
80513
+ }
80514
+ } else if (err2.message.includes("Insufficient tokens received")) {
80515
+ logger2.error("Insufficient tokens received");
80516
+ if (sameErrorCount.error == "Insufficient tokens received") {
80517
+ sameErrorCount.count++;
80518
+ } else {
80519
+ sameErrorCount.error = "Insufficient tokens received";
80520
+ sameErrorCount.count = 1;
80521
+ }
80522
+ } else if (err2.message.includes("Could not reach the end of the program")) {
80523
+ logger2.error("Could not reach the end of the program, may be the block is full (could be a temp/permanent gas issue)");
80524
+ if (sameErrorCount.error == "Could not reach the end of the program") {
80525
+ sameErrorCount.count++;
80526
+ } else {
80527
+ sameErrorCount.error = "Could not reach the end of the program";
80528
+ sameErrorCount.count = 1;
80529
+ }
80503
80530
  } else {
80504
80531
  logger2.error("Unexpected error:", err2);
80505
80532
  throw err2;
@@ -80512,7 +80539,10 @@ spurious results.`);
80512
80539
  isSellTokenToken0,
80513
80540
  retry + 1,
80514
80541
  lowerLimit,
80515
- upperLimit
80542
+ upperLimit,
80543
+ MAX_RETRIES,
80544
+ sameErrorCount,
80545
+ MAX_SAME_ERROR_COUNT
80516
80546
  );
80517
80547
  }
80518
80548
  }
@@ -16297,7 +16297,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16297
16297
  }
16298
16298
  };
16299
16299
  }
16300
- async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4) {
16300
+ async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
16301
16301
  const poolKey = await this.getPoolKey();
16302
16302
  const unusedBalances = await this.unusedBalances(poolKey);
16303
16303
  const { amount: token0Bal1, usdValue: token0PriceUsd } = unusedBalances.token0;
@@ -16337,7 +16337,8 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16337
16337
  token1Bal,
16338
16338
  ekuboBounds,
16339
16339
  maxIterations,
16340
- priceRatioPrecision
16340
+ priceRatioPrecision,
16341
+ getQuoteCallback
16341
16342
  );
16342
16343
  }
16343
16344
  assertValidBounds(bounds) {
@@ -16382,7 +16383,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16382
16383
  * @returns {Promise<SwapInfo>}
16383
16384
  *
16384
16385
  */
16385
- async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4) {
16386
+ async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
16386
16387
  logger.verbose(
16387
16388
  `${_EkuboCLVault.name}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
16388
16389
  );
@@ -16417,12 +16418,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16417
16418
  if (amountToSell.eq(0)) {
16418
16419
  return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
16419
16420
  }
16420
- const quote = await this.avnu.getQuotes(
16421
- tokenToSell.address,
16422
- tokenToBuy.address,
16423
- amountToSell.toWei(),
16424
- this.address.address
16425
- );
16421
+ const quote = await getQuoteCallback(tokenToSell.address, tokenToBuy.address, amountToSell.toWei(), this.address.address);
16426
16422
  if (remainingSellAmount.eq(0)) {
16427
16423
  const minAmountOut = Web3Number.fromWei(
16428
16424
  quote.buyAmount.toString(),
@@ -16505,13 +16501,20 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16505
16501
  * @param retry - Current retry attempt number (default 0)
16506
16502
  * @param adjustmentFactor - Percentage to adjust swap amount by (default 1)
16507
16503
  * @param isToken0Deficit - Whether token0 balance needs increasing (default true)
16504
+ * @param MAX_RETRIES - Maximum number of retries (default 40)
16505
+ * @param sameErrorCount - For certain errors, we just retry with same amount again. This is the count of such retries (default { count: 0, error: null })
16506
+ * @param MAX_SAME_ERROR_COUNT - For certain errors, we just retry with same amount again. This limits such retries (default 10)
16508
16507
  * @returns Array of contract calls needed for rebalancing
16509
- * @throws Error if max retries reached without successful rebalance
16508
+ * @throws Error if max retries reached without successful rebalance or max same errors reached
16510
16509
  */
16511
- async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40) {
16510
+ async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40, sameErrorCount = { count: 0, error: null }, MAX_SAME_ERROR_COUNT = 10) {
16512
16511
  logger.verbose(
16513
- `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}`
16512
+ `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}, MAX_RETRIES=${MAX_RETRIES}, sameErrorCount=${sameErrorCount.error} (${sameErrorCount.count})`
16514
16513
  );
16514
+ if (sameErrorCount.count >= MAX_SAME_ERROR_COUNT) {
16515
+ logger.error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
16516
+ throw new Error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
16517
+ }
16515
16518
  const fromAmount = uint2564.uint256ToBN(swapInfo.token_from_amount);
16516
16519
  logger.verbose(
16517
16520
  `Selling ${fromAmount.toString()} of token ${swapInfo.token_from_address}`
@@ -16530,7 +16533,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16530
16533
  );
16531
16534
  const newSwapInfo = { ...swapInfo };
16532
16535
  const currentAmount = Web3Number.fromWei(fromAmount.toString(), 18);
16533
- logger.verbose(`Current amount: ${currentAmount.toString()}`);
16536
+ logger.verbose(`Current amount: ${currentAmount.toString()}, lowerLimit: ${lowerLimit.toString()}, upperLimit: ${upperLimit.toString()}`);
16534
16537
  if (err.message.includes("invalid token0 balance") || err.message.includes("invalid token0 amount")) {
16535
16538
  if (!isSellTokenToken0) {
16536
16539
  logger.verbose("Reducing swap amount - excess token0");
@@ -16577,6 +16580,30 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16577
16580
  }
16578
16581
  newSwapInfo.token_from_amount = uint2564.bnToUint256(nextAmount);
16579
16582
  }
16583
+ } else if (err.message.includes("Residual tokens")) {
16584
+ logger.error("Residual tokens");
16585
+ if (sameErrorCount.error == "Residual tokens") {
16586
+ sameErrorCount.count++;
16587
+ } else {
16588
+ sameErrorCount.error = "Residual tokens";
16589
+ sameErrorCount.count = 1;
16590
+ }
16591
+ } else if (err.message.includes("Insufficient tokens received")) {
16592
+ logger.error("Insufficient tokens received");
16593
+ if (sameErrorCount.error == "Insufficient tokens received") {
16594
+ sameErrorCount.count++;
16595
+ } else {
16596
+ sameErrorCount.error = "Insufficient tokens received";
16597
+ sameErrorCount.count = 1;
16598
+ }
16599
+ } else if (err.message.includes("Could not reach the end of the program")) {
16600
+ logger.error("Could not reach the end of the program, may be the block is full (could be a temp/permanent gas issue)");
16601
+ if (sameErrorCount.error == "Could not reach the end of the program") {
16602
+ sameErrorCount.count++;
16603
+ } else {
16604
+ sameErrorCount.error = "Could not reach the end of the program";
16605
+ sameErrorCount.count = 1;
16606
+ }
16580
16607
  } else {
16581
16608
  logger.error("Unexpected error:", err);
16582
16609
  throw err;
@@ -16589,7 +16616,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16589
16616
  isSellTokenToken0,
16590
16617
  retry + 1,
16591
16618
  lowerLimit,
16592
- upperLimit
16619
+ upperLimit,
16620
+ MAX_RETRIES,
16621
+ sameErrorCount,
16622
+ MAX_SAME_ERROR_COUNT
16593
16623
  );
16594
16624
  }
16595
16625
  }
package/dist/index.d.ts CHANGED
@@ -782,7 +782,7 @@ declare class EkuboCLVault extends BaseStrategy<DualTokenInfo, DualActionAmount>
782
782
  usdValue: number;
783
783
  };
784
784
  }>;
785
- getSwapInfoToHandleUnused(considerRebalance?: boolean, newBounds?: EkuboBounds | null, maxIterations?: number, priceRatioPrecision?: number): Promise<SwapInfo>;
785
+ getSwapInfoToHandleUnused(considerRebalance?: boolean, newBounds?: EkuboBounds | null, maxIterations?: number, priceRatioPrecision?: number, getQuoteCallback?: (tokenToSell: string, tokenToBuy: string, amountWei: string, beneficiary: string) => Promise<Quote>): Promise<SwapInfo>;
786
786
  assertValidBounds(bounds: EkuboBounds): void;
787
787
  assertValidAmounts(expectedAmounts: any, token0Bal: Web3Number, token1Bal: Web3Number): void;
788
788
  getSwapParams(expectedAmounts: any, poolKey: EkuboPoolKey, token0Bal: Web3Number, token1Bal: Web3Number): {
@@ -802,7 +802,7 @@ declare class EkuboCLVault extends BaseStrategy<DualTokenInfo, DualActionAmount>
802
802
  * @returns {Promise<SwapInfo>}
803
803
  *
804
804
  */
805
- getSwapInfoGivenAmounts(poolKey: EkuboPoolKey, token0Bal: Web3Number, token1Bal: Web3Number, bounds: EkuboBounds, maxIterations?: number, priceRatioPrecision?: number): Promise<SwapInfo>;
805
+ getSwapInfoGivenAmounts(poolKey: EkuboPoolKey, token0Bal: Web3Number, token1Bal: Web3Number, bounds: EkuboBounds, maxIterations?: number, priceRatioPrecision?: number, getQuoteCallback?: (tokenToSell: string, tokenToBuy: string, amountWei: string, beneficiary: string) => Promise<Quote>): Promise<SwapInfo>;
806
806
  /**
807
807
  * Attempts to rebalance the vault by iteratively adjusting swap amounts if initial attempt fails.
808
808
  * Uses binary search approach to find optimal swap amount.
@@ -813,10 +813,16 @@ declare class EkuboCLVault extends BaseStrategy<DualTokenInfo, DualActionAmount>
813
813
  * @param retry - Current retry attempt number (default 0)
814
814
  * @param adjustmentFactor - Percentage to adjust swap amount by (default 1)
815
815
  * @param isToken0Deficit - Whether token0 balance needs increasing (default true)
816
+ * @param MAX_RETRIES - Maximum number of retries (default 40)
817
+ * @param sameErrorCount - For certain errors, we just retry with same amount again. This is the count of such retries (default { count: 0, error: null })
818
+ * @param MAX_SAME_ERROR_COUNT - For certain errors, we just retry with same amount again. This limits such retries (default 10)
816
819
  * @returns Array of contract calls needed for rebalancing
817
- * @throws Error if max retries reached without successful rebalance
820
+ * @throws Error if max retries reached without successful rebalance or max same errors reached
818
821
  */
819
- rebalanceIter(swapInfo: SwapInfo, acc: Account, estimateCall: (swapInfo: SwapInfo) => Promise<Call[]>, isSellTokenToken0?: boolean, retry?: number, lowerLimit?: bigint, upperLimit?: bigint, MAX_RETRIES?: number): Promise<Call[]>;
822
+ rebalanceIter(swapInfo: SwapInfo, acc: Account, estimateCall: (swapInfo: SwapInfo) => Promise<Call[]>, isSellTokenToken0?: boolean, retry?: number, lowerLimit?: bigint, upperLimit?: bigint, MAX_RETRIES?: number, sameErrorCount?: {
823
+ count: number;
824
+ error: null | string;
825
+ }, MAX_SAME_ERROR_COUNT?: number): Promise<Call[]>;
820
826
  static tickToi129(tick: number): {
821
827
  mag: number;
822
828
  sign: number;
package/dist/index.js CHANGED
@@ -16297,7 +16297,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16297
16297
  }
16298
16298
  };
16299
16299
  }
16300
- async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4) {
16300
+ async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
16301
16301
  const poolKey = await this.getPoolKey();
16302
16302
  const unusedBalances = await this.unusedBalances(poolKey);
16303
16303
  const { amount: token0Bal1, usdValue: token0PriceUsd } = unusedBalances.token0;
@@ -16337,7 +16337,8 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16337
16337
  token1Bal,
16338
16338
  ekuboBounds,
16339
16339
  maxIterations,
16340
- priceRatioPrecision
16340
+ priceRatioPrecision,
16341
+ getQuoteCallback
16341
16342
  );
16342
16343
  }
16343
16344
  assertValidBounds(bounds) {
@@ -16382,7 +16383,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16382
16383
  * @returns {Promise<SwapInfo>}
16383
16384
  *
16384
16385
  */
16385
- async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4) {
16386
+ async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
16386
16387
  logger.verbose(
16387
16388
  `${_EkuboCLVault.name}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
16388
16389
  );
@@ -16417,12 +16418,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16417
16418
  if (amountToSell.eq(0)) {
16418
16419
  return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
16419
16420
  }
16420
- const quote = await this.avnu.getQuotes(
16421
- tokenToSell.address,
16422
- tokenToBuy.address,
16423
- amountToSell.toWei(),
16424
- this.address.address
16425
- );
16421
+ const quote = await getQuoteCallback(tokenToSell.address, tokenToBuy.address, amountToSell.toWei(), this.address.address);
16426
16422
  if (remainingSellAmount.eq(0)) {
16427
16423
  const minAmountOut = Web3Number.fromWei(
16428
16424
  quote.buyAmount.toString(),
@@ -16505,13 +16501,20 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16505
16501
  * @param retry - Current retry attempt number (default 0)
16506
16502
  * @param adjustmentFactor - Percentage to adjust swap amount by (default 1)
16507
16503
  * @param isToken0Deficit - Whether token0 balance needs increasing (default true)
16504
+ * @param MAX_RETRIES - Maximum number of retries (default 40)
16505
+ * @param sameErrorCount - For certain errors, we just retry with same amount again. This is the count of such retries (default { count: 0, error: null })
16506
+ * @param MAX_SAME_ERROR_COUNT - For certain errors, we just retry with same amount again. This limits such retries (default 10)
16508
16507
  * @returns Array of contract calls needed for rebalancing
16509
- * @throws Error if max retries reached without successful rebalance
16508
+ * @throws Error if max retries reached without successful rebalance or max same errors reached
16510
16509
  */
16511
- async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40) {
16510
+ async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40, sameErrorCount = { count: 0, error: null }, MAX_SAME_ERROR_COUNT = 10) {
16512
16511
  logger.verbose(
16513
- `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}`
16512
+ `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}, MAX_RETRIES=${MAX_RETRIES}, sameErrorCount=${sameErrorCount.error} (${sameErrorCount.count})`
16514
16513
  );
16514
+ if (sameErrorCount.count >= MAX_SAME_ERROR_COUNT) {
16515
+ logger.error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
16516
+ throw new Error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
16517
+ }
16515
16518
  const fromAmount = import_starknet11.uint256.uint256ToBN(swapInfo.token_from_amount);
16516
16519
  logger.verbose(
16517
16520
  `Selling ${fromAmount.toString()} of token ${swapInfo.token_from_address}`
@@ -16530,7 +16533,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16530
16533
  );
16531
16534
  const newSwapInfo = { ...swapInfo };
16532
16535
  const currentAmount = Web3Number.fromWei(fromAmount.toString(), 18);
16533
- logger.verbose(`Current amount: ${currentAmount.toString()}`);
16536
+ logger.verbose(`Current amount: ${currentAmount.toString()}, lowerLimit: ${lowerLimit.toString()}, upperLimit: ${upperLimit.toString()}`);
16534
16537
  if (err.message.includes("invalid token0 balance") || err.message.includes("invalid token0 amount")) {
16535
16538
  if (!isSellTokenToken0) {
16536
16539
  logger.verbose("Reducing swap amount - excess token0");
@@ -16577,6 +16580,30 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16577
16580
  }
16578
16581
  newSwapInfo.token_from_amount = import_starknet11.uint256.bnToUint256(nextAmount);
16579
16582
  }
16583
+ } else if (err.message.includes("Residual tokens")) {
16584
+ logger.error("Residual tokens");
16585
+ if (sameErrorCount.error == "Residual tokens") {
16586
+ sameErrorCount.count++;
16587
+ } else {
16588
+ sameErrorCount.error = "Residual tokens";
16589
+ sameErrorCount.count = 1;
16590
+ }
16591
+ } else if (err.message.includes("Insufficient tokens received")) {
16592
+ logger.error("Insufficient tokens received");
16593
+ if (sameErrorCount.error == "Insufficient tokens received") {
16594
+ sameErrorCount.count++;
16595
+ } else {
16596
+ sameErrorCount.error = "Insufficient tokens received";
16597
+ sameErrorCount.count = 1;
16598
+ }
16599
+ } else if (err.message.includes("Could not reach the end of the program")) {
16600
+ logger.error("Could not reach the end of the program, may be the block is full (could be a temp/permanent gas issue)");
16601
+ if (sameErrorCount.error == "Could not reach the end of the program") {
16602
+ sameErrorCount.count++;
16603
+ } else {
16604
+ sameErrorCount.error = "Could not reach the end of the program";
16605
+ sameErrorCount.count = 1;
16606
+ }
16580
16607
  } else {
16581
16608
  logger.error("Unexpected error:", err);
16582
16609
  throw err;
@@ -16589,7 +16616,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16589
16616
  isSellTokenToken0,
16590
16617
  retry + 1,
16591
16618
  lowerLimit,
16592
- upperLimit
16619
+ upperLimit,
16620
+ MAX_RETRIES,
16621
+ sameErrorCount,
16622
+ MAX_SAME_ERROR_COUNT
16593
16623
  );
16594
16624
  }
16595
16625
  }
package/dist/index.mjs CHANGED
@@ -16195,7 +16195,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16195
16195
  }
16196
16196
  };
16197
16197
  }
16198
- async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4) {
16198
+ async getSwapInfoToHandleUnused(considerRebalance = true, newBounds = null, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
16199
16199
  const poolKey = await this.getPoolKey();
16200
16200
  const unusedBalances = await this.unusedBalances(poolKey);
16201
16201
  const { amount: token0Bal1, usdValue: token0PriceUsd } = unusedBalances.token0;
@@ -16235,7 +16235,8 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16235
16235
  token1Bal,
16236
16236
  ekuboBounds,
16237
16237
  maxIterations,
16238
- priceRatioPrecision
16238
+ priceRatioPrecision,
16239
+ getQuoteCallback
16239
16240
  );
16240
16241
  }
16241
16242
  assertValidBounds(bounds) {
@@ -16280,7 +16281,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16280
16281
  * @returns {Promise<SwapInfo>}
16281
16282
  *
16282
16283
  */
16283
- async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4) {
16284
+ async getSwapInfoGivenAmounts(poolKey, token0Bal, token1Bal, bounds, maxIterations = 20, priceRatioPrecision = 4, getQuoteCallback = this.avnu.getQuotes) {
16284
16285
  logger.verbose(
16285
16286
  `${_EkuboCLVault.name}: getSwapInfoGivenAmounts::pre => token0Bal: ${token0Bal.toString()}, token1Bal: ${token1Bal.toString()}`
16286
16287
  );
@@ -16315,12 +16316,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16315
16316
  if (amountToSell.eq(0)) {
16316
16317
  return AvnuWrapper.buildZeroSwap(tokenToSell, this.address.address);
16317
16318
  }
16318
- const quote = await this.avnu.getQuotes(
16319
- tokenToSell.address,
16320
- tokenToBuy.address,
16321
- amountToSell.toWei(),
16322
- this.address.address
16323
- );
16319
+ const quote = await getQuoteCallback(tokenToSell.address, tokenToBuy.address, amountToSell.toWei(), this.address.address);
16324
16320
  if (remainingSellAmount.eq(0)) {
16325
16321
  const minAmountOut = Web3Number.fromWei(
16326
16322
  quote.buyAmount.toString(),
@@ -16403,13 +16399,20 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16403
16399
  * @param retry - Current retry attempt number (default 0)
16404
16400
  * @param adjustmentFactor - Percentage to adjust swap amount by (default 1)
16405
16401
  * @param isToken0Deficit - Whether token0 balance needs increasing (default true)
16402
+ * @param MAX_RETRIES - Maximum number of retries (default 40)
16403
+ * @param sameErrorCount - For certain errors, we just retry with same amount again. This is the count of such retries (default { count: 0, error: null })
16404
+ * @param MAX_SAME_ERROR_COUNT - For certain errors, we just retry with same amount again. This limits such retries (default 10)
16406
16405
  * @returns Array of contract calls needed for rebalancing
16407
- * @throws Error if max retries reached without successful rebalance
16406
+ * @throws Error if max retries reached without successful rebalance or max same errors reached
16408
16407
  */
16409
- async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40) {
16408
+ async rebalanceIter(swapInfo, acc, estimateCall, isSellTokenToken0 = true, retry = 0, lowerLimit = 0n, upperLimit = 0n, MAX_RETRIES = 40, sameErrorCount = { count: 0, error: null }, MAX_SAME_ERROR_COUNT = 10) {
16410
16409
  logger.verbose(
16411
- `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}`
16410
+ `Rebalancing ${this.metadata.name}: retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}, MAX_RETRIES=${MAX_RETRIES}, sameErrorCount=${sameErrorCount.error} (${sameErrorCount.count})`
16412
16411
  );
16412
+ if (sameErrorCount.count >= MAX_SAME_ERROR_COUNT) {
16413
+ logger.error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
16414
+ throw new Error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
16415
+ }
16413
16416
  const fromAmount = uint2564.uint256ToBN(swapInfo.token_from_amount);
16414
16417
  logger.verbose(
16415
16418
  `Selling ${fromAmount.toString()} of token ${swapInfo.token_from_address}`
@@ -16428,7 +16431,7 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16428
16431
  );
16429
16432
  const newSwapInfo = { ...swapInfo };
16430
16433
  const currentAmount = Web3Number.fromWei(fromAmount.toString(), 18);
16431
- logger.verbose(`Current amount: ${currentAmount.toString()}`);
16434
+ logger.verbose(`Current amount: ${currentAmount.toString()}, lowerLimit: ${lowerLimit.toString()}, upperLimit: ${upperLimit.toString()}`);
16432
16435
  if (err.message.includes("invalid token0 balance") || err.message.includes("invalid token0 amount")) {
16433
16436
  if (!isSellTokenToken0) {
16434
16437
  logger.verbose("Reducing swap amount - excess token0");
@@ -16475,6 +16478,30 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16475
16478
  }
16476
16479
  newSwapInfo.token_from_amount = uint2564.bnToUint256(nextAmount);
16477
16480
  }
16481
+ } else if (err.message.includes("Residual tokens")) {
16482
+ logger.error("Residual tokens");
16483
+ if (sameErrorCount.error == "Residual tokens") {
16484
+ sameErrorCount.count++;
16485
+ } else {
16486
+ sameErrorCount.error = "Residual tokens";
16487
+ sameErrorCount.count = 1;
16488
+ }
16489
+ } else if (err.message.includes("Insufficient tokens received")) {
16490
+ logger.error("Insufficient tokens received");
16491
+ if (sameErrorCount.error == "Insufficient tokens received") {
16492
+ sameErrorCount.count++;
16493
+ } else {
16494
+ sameErrorCount.error = "Insufficient tokens received";
16495
+ sameErrorCount.count = 1;
16496
+ }
16497
+ } else if (err.message.includes("Could not reach the end of the program")) {
16498
+ logger.error("Could not reach the end of the program, may be the block is full (could be a temp/permanent gas issue)");
16499
+ if (sameErrorCount.error == "Could not reach the end of the program") {
16500
+ sameErrorCount.count++;
16501
+ } else {
16502
+ sameErrorCount.error = "Could not reach the end of the program";
16503
+ sameErrorCount.count = 1;
16504
+ }
16478
16505
  } else {
16479
16506
  logger.error("Unexpected error:", err);
16480
16507
  throw err;
@@ -16487,7 +16514,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16487
16514
  isSellTokenToken0,
16488
16515
  retry + 1,
16489
16516
  lowerLimit,
16490
- upperLimit
16517
+ upperLimit,
16518
+ MAX_RETRIES,
16519
+ sameErrorCount,
16520
+ MAX_SAME_ERROR_COUNT
16491
16521
  );
16492
16522
  }
16493
16523
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strkfarm/sdk",
3
- "version": "1.1.59",
3
+ "version": "1.1.61",
4
4
  "description": "STRKFarm TS SDK (Meant for our internal use, but feel free to use it)",
5
5
  "typings": "dist/index.d.ts",
6
6
  "types": "dist/index.d.ts",
@@ -40,6 +40,7 @@ import { DepegRiskLevel, ImpermanentLossLevel, MarketRiskLevel, SmartContractRis
40
40
  import { gql } from "@apollo/client";
41
41
  import apolloClient from "@/modules/apollo-client";
42
42
  import { binarySearch } from "@/utils/math-utils";
43
+ import { Quote } from "@avnu/avnu-sdk";
43
44
 
44
45
  export interface EkuboPoolKey {
45
46
  token0: ContractAddr;
@@ -1080,7 +1081,12 @@ export class EkuboCLVault extends BaseStrategy<
1080
1081
  };
1081
1082
  }
1082
1083
 
1083
- async getSwapInfoToHandleUnused(considerRebalance: boolean = true, newBounds: EkuboBounds | null = null, maxIterations = 20, priceRatioPrecision = 4): Promise<SwapInfo> {
1084
+ async getSwapInfoToHandleUnused(
1085
+ considerRebalance: boolean = true,
1086
+ newBounds: EkuboBounds | null = null,
1087
+ maxIterations = 20, priceRatioPrecision = 4,
1088
+ getQuoteCallback: (tokenToSell: string, tokenToBuy: string, amountWei: string, beneficiary: string) => Promise<Quote> = this.avnu.getQuotes
1089
+ ): Promise<SwapInfo> {
1084
1090
  const poolKey = await this.getPoolKey();
1085
1091
 
1086
1092
  // fetch current unused balances of vault
@@ -1145,7 +1151,8 @@ export class EkuboCLVault extends BaseStrategy<
1145
1151
  token1Bal,
1146
1152
  ekuboBounds,
1147
1153
  maxIterations,
1148
- priceRatioPrecision
1154
+ priceRatioPrecision,
1155
+ getQuoteCallback
1149
1156
  );
1150
1157
  }
1151
1158
 
@@ -1229,7 +1236,8 @@ export class EkuboCLVault extends BaseStrategy<
1229
1236
  token1Bal: Web3Number,
1230
1237
  bounds: EkuboBounds,
1231
1238
  maxIterations: number = 20,
1232
- priceRatioPrecision: number = 4
1239
+ priceRatioPrecision: number = 4,
1240
+ getQuoteCallback: (tokenToSell: string, tokenToBuy: string, amountWei: string, beneficiary: string) => Promise<Quote> = this.avnu.getQuotes
1233
1241
  ): Promise<SwapInfo> {
1234
1242
  logger.verbose(
1235
1243
  `${
@@ -1284,12 +1292,7 @@ export class EkuboCLVault extends BaseStrategy<
1284
1292
  }
1285
1293
 
1286
1294
  // Get a quote for swapping the calculated amount
1287
- const quote = await this.avnu.getQuotes(
1288
- tokenToSell.address,
1289
- tokenToBuy.address,
1290
- amountToSell.toWei(),
1291
- this.address.address
1292
- );
1295
+ const quote = await getQuoteCallback(tokenToSell.address, tokenToBuy.address, amountToSell.toWei(), this.address.address);
1293
1296
 
1294
1297
  // If all of the token is to be swapped, return the swap info directly
1295
1298
  if (remainingSellAmount.eq(0)) {
@@ -1399,8 +1402,11 @@ export class EkuboCLVault extends BaseStrategy<
1399
1402
  * @param retry - Current retry attempt number (default 0)
1400
1403
  * @param adjustmentFactor - Percentage to adjust swap amount by (default 1)
1401
1404
  * @param isToken0Deficit - Whether token0 balance needs increasing (default true)
1405
+ * @param MAX_RETRIES - Maximum number of retries (default 40)
1406
+ * @param sameErrorCount - For certain errors, we just retry with same amount again. This is the count of such retries (default { count: 0, error: null })
1407
+ * @param MAX_SAME_ERROR_COUNT - For certain errors, we just retry with same amount again. This limits such retries (default 10)
1402
1408
  * @returns Array of contract calls needed for rebalancing
1403
- * @throws Error if max retries reached without successful rebalance
1409
+ * @throws Error if max retries reached without successful rebalance or max same errors reached
1404
1410
  */
1405
1411
  async rebalanceIter(
1406
1412
  swapInfo: SwapInfo,
@@ -1410,14 +1416,21 @@ export class EkuboCLVault extends BaseStrategy<
1410
1416
  retry = 0,
1411
1417
  lowerLimit = 0n,
1412
1418
  upperLimit = 0n,
1413
- MAX_RETRIES = 40
1419
+ MAX_RETRIES = 40,
1420
+ sameErrorCount: { count: number, error: null | string } = { count: 0, error: null },
1421
+ MAX_SAME_ERROR_COUNT = 10
1414
1422
  ): Promise<Call[]> {
1415
1423
 
1416
1424
  logger.verbose(
1417
1425
  `Rebalancing ${this.metadata.name}: ` +
1418
- `retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}`
1426
+ `retry=${retry}, lowerLimit=${lowerLimit}, upperLimit=${upperLimit}, isSellTokenToken0=${isSellTokenToken0}, MAX_RETRIES=${MAX_RETRIES}, sameErrorCount=${sameErrorCount.error} (${sameErrorCount.count})`
1419
1427
  );
1420
1428
 
1429
+ if (sameErrorCount.count >= MAX_SAME_ERROR_COUNT) {
1430
+ logger.error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
1431
+ throw new Error(`Rebalance failed after ${MAX_SAME_ERROR_COUNT} same errors`);
1432
+ }
1433
+
1421
1434
  const fromAmount = uint256.uint256ToBN(swapInfo.token_from_amount);
1422
1435
  logger.verbose(
1423
1436
  `Selling ${fromAmount.toString()} of token ${swapInfo.token_from_address}`
@@ -1439,7 +1452,7 @@ export class EkuboCLVault extends BaseStrategy<
1439
1452
 
1440
1453
  const newSwapInfo = { ...swapInfo };
1441
1454
  const currentAmount = Web3Number.fromWei(fromAmount.toString(), 18); // 18 is ok, as its toWei eventually anyways
1442
- logger.verbose(`Current amount: ${currentAmount.toString()}`);
1455
+ logger.verbose(`Current amount: ${currentAmount.toString()}, lowerLimit: ${lowerLimit.toString()}, upperLimit: ${upperLimit.toString()}`);
1443
1456
  if (
1444
1457
  err.message.includes("invalid token0 balance") ||
1445
1458
  err.message.includes("invalid token0 amount")
@@ -1492,6 +1505,33 @@ export class EkuboCLVault extends BaseStrategy<
1492
1505
  }
1493
1506
  newSwapInfo.token_from_amount = uint256.bnToUint256(nextAmount);
1494
1507
  }
1508
+ } else if (err.message.includes("Residual tokens")) {
1509
+ logger.error("Residual tokens");
1510
+ if (sameErrorCount.error == "Residual tokens") {
1511
+ sameErrorCount.count++;
1512
+ } else {
1513
+ sameErrorCount.error = "Residual tokens";
1514
+ sameErrorCount.count = 1;
1515
+ }
1516
+ // dont do anything, just try again.
1517
+ } else if (err.message.includes("Insufficient tokens received")) {
1518
+ logger.error("Insufficient tokens received");
1519
+ if (sameErrorCount.error == "Insufficient tokens received") {
1520
+ sameErrorCount.count++;
1521
+ } else {
1522
+ sameErrorCount.error = "Insufficient tokens received";
1523
+ sameErrorCount.count = 1;
1524
+ }
1525
+ // dont do anything, just try again.
1526
+ } else if (err.message.includes("Could not reach the end of the program")) {
1527
+ logger.error("Could not reach the end of the program, may be the block is full (could be a temp/permanent gas issue)");
1528
+ if (sameErrorCount.error == "Could not reach the end of the program") {
1529
+ sameErrorCount.count++;
1530
+ } else {
1531
+ sameErrorCount.error = "Could not reach the end of the program";
1532
+ sameErrorCount.count = 1;
1533
+ }
1534
+ // just try again.
1495
1535
  } else {
1496
1536
  logger.error("Unexpected error:", err);
1497
1537
  throw err;
@@ -1504,7 +1544,10 @@ export class EkuboCLVault extends BaseStrategy<
1504
1544
  isSellTokenToken0,
1505
1545
  retry + 1,
1506
1546
  lowerLimit,
1507
- upperLimit
1547
+ upperLimit,
1548
+ MAX_RETRIES,
1549
+ sameErrorCount,
1550
+ MAX_SAME_ERROR_COUNT
1508
1551
  );
1509
1552
  }
1510
1553
  }