@strkfarm/sdk 1.1.49 → 1.1.51

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.
@@ -53725,10 +53725,9 @@ ${JSON.stringify(data, null, 2)}`;
53725
53725
  }
53726
53726
 
53727
53727
  // src/modules/avnu.ts
53728
- var AvnuWrapper = class _AvnuWrapper {
53728
+ var AvnuWrapper = class {
53729
53729
  async getQuotes(fromToken, toToken, amountWei, taker, retry = 0, excludeSources = ["Haiko(Solvers)"]) {
53730
53730
  const MAX_RETRY = 5;
53731
- logger2.verbose(`${_AvnuWrapper.name}: getQuotes => Getting quotes for ${fromToken} -> ${toToken}, amount: ${amountWei}, taker: ${taker}, retry: ${retry}`);
53732
53731
  const params = {
53733
53732
  sellTokenAddress: fromToken,
53734
53733
  buyTokenAddress: toToken,
@@ -53771,9 +53770,6 @@ ${JSON.stringify(data, null, 2)}`;
53771
53770
  startIndex += 5 + swap_params_len;
53772
53771
  }
53773
53772
  const _minAmount = minAmount || (quote.buyAmount * 95n / 100n).toString();
53774
- logger2.verbose(`${_AvnuWrapper.name}: getSwapInfo => sellToken: ${quote.sellTokenAddress}, sellAmount: ${quote.sellAmount}`);
53775
- logger2.verbose(`${_AvnuWrapper.name}: getSwapInfo => buyToken: ${quote.buyTokenAddress}`);
53776
- logger2.verbose(`${_AvnuWrapper.name}: getSwapInfo => buyAmount: ${quote.buyAmount}, minAmount: ${_minAmount}`);
53777
53773
  const swapInfo = {
53778
53774
  token_from_address: quote.sellTokenAddress,
53779
53775
  token_from_amount: uint256_exports.bnToUint256(quote.sellAmount),
@@ -55736,20 +55732,26 @@ ${JSON.stringify(data, null, 2)}`;
55736
55732
  const rewards = await this.getHarvests(addr);
55737
55733
  if (rewards.length == 0) return [];
55738
55734
  const unClaimed = [];
55739
- const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
55740
- const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
55741
- const contract = new Contract({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
55742
- const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
55743
- logger2.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
55744
- if (isClaimed) {
55745
- return unClaimed;
55746
- }
55747
- const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
55748
- if (bal.lessThan(reward.claim.amount)) {
55749
- logger2.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
55750
- return unClaimed;
55751
- }
55752
- unClaimed.unshift(reward);
55735
+ const sortedRewards = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime());
55736
+ if (sortedRewards.length == 0) {
55737
+ logger2.verbose(`${_Harvests.name}: no rewards found`);
55738
+ return [];
55739
+ }
55740
+ const cls = await this.config.provider.getClassAt(sortedRewards[0].rewardsContract.address);
55741
+ for (const reward of sortedRewards) {
55742
+ const contract = new Contract({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
55743
+ const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
55744
+ logger2.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}, claim id: ${reward.claim.id}, address: ${reward.rewardsContract.address}`);
55745
+ if (isClaimed) {
55746
+ continue;
55747
+ }
55748
+ const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
55749
+ if (bal.lessThan(reward.claim.amount)) {
55750
+ logger2.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
55751
+ continue;
55752
+ }
55753
+ unClaimed.push(reward);
55754
+ }
55753
55755
  return unClaimed;
55754
55756
  }
55755
55757
  };
@@ -79681,13 +79683,27 @@ spurious results.`);
79681
79683
  const tvlBefore = await this._getTVL(blockBefore);
79682
79684
  const supplyBefore = await this.totalSupply(blockBefore);
79683
79685
  const priceBefore = await this.getCurrentPrice(blockBefore);
79684
- const tvlInToken0Now = tvlNow.amount0.multipliedBy(priceNow.price).plus(tvlNow.amount1);
79685
- const tvlPerShareNow = tvlInToken0Now.multipliedBy(1e18).dividedBy(adjustedSupplyNow.toString());
79686
- const tvlInToken0Bf = tvlBefore.amount0.multipliedBy(priceBefore.price).plus(tvlBefore.amount1);
79687
- const tvlPerShareBf = tvlInToken0Bf.multipliedBy(1e18).dividedBy(supplyBefore.toString());
79686
+ const poolKey = await this.getPoolKey(blockBefore);
79687
+ logger2.verbose(`priceBefore: ${priceBefore.price.toString()}`);
79688
+ logger2.verbose(`priceNow: ${priceNow.price.toString()}`);
79689
+ logger2.verbose(`tvlBefore: ${JSON.stringify(tvlBefore)}`);
79690
+ logger2.verbose(`tvlNow: ${JSON.stringify(tvlNow)}`);
79691
+ const isQuoteTokenToken0 = this.metadata.additionalInfo.quoteAsset.address.eq(poolKey.token0);
79692
+ logger2.verbose(`isQuoteTokenToken0: ${isQuoteTokenToken0}`);
79693
+ let tvlBeforeInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
79694
+ let tvlNowInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
79695
+ if (!isQuoteTokenToken0) {
79696
+ tvlNowInBaseAsset = tvlNow.amount0.multipliedBy(priceNow.price).plus(tvlNow.amount1);
79697
+ tvlBeforeInBaseAsset = tvlBefore.amount0.multipliedBy(priceBefore.price).plus(tvlBefore.amount1);
79698
+ } else {
79699
+ tvlNowInBaseAsset = tvlNow.amount1.multipliedBy(1 / priceNow.price).plus(tvlNow.amount0);
79700
+ tvlBeforeInBaseAsset = tvlBefore.amount1.multipliedBy(1 / priceBefore.price).plus(tvlBefore.amount0);
79701
+ }
79702
+ const tvlPerShareNow = tvlNowInBaseAsset.multipliedBy(1e18).dividedBy(adjustedSupplyNow.toString());
79703
+ const tvlPerShareBf = tvlBeforeInBaseAsset.multipliedBy(1e18).dividedBy(supplyBefore.toString());
79688
79704
  const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
79689
- logger2.verbose(`tvlInToken0Now: ${tvlInToken0Now.toString()}`);
79690
- logger2.verbose(`tvlInToken0Bf: ${tvlInToken0Bf.toString()}`);
79705
+ logger2.verbose(`tvlNowInBaseAsset: ${tvlNowInBaseAsset.toString()}`);
79706
+ logger2.verbose(`tvlBeforeInBaseAsset: ${tvlBeforeInBaseAsset.toString()}`);
79691
79707
  logger2.verbose(`tvlPerShareNow: ${tvlPerShareNow.toString()}`);
79692
79708
  logger2.verbose(`tvlPerShareBf: ${tvlPerShareBf.toString()}`);
79693
79709
  logger2.verbose(`Price before: ${priceBefore.price.toString()}`);
@@ -80549,11 +80565,15 @@ spurious results.`);
80549
80565
  amount1
80550
80566
  };
80551
80567
  }
80552
- async harvest(acc, maxIterations = 20, priceRatioPrecision = 4) {
80568
+ async harvest(acc, maxIterations = 20, priceRatioPrecision = 4, minRewardAmount = new Web3Number(0, 18)) {
80553
80569
  const ekuboHarvests = new EkuboHarvests(this.config);
80554
- const unClaimedRewards = await ekuboHarvests.getUnHarvestedRewards(
80570
+ const unClaimedRewards = (await ekuboHarvests.getUnHarvestedRewards(
80555
80571
  this.address
80556
- );
80572
+ )).filter((claim) => claim.actualReward.greaterThanOrEqualTo(minRewardAmount));
80573
+ if (unClaimedRewards.length == 0) {
80574
+ logger2.verbose(`${_EkuboCLVault.name}: harvest => no unclaimed rewards found`);
80575
+ return [];
80576
+ }
80557
80577
  const poolKey = await this.getPoolKey();
80558
80578
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
80559
80579
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
@@ -80562,7 +80582,10 @@ spurious results.`);
80562
80582
  `${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
80563
80583
  );
80564
80584
  const calls = [];
80565
- for (let claim of unClaimedRewards) {
80585
+ const chosenClaim = unClaimedRewards[0];
80586
+ logger2.info(`${_EkuboCLVault.name}: harvest => doing one at a time`);
80587
+ logger2.info(`${_EkuboCLVault.name}: harvest => chosenClaim -> Claim ID: ${chosenClaim.claim.id}, Amount: ${chosenClaim.claim.amount.toString()}, actualAmount: ${chosenClaim.actualReward.toString()}, addr: ${chosenClaim.claim.claimee.toString()}`);
80588
+ for (let claim of [chosenClaim]) {
80566
80589
  const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
80567
80590
  const postFeeAmount = claim.claim.amount.minus(fee);
80568
80591
  const isToken1 = claim.token.eq(poolKey.token1);
@@ -80611,57 +80634,41 @@ spurious results.`);
80611
80634
  const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
80612
80635
  const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
80613
80636
  logger2.verbose(
80614
- `${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
80615
- );
80616
- const swapInfo = await this.getSwapInfoGivenAmounts(
80617
- poolKey,
80618
- token0Amt,
80619
- token1Amt,
80620
- bounds,
80621
- maxIterations,
80622
- priceRatioPrecision
80623
- );
80624
- swapInfo.token_to_address = token0Info.address.address;
80625
- logger2.verbose(
80626
- `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
80637
+ `${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toFixed(18)}, token1Amt: ${token1Amt.toFixed(18)}`
80627
80638
  );
80628
80639
  logger2.verbose(
80629
80640
  `${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
80630
80641
  );
80631
- const harvestEstimateCall = async (swapInfo1) => {
80632
- const swap1Amount = Web3Number.fromWei(
80633
- uint256_exports.uint256ToBN(swapInfo1.token_from_amount).toString(),
80634
- 18
80635
- // cause its always STRK?
80642
+ const claimTokenInfo = await Global.getTokenInfoFromAddr(claim.token);
80643
+ const harvestEstimateCall = async (baseSwapInfo2) => {
80644
+ let baseSwapAmount = Web3Number.fromWei(
80645
+ uint256_exports.uint256ToBN(baseSwapInfo2.token_from_amount).toString(),
80646
+ claimTokenInfo.decimals
80636
80647
  ).minimum(
80637
- postFeeAmount.toFixed(18)
80638
- // cause always strk
80639
- );
80640
- swapInfo.token_from_amount = uint256_exports.bnToUint256(swap1Amount.toWei());
80641
- swapInfo.token_to_min_amount = uint256_exports.bnToUint256(
80642
- swap1Amount.multipliedBy(0).toWei()
80643
- // placeholder
80648
+ postFeeAmount.toFixed(claimTokenInfo.decimals)
80644
80649
  );
80650
+ if (baseSwapAmount.lt(1e-4)) {
80651
+ baseSwapAmount = new Web3Number(0, claimTokenInfo.decimals);
80652
+ }
80653
+ baseSwapInfo2.token_from_amount = uint256_exports.bnToUint256(baseSwapAmount.toWei());
80654
+ const isToken0ClaimToken2 = claim.token.eq(poolKey.token0);
80645
80655
  logger2.verbose(
80646
- `${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
80656
+ `${_EkuboCLVault.name}: harvest => isToken0ClaimToken: ${isToken0ClaimToken2}, baseSwapAmount: ${baseSwapAmount}`
80647
80657
  );
80648
- const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
80658
+ const remainingAmount = postFeeAmount.minus(baseSwapAmount).maximum(0);
80649
80659
  logger2.verbose(
80650
80660
  `${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
80651
80661
  );
80652
- const swapInfo2 = {
80653
- ...swapInfo,
80654
- token_from_amount: uint256_exports.bnToUint256(remainingAmount.toWei())
80655
- };
80656
- swapInfo2.token_to_address = token1Info.address.address;
80662
+ let dummySwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, claim.token);
80663
+ dummySwapInfo.token_from_amount = uint256_exports.bnToUint256(remainingAmount.toWei());
80657
80664
  logger2.verbose(
80658
- `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
80659
- swapInfo
80665
+ `${_EkuboCLVault.name}: harvest => dummySwapInfo: ${JSON.stringify(
80666
+ dummySwapInfo
80660
80667
  )}`
80661
80668
  );
80662
80669
  logger2.verbose(
80663
- `${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
80664
- swapInfo2
80670
+ `${_EkuboCLVault.name}: harvest => baseSwapInfo: ${JSON.stringify(
80671
+ baseSwapInfo2
80665
80672
  )}`
80666
80673
  );
80667
80674
  const calldata = [
@@ -80672,18 +80679,36 @@ spurious results.`);
80672
80679
  claimee: claim.claim.claimee.address
80673
80680
  },
80674
80681
  claim.proof.map((p) => num_exports.getDecimalString(p)),
80675
- swapInfo,
80676
- swapInfo2
80682
+ isToken0ClaimToken2 ? dummySwapInfo : baseSwapInfo2,
80683
+ // is token0 claim token, its just dummy swap
80684
+ isToken0ClaimToken2 ? baseSwapInfo2 : dummySwapInfo
80677
80685
  ];
80678
- logger2.verbose(
80679
- `${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
80680
- calldata
80681
- )}`
80682
- );
80683
80686
  return [this.contract.populate("harvest", calldata)];
80684
80687
  };
80688
+ const isToken0ClaimToken = claim.token.eq(poolKey.token0);
80689
+ let baseSwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, isToken0ClaimToken ? token1Info.address : token0Info.address);
80690
+ baseSwapInfo.token_from_amount = uint256_exports.bnToUint256(postFeeAmount.toWei());
80691
+ if (postFeeAmount.greaterThan(0) && !isToken0ClaimToken) {
80692
+ const avnuWrapper = new AvnuWrapper();
80693
+ const quote = await avnuWrapper.getQuotes(
80694
+ claim.token.address,
80695
+ token0Info.address.address,
80696
+ postFeeAmount.toWei(),
80697
+ this.address.address
80698
+ );
80699
+ baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
80700
+ } else if (postFeeAmount.greaterThan(0) && isToken0ClaimToken) {
80701
+ const avnuWrapper = new AvnuWrapper();
80702
+ const quote = await avnuWrapper.getQuotes(
80703
+ claim.token.address,
80704
+ token1Info.address.address,
80705
+ postFeeAmount.toWei(),
80706
+ this.address.address
80707
+ );
80708
+ baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
80709
+ }
80685
80710
  const _callsFinal = await this.rebalanceIter(
80686
- swapInfo,
80711
+ baseSwapInfo,
80687
80712
  acc,
80688
80713
  harvestEstimateCall,
80689
80714
  claim.token.eq(poolKey.token0),
@@ -80727,32 +80752,40 @@ spurious results.`);
80727
80752
  async harvestMismatchEstimateCallFn(params) {
80728
80753
  const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
80729
80754
  let harvestCall = null;
80755
+ logger2.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => postFeeAmount: ${postFeeAmount.toString()}`);
80756
+ let attempt = 0;
80757
+ let MAX_ATTEMPTS = 50;
80730
80758
  const binarySearchCallbackFn = async (mid) => {
80759
+ attempt++;
80760
+ logger2.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => mid: ${mid}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
80731
80761
  const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
80732
80762
  const avnuWrapper = new AvnuWrapper();
80733
80763
  const beneficiary = this.address.address;
80734
- const quote1 = await avnuWrapper.getQuotes(
80764
+ const quote1Prom = avnuWrapper.getQuotes(
80735
80765
  claim.token.address,
80736
80766
  token0Info.address.address,
80737
80767
  mid.toString(),
80738
80768
  beneficiary
80739
80769
  );
80770
+ const quote2Prom = avnuWrapper.getQuotes(
80771
+ claim.token.address,
80772
+ token1Info.address.address,
80773
+ rewardPart2.toString(),
80774
+ beneficiary
80775
+ );
80776
+ const [quote1, quote2] = await Promise.all([quote1Prom, quote2Prom]);
80740
80777
  const swapInfo1 = await avnuWrapper.getSwapInfo(
80741
80778
  quote1,
80742
80779
  beneficiary,
80743
80780
  0,
80744
- beneficiary
80745
- );
80746
- const quote2 = await avnuWrapper.getQuotes(
80747
- claim.token.address,
80748
- token1Info.address.address,
80749
- rewardPart2.toString(),
80781
+ // fee bps
80750
80782
  beneficiary
80751
80783
  );
80752
80784
  const swapInfo2 = await avnuWrapper.getSwapInfo(
80753
80785
  quote2,
80754
80786
  beneficiary,
80755
80787
  0,
80788
+ // fee bps
80756
80789
  beneficiary
80757
80790
  );
80758
80791
  try {
@@ -80769,13 +80802,17 @@ spurious results.`);
80769
80802
  ];
80770
80803
  harvestCall = this.contract.populate("harvest", calldata);
80771
80804
  const gas = await acc.estimateInvokeFee(harvestCall);
80805
+ logger2.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => gas: ${gas.overall_fee.toString()}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
80772
80806
  return "found";
80773
80807
  } catch (err2) {
80774
80808
  if (err2.message.includes("invalid token0 amount")) {
80809
+ logger2.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token0 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
80775
80810
  return "go_low";
80776
80811
  } else if (err2.message.includes("invalid token1 amount")) {
80812
+ logger2.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token1 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
80777
80813
  return "go_high";
80778
80814
  }
80815
+ logger2.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => error: ${err2.message}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
80779
80816
  return "retry";
80780
80817
  }
80781
80818
  };
@@ -2116,10 +2116,9 @@ function getTrovesEndpoint() {
2116
2116
  }
2117
2117
 
2118
2118
  // src/modules/avnu.ts
2119
- var AvnuWrapper = class _AvnuWrapper {
2119
+ var AvnuWrapper = class {
2120
2120
  async getQuotes(fromToken, toToken, amountWei, taker, retry = 0, excludeSources = ["Haiko(Solvers)"]) {
2121
2121
  const MAX_RETRY = 5;
2122
- logger.verbose(`${_AvnuWrapper.name}: getQuotes => Getting quotes for ${fromToken} -> ${toToken}, amount: ${amountWei}, taker: ${taker}, retry: ${retry}`);
2123
2122
  const params = {
2124
2123
  sellTokenAddress: fromToken,
2125
2124
  buyTokenAddress: toToken,
@@ -2162,9 +2161,6 @@ var AvnuWrapper = class _AvnuWrapper {
2162
2161
  startIndex += 5 + swap_params_len;
2163
2162
  }
2164
2163
  const _minAmount = minAmount || (quote.buyAmount * 95n / 100n).toString();
2165
- logger.verbose(`${_AvnuWrapper.name}: getSwapInfo => sellToken: ${quote.sellTokenAddress}, sellAmount: ${quote.sellAmount}`);
2166
- logger.verbose(`${_AvnuWrapper.name}: getSwapInfo => buyToken: ${quote.buyTokenAddress}`);
2167
- logger.verbose(`${_AvnuWrapper.name}: getSwapInfo => buyAmount: ${quote.buyAmount}, minAmount: ${_minAmount}`);
2168
2164
  const swapInfo = {
2169
2165
  token_from_address: quote.sellTokenAddress,
2170
2166
  token_from_amount: uint256.bnToUint256(quote.sellAmount),
@@ -4136,20 +4132,26 @@ var Harvests = class _Harvests {
4136
4132
  const rewards = await this.getHarvests(addr);
4137
4133
  if (rewards.length == 0) return [];
4138
4134
  const unClaimed = [];
4139
- const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
4140
- const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
4141
- const contract = new Contract4({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
4142
- const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
4143
- logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
4144
- if (isClaimed) {
4145
- return unClaimed;
4135
+ const sortedRewards = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime());
4136
+ if (sortedRewards.length == 0) {
4137
+ logger.verbose(`${_Harvests.name}: no rewards found`);
4138
+ return [];
4146
4139
  }
4147
- const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
4148
- if (bal.lessThan(reward.claim.amount)) {
4149
- logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
4150
- return unClaimed;
4140
+ const cls = await this.config.provider.getClassAt(sortedRewards[0].rewardsContract.address);
4141
+ for (const reward of sortedRewards) {
4142
+ const contract = new Contract4({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
4143
+ const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
4144
+ logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}, claim id: ${reward.claim.id}, address: ${reward.rewardsContract.address}`);
4145
+ if (isClaimed) {
4146
+ continue;
4147
+ }
4148
+ const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
4149
+ if (bal.lessThan(reward.claim.amount)) {
4150
+ logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
4151
+ continue;
4152
+ }
4153
+ unClaimed.push(reward);
4151
4154
  }
4152
- unClaimed.unshift(reward);
4153
4155
  return unClaimed;
4154
4156
  }
4155
4157
  };
@@ -15758,13 +15760,27 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
15758
15760
  const tvlBefore = await this._getTVL(blockBefore);
15759
15761
  const supplyBefore = await this.totalSupply(blockBefore);
15760
15762
  const priceBefore = await this.getCurrentPrice(blockBefore);
15761
- const tvlInToken0Now = tvlNow.amount0.multipliedBy(priceNow.price).plus(tvlNow.amount1);
15762
- const tvlPerShareNow = tvlInToken0Now.multipliedBy(1e18).dividedBy(adjustedSupplyNow.toString());
15763
- const tvlInToken0Bf = tvlBefore.amount0.multipliedBy(priceBefore.price).plus(tvlBefore.amount1);
15764
- const tvlPerShareBf = tvlInToken0Bf.multipliedBy(1e18).dividedBy(supplyBefore.toString());
15763
+ const poolKey = await this.getPoolKey(blockBefore);
15764
+ logger.verbose(`priceBefore: ${priceBefore.price.toString()}`);
15765
+ logger.verbose(`priceNow: ${priceNow.price.toString()}`);
15766
+ logger.verbose(`tvlBefore: ${JSON.stringify(tvlBefore)}`);
15767
+ logger.verbose(`tvlNow: ${JSON.stringify(tvlNow)}`);
15768
+ const isQuoteTokenToken0 = this.metadata.additionalInfo.quoteAsset.address.eq(poolKey.token0);
15769
+ logger.verbose(`isQuoteTokenToken0: ${isQuoteTokenToken0}`);
15770
+ let tvlBeforeInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
15771
+ let tvlNowInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
15772
+ if (!isQuoteTokenToken0) {
15773
+ tvlNowInBaseAsset = tvlNow.amount0.multipliedBy(priceNow.price).plus(tvlNow.amount1);
15774
+ tvlBeforeInBaseAsset = tvlBefore.amount0.multipliedBy(priceBefore.price).plus(tvlBefore.amount1);
15775
+ } else {
15776
+ tvlNowInBaseAsset = tvlNow.amount1.multipliedBy(1 / priceNow.price).plus(tvlNow.amount0);
15777
+ tvlBeforeInBaseAsset = tvlBefore.amount1.multipliedBy(1 / priceBefore.price).plus(tvlBefore.amount0);
15778
+ }
15779
+ const tvlPerShareNow = tvlNowInBaseAsset.multipliedBy(1e18).dividedBy(adjustedSupplyNow.toString());
15780
+ const tvlPerShareBf = tvlBeforeInBaseAsset.multipliedBy(1e18).dividedBy(supplyBefore.toString());
15765
15781
  const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
15766
- logger.verbose(`tvlInToken0Now: ${tvlInToken0Now.toString()}`);
15767
- logger.verbose(`tvlInToken0Bf: ${tvlInToken0Bf.toString()}`);
15782
+ logger.verbose(`tvlNowInBaseAsset: ${tvlNowInBaseAsset.toString()}`);
15783
+ logger.verbose(`tvlBeforeInBaseAsset: ${tvlBeforeInBaseAsset.toString()}`);
15768
15784
  logger.verbose(`tvlPerShareNow: ${tvlPerShareNow.toString()}`);
15769
15785
  logger.verbose(`tvlPerShareBf: ${tvlPerShareBf.toString()}`);
15770
15786
  logger.verbose(`Price before: ${priceBefore.price.toString()}`);
@@ -16626,11 +16642,15 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16626
16642
  amount1
16627
16643
  };
16628
16644
  }
16629
- async harvest(acc, maxIterations = 20, priceRatioPrecision = 4) {
16645
+ async harvest(acc, maxIterations = 20, priceRatioPrecision = 4, minRewardAmount = new Web3Number(0, 18)) {
16630
16646
  const ekuboHarvests = new EkuboHarvests(this.config);
16631
- const unClaimedRewards = await ekuboHarvests.getUnHarvestedRewards(
16647
+ const unClaimedRewards = (await ekuboHarvests.getUnHarvestedRewards(
16632
16648
  this.address
16633
- );
16649
+ )).filter((claim) => claim.actualReward.greaterThanOrEqualTo(minRewardAmount));
16650
+ if (unClaimedRewards.length == 0) {
16651
+ logger.verbose(`${_EkuboCLVault.name}: harvest => no unclaimed rewards found`);
16652
+ return [];
16653
+ }
16634
16654
  const poolKey = await this.getPoolKey();
16635
16655
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
16636
16656
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
@@ -16639,7 +16659,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16639
16659
  `${_EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
16640
16660
  );
16641
16661
  const calls = [];
16642
- for (let claim of unClaimedRewards) {
16662
+ const chosenClaim = unClaimedRewards[0];
16663
+ logger.info(`${_EkuboCLVault.name}: harvest => doing one at a time`);
16664
+ logger.info(`${_EkuboCLVault.name}: harvest => chosenClaim -> Claim ID: ${chosenClaim.claim.id}, Amount: ${chosenClaim.claim.amount.toString()}, actualAmount: ${chosenClaim.actualReward.toString()}, addr: ${chosenClaim.claim.claimee.toString()}`);
16665
+ for (let claim of [chosenClaim]) {
16643
16666
  const fee = claim.claim.amount.multipliedBy(this.metadata.additionalInfo.feeBps).dividedBy(1e4);
16644
16667
  const postFeeAmount = claim.claim.amount.minus(fee);
16645
16668
  const isToken1 = claim.token.eq(poolKey.token1);
@@ -16688,57 +16711,41 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16688
16711
  const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
16689
16712
  const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
16690
16713
  logger.verbose(
16691
- `${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
16692
- );
16693
- const swapInfo = await this.getSwapInfoGivenAmounts(
16694
- poolKey,
16695
- token0Amt,
16696
- token1Amt,
16697
- bounds,
16698
- maxIterations,
16699
- priceRatioPrecision
16700
- );
16701
- swapInfo.token_to_address = token0Info.address.address;
16702
- logger.verbose(
16703
- `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
16714
+ `${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toFixed(18)}, token1Amt: ${token1Amt.toFixed(18)}`
16704
16715
  );
16705
16716
  logger.verbose(
16706
16717
  `${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
16707
16718
  );
16708
- const harvestEstimateCall = async (swapInfo1) => {
16709
- const swap1Amount = Web3Number.fromWei(
16710
- uint2564.uint256ToBN(swapInfo1.token_from_amount).toString(),
16711
- 18
16712
- // cause its always STRK?
16719
+ const claimTokenInfo = await Global.getTokenInfoFromAddr(claim.token);
16720
+ const harvestEstimateCall = async (baseSwapInfo2) => {
16721
+ let baseSwapAmount = Web3Number.fromWei(
16722
+ uint2564.uint256ToBN(baseSwapInfo2.token_from_amount).toString(),
16723
+ claimTokenInfo.decimals
16713
16724
  ).minimum(
16714
- postFeeAmount.toFixed(18)
16715
- // cause always strk
16716
- );
16717
- swapInfo.token_from_amount = uint2564.bnToUint256(swap1Amount.toWei());
16718
- swapInfo.token_to_min_amount = uint2564.bnToUint256(
16719
- swap1Amount.multipliedBy(0).toWei()
16720
- // placeholder
16725
+ postFeeAmount.toFixed(claimTokenInfo.decimals)
16721
16726
  );
16727
+ if (baseSwapAmount.lt(1e-4)) {
16728
+ baseSwapAmount = new Web3Number(0, claimTokenInfo.decimals);
16729
+ }
16730
+ baseSwapInfo2.token_from_amount = uint2564.bnToUint256(baseSwapAmount.toWei());
16731
+ const isToken0ClaimToken2 = claim.token.eq(poolKey.token0);
16722
16732
  logger.verbose(
16723
- `${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
16733
+ `${_EkuboCLVault.name}: harvest => isToken0ClaimToken: ${isToken0ClaimToken2}, baseSwapAmount: ${baseSwapAmount}`
16724
16734
  );
16725
- const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
16735
+ const remainingAmount = postFeeAmount.minus(baseSwapAmount).maximum(0);
16726
16736
  logger.verbose(
16727
16737
  `${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
16728
16738
  );
16729
- const swapInfo2 = {
16730
- ...swapInfo,
16731
- token_from_amount: uint2564.bnToUint256(remainingAmount.toWei())
16732
- };
16733
- swapInfo2.token_to_address = token1Info.address.address;
16739
+ let dummySwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, claim.token);
16740
+ dummySwapInfo.token_from_amount = uint2564.bnToUint256(remainingAmount.toWei());
16734
16741
  logger.verbose(
16735
- `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
16736
- swapInfo
16742
+ `${_EkuboCLVault.name}: harvest => dummySwapInfo: ${JSON.stringify(
16743
+ dummySwapInfo
16737
16744
  )}`
16738
16745
  );
16739
16746
  logger.verbose(
16740
- `${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
16741
- swapInfo2
16747
+ `${_EkuboCLVault.name}: harvest => baseSwapInfo: ${JSON.stringify(
16748
+ baseSwapInfo2
16742
16749
  )}`
16743
16750
  );
16744
16751
  const calldata = [
@@ -16749,18 +16756,36 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16749
16756
  claimee: claim.claim.claimee.address
16750
16757
  },
16751
16758
  claim.proof.map((p) => num5.getDecimalString(p)),
16752
- swapInfo,
16753
- swapInfo2
16759
+ isToken0ClaimToken2 ? dummySwapInfo : baseSwapInfo2,
16760
+ // is token0 claim token, its just dummy swap
16761
+ isToken0ClaimToken2 ? baseSwapInfo2 : dummySwapInfo
16754
16762
  ];
16755
- logger.verbose(
16756
- `${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
16757
- calldata
16758
- )}`
16759
- );
16760
16763
  return [this.contract.populate("harvest", calldata)];
16761
16764
  };
16765
+ const isToken0ClaimToken = claim.token.eq(poolKey.token0);
16766
+ let baseSwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, isToken0ClaimToken ? token1Info.address : token0Info.address);
16767
+ baseSwapInfo.token_from_amount = uint2564.bnToUint256(postFeeAmount.toWei());
16768
+ if (postFeeAmount.greaterThan(0) && !isToken0ClaimToken) {
16769
+ const avnuWrapper = new AvnuWrapper();
16770
+ const quote = await avnuWrapper.getQuotes(
16771
+ claim.token.address,
16772
+ token0Info.address.address,
16773
+ postFeeAmount.toWei(),
16774
+ this.address.address
16775
+ );
16776
+ baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
16777
+ } else if (postFeeAmount.greaterThan(0) && isToken0ClaimToken) {
16778
+ const avnuWrapper = new AvnuWrapper();
16779
+ const quote = await avnuWrapper.getQuotes(
16780
+ claim.token.address,
16781
+ token1Info.address.address,
16782
+ postFeeAmount.toWei(),
16783
+ this.address.address
16784
+ );
16785
+ baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
16786
+ }
16762
16787
  const _callsFinal = await this.rebalanceIter(
16763
- swapInfo,
16788
+ baseSwapInfo,
16764
16789
  acc,
16765
16790
  harvestEstimateCall,
16766
16791
  claim.token.eq(poolKey.token0),
@@ -16804,32 +16829,40 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16804
16829
  async harvestMismatchEstimateCallFn(params) {
16805
16830
  const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
16806
16831
  let harvestCall = null;
16832
+ logger.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => postFeeAmount: ${postFeeAmount.toString()}`);
16833
+ let attempt = 0;
16834
+ let MAX_ATTEMPTS = 50;
16807
16835
  const binarySearchCallbackFn = async (mid) => {
16836
+ attempt++;
16837
+ logger.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => mid: ${mid}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
16808
16838
  const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
16809
16839
  const avnuWrapper = new AvnuWrapper();
16810
16840
  const beneficiary = this.address.address;
16811
- const quote1 = await avnuWrapper.getQuotes(
16841
+ const quote1Prom = avnuWrapper.getQuotes(
16812
16842
  claim.token.address,
16813
16843
  token0Info.address.address,
16814
16844
  mid.toString(),
16815
16845
  beneficiary
16816
16846
  );
16847
+ const quote2Prom = avnuWrapper.getQuotes(
16848
+ claim.token.address,
16849
+ token1Info.address.address,
16850
+ rewardPart2.toString(),
16851
+ beneficiary
16852
+ );
16853
+ const [quote1, quote2] = await Promise.all([quote1Prom, quote2Prom]);
16817
16854
  const swapInfo1 = await avnuWrapper.getSwapInfo(
16818
16855
  quote1,
16819
16856
  beneficiary,
16820
16857
  0,
16821
- beneficiary
16822
- );
16823
- const quote2 = await avnuWrapper.getQuotes(
16824
- claim.token.address,
16825
- token1Info.address.address,
16826
- rewardPart2.toString(),
16858
+ // fee bps
16827
16859
  beneficiary
16828
16860
  );
16829
16861
  const swapInfo2 = await avnuWrapper.getSwapInfo(
16830
16862
  quote2,
16831
16863
  beneficiary,
16832
16864
  0,
16865
+ // fee bps
16833
16866
  beneficiary
16834
16867
  );
16835
16868
  try {
@@ -16846,13 +16879,17 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16846
16879
  ];
16847
16880
  harvestCall = this.contract.populate("harvest", calldata);
16848
16881
  const gas = await acc.estimateInvokeFee(harvestCall);
16882
+ logger.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => gas: ${gas.overall_fee.toString()}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
16849
16883
  return "found";
16850
16884
  } catch (err) {
16851
16885
  if (err.message.includes("invalid token0 amount")) {
16886
+ logger.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token0 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
16852
16887
  return "go_low";
16853
16888
  } else if (err.message.includes("invalid token1 amount")) {
16889
+ logger.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token1 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
16854
16890
  return "go_high";
16855
16891
  }
16892
+ logger.verbose(`${_EkuboCLVault.name}: harvestMismatchEstimateCallFn => error: ${err.message}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
16856
16893
  return "retry";
16857
16894
  }
16858
16895
  };
package/dist/index.d.ts CHANGED
@@ -833,7 +833,7 @@ declare class EkuboCLVault extends BaseStrategy<DualTokenInfo, DualActionAmount>
833
833
  amount0: Web3Number;
834
834
  amount1: Web3Number;
835
835
  }>;
836
- harvest(acc: Account, maxIterations?: number, priceRatioPrecision?: number): Promise<Call[]>;
836
+ harvest(acc: Account, maxIterations?: number, priceRatioPrecision?: number, minRewardAmount?: Web3Number): Promise<Call[]>;
837
837
  /**
838
838
  * @description This funciton requires atleast one of the pool tokens to be reward token
839
839
  * i.e. STRK.
@@ -1696,6 +1696,7 @@ declare function executeDeployCalls(contractsInfo: DeployContractResult[], acc:
1696
1696
  declare function executeTransactions(calls: Call[], acc: Account, provider: RpcProvider, remarks?: string): Promise<{
1697
1697
  transaction_hash: string;
1698
1698
  }>;
1699
+ declare function myWaitForTransaction(transaction_hash: string, provider: RpcProvider, retry?: number): Promise<boolean>;
1699
1700
  declare const Deployer: {
1700
1701
  getAccount: typeof getAccount;
1701
1702
  myDeclare: typeof myDeclare;
@@ -1703,6 +1704,7 @@ declare const Deployer: {
1703
1704
  prepareMultiDeployContracts: typeof prepareMultiDeployContracts;
1704
1705
  executeDeployCalls: typeof executeDeployCalls;
1705
1706
  executeTransactions: typeof executeTransactions;
1707
+ myWaitForTransaction: typeof myWaitForTransaction;
1706
1708
  };
1707
1709
 
1708
1710
  /**