@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.
@@ -416,22 +416,41 @@ export class EkuboCLVault extends BaseStrategy<
416
416
  const tvlBefore = await this._getTVL(blockBefore);
417
417
  const supplyBefore = await this.totalSupply(blockBefore);
418
418
  const priceBefore = await this.getCurrentPrice(blockBefore);
419
-
420
- const tvlInToken0Now = (tvlNow.amount0
421
- .multipliedBy(priceNow.price))
422
- .plus(tvlNow.amount1);
423
- const tvlPerShareNow = tvlInToken0Now
419
+ const poolKey = await this.getPoolKey(blockBefore);
420
+ logger.verbose(`priceBefore: ${priceBefore.price.toString()}`);
421
+ logger.verbose(`priceNow: ${priceNow.price.toString()}`);
422
+ logger.verbose(`tvlBefore: ${JSON.stringify(tvlBefore)}`);
423
+ logger.verbose(`tvlNow: ${JSON.stringify(tvlNow)}`);
424
+
425
+ const isQuoteTokenToken0 = this.metadata.additionalInfo.quoteAsset.address.eq(poolKey.token0);
426
+ logger.verbose(`isQuoteTokenToken0: ${isQuoteTokenToken0}`);
427
+ let tvlBeforeInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
428
+ let tvlNowInBaseAsset = Web3Number.fromWei(0, this.metadata.additionalInfo.quoteAsset.decimals);
429
+ if (!isQuoteTokenToken0) {
430
+ tvlNowInBaseAsset = (tvlNow.amount0
431
+ .multipliedBy(priceNow.price))
432
+ .plus(tvlNow.amount1);
433
+ tvlBeforeInBaseAsset = (tvlBefore.amount0
434
+ .multipliedBy(priceBefore.price))
435
+ .plus(tvlBefore.amount1);
436
+ } else {
437
+ tvlNowInBaseAsset = (tvlNow.amount1
438
+ .multipliedBy(1 / priceNow.price))
439
+ .plus(tvlNow.amount0);
440
+ tvlBeforeInBaseAsset = (tvlBefore.amount1
441
+ .multipliedBy(1 / priceBefore.price))
442
+ .plus(tvlBefore.amount0);
443
+ }
444
+ const tvlPerShareNow = tvlNowInBaseAsset
424
445
  .multipliedBy(1e18)
425
446
  .dividedBy(adjustedSupplyNow.toString());
426
- const tvlInToken0Bf = (tvlBefore.amount0
427
- .multipliedBy(priceBefore.price))
428
- .plus(tvlBefore.amount1);
429
- const tvlPerShareBf = tvlInToken0Bf
447
+
448
+ const tvlPerShareBf = tvlBeforeInBaseAsset
430
449
  .multipliedBy(1e18)
431
450
  .dividedBy(supplyBefore.toString());
432
451
  const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
433
- logger.verbose(`tvlInToken0Now: ${tvlInToken0Now.toString()}`);
434
- logger.verbose(`tvlInToken0Bf: ${tvlInToken0Bf.toString()}`);
452
+ logger.verbose(`tvlNowInBaseAsset: ${tvlNowInBaseAsset.toString()}`);
453
+ logger.verbose(`tvlBeforeInBaseAsset: ${tvlBeforeInBaseAsset.toString()}`);
435
454
  logger.verbose(`tvlPerShareNow: ${tvlPerShareNow.toString()}`);
436
455
  logger.verbose(`tvlPerShareBf: ${tvlPerShareBf.toString()}`);
437
456
  logger.verbose(`Price before: ${priceBefore.price.toString()}`);
@@ -1578,11 +1597,20 @@ export class EkuboCLVault extends BaseStrategy<
1578
1597
  };
1579
1598
  }
1580
1599
 
1581
- async harvest(acc: Account, maxIterations = 20, priceRatioPrecision = 4): Promise<Call[]> {
1600
+ async harvest(acc: Account, maxIterations = 20, priceRatioPrecision = 4, minRewardAmount: Web3Number = new Web3Number(0, 18)): Promise<Call[]> {
1582
1601
  const ekuboHarvests = new EkuboHarvests(this.config);
1583
- const unClaimedRewards = await ekuboHarvests.getUnHarvestedRewards(
1602
+
1603
+ // get unclaimed rewards and filter out those less than the minimum reward amount
1604
+ const unClaimedRewards = (await ekuboHarvests.getUnHarvestedRewards(
1584
1605
  this.address
1585
- );
1606
+ )).filter(claim => claim.actualReward.greaterThanOrEqualTo(minRewardAmount));
1607
+
1608
+ if (unClaimedRewards.length == 0) {
1609
+ logger.verbose(`${EkuboCLVault.name}: harvest => no unclaimed rewards found`);
1610
+ return [];
1611
+ }
1612
+
1613
+ // get necessary info for the harvest
1586
1614
  const poolKey = await this.getPoolKey();
1587
1615
  const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
1588
1616
  const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
@@ -1590,8 +1618,14 @@ export class EkuboCLVault extends BaseStrategy<
1590
1618
  logger.verbose(
1591
1619
  `${EkuboCLVault.name}: harvest => unClaimedRewards: ${unClaimedRewards.length}`
1592
1620
  );
1621
+
1622
+ // execute the harvest
1593
1623
  const calls: Call[] = [];
1594
- for (let claim of unClaimedRewards) {
1624
+ // do one at a time.
1625
+ const chosenClaim = unClaimedRewards[0];
1626
+ logger.info(`${EkuboCLVault.name}: harvest => doing one at a time`);
1627
+ 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()}`);
1628
+ for (let claim of [chosenClaim]) {
1595
1629
  const fee = claim.claim.amount
1596
1630
  .multipliedBy(this.metadata.additionalInfo.feeBps)
1597
1631
  .dividedBy(10000);
@@ -1664,60 +1698,50 @@ export class EkuboCLVault extends BaseStrategy<
1664
1698
  logger.verbose(
1665
1699
  `${
1666
1700
  EkuboCLVault.name
1667
- }: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
1668
- );
1669
-
1670
- // THis function cannot handle swapping of non-STRK pool,
1671
- // bcz atleast one of token0Amt or token1Amt are in STRK terms.
1672
- const swapInfo = await this.getSwapInfoGivenAmounts(
1673
- poolKey,
1674
- token0Amt,
1675
- token1Amt,
1676
- bounds,
1677
- maxIterations,
1678
- priceRatioPrecision
1679
- );
1680
- swapInfo.token_to_address = token0Info.address.address;
1681
- logger.verbose(
1682
- `${EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
1701
+ }: harvest => token0Amt: ${token0Amt.toFixed(18)}, token1Amt: ${token1Amt.toFixed(18)}`
1683
1702
  );
1684
1703
 
1685
1704
  logger.verbose(
1686
1705
  `${EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
1687
1706
  );
1688
- const harvestEstimateCall = async (swapInfo1: SwapInfo) => {
1689
- const swap1Amount = Web3Number.fromWei(
1690
- uint256.uint256ToBN(swapInfo1.token_from_amount).toString(),
1691
- 18 // cause its always STRK?
1707
+ const claimTokenInfo = await Global.getTokenInfoFromAddr(claim.token);
1708
+ const harvestEstimateCall = async (baseSwapInfo: SwapInfo) => {
1709
+ // - the base swap if actual swap from claim token to non-claim token
1710
+ // - the other swap is just claim token to claim token (e.g. STRK to STRK)
1711
+ // which is just dummy
1712
+ let baseSwapAmount = Web3Number.fromWei(
1713
+ uint256.uint256ToBN(baseSwapInfo.token_from_amount).toString(),
1714
+ claimTokenInfo.decimals
1692
1715
  ).minimum(
1693
- postFeeAmount.toFixed(18) // cause always strk
1716
+ postFeeAmount.toFixed(claimTokenInfo.decimals)
1694
1717
  ); // ensure we don't swap more than we have
1695
- swapInfo.token_from_amount = uint256.bnToUint256(swap1Amount.toWei());
1696
- swapInfo.token_to_min_amount = uint256.bnToUint256(
1697
- swap1Amount.multipliedBy(0).toWei() // placeholder
1698
- ); // 0.01% slippage
1718
+ if (baseSwapAmount.lt(0.0001)) {
1719
+ baseSwapAmount = new Web3Number(0, claimTokenInfo.decimals);
1720
+ }
1721
+ baseSwapInfo.token_from_amount = uint256.bnToUint256(baseSwapAmount.toWei());
1699
1722
 
1723
+ const isToken0ClaimToken = claim.token.eq(poolKey.token0);
1700
1724
  logger.verbose(
1701
- `${EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
1725
+ `${EkuboCLVault.name}: harvest => isToken0ClaimToken: ${isToken0ClaimToken}, baseSwapAmount: ${baseSwapAmount}`
1702
1726
  );
1703
1727
 
1704
- const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
1728
+ const remainingAmount = postFeeAmount.minus(baseSwapAmount).maximum(0);
1705
1729
  logger.verbose(
1706
1730
  `${EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
1707
1731
  );
1708
- const swapInfo2 = {
1709
- ...swapInfo,
1710
- token_from_amount: uint256.bnToUint256(remainingAmount.toWei()),
1711
- };
1712
- swapInfo2.token_to_address = token1Info.address.address;
1732
+
1733
+ // obv, same to same
1734
+ let dummySwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, claim.token);
1735
+ dummySwapInfo.token_from_amount = uint256.bnToUint256(remainingAmount.toWei());
1736
+
1713
1737
  logger.verbose(
1714
- `${EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
1715
- swapInfo
1738
+ `${EkuboCLVault.name}: harvest => dummySwapInfo: ${JSON.stringify(
1739
+ dummySwapInfo
1716
1740
  )}`
1717
1741
  );
1718
1742
  logger.verbose(
1719
- `${EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
1720
- swapInfo2
1743
+ `${EkuboCLVault.name}: harvest => baseSwapInfo: ${JSON.stringify(
1744
+ baseSwapInfo
1721
1745
  )}`
1722
1746
  );
1723
1747
  const calldata = [
@@ -1728,18 +1752,41 @@ export class EkuboCLVault extends BaseStrategy<
1728
1752
  claimee: claim.claim.claimee.address,
1729
1753
  },
1730
1754
  claim.proof.map((p) => num.getDecimalString(p)),
1731
- swapInfo,
1732
- swapInfo2,
1755
+ isToken0ClaimToken ? dummySwapInfo : baseSwapInfo, // is token0 claim token, its just dummy swap
1756
+ isToken0ClaimToken ? baseSwapInfo : dummySwapInfo,
1733
1757
  ];
1734
- logger.verbose(
1735
- `${EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
1736
- calldata
1737
- )}`
1738
- );
1739
1758
  return [this.contract.populate("harvest", calldata)];
1740
1759
  };
1760
+
1761
+ // if token0 == claim token, then the base swapInfo is from claim token to token1
1762
+ // if token1 == claim token, then the base swapInfo is from claim token to token0
1763
+ const isToken0ClaimToken = claim.token.eq(poolKey.token0);
1764
+ let baseSwapInfo = AvnuWrapper.buildZeroSwap(claim.token, this.address.address, isToken0ClaimToken ? token1Info.address : token0Info.address);
1765
+ baseSwapInfo.token_from_amount = uint256.bnToUint256(postFeeAmount.toWei()); // we try to swap all to start with
1766
+
1767
+ // if token0 != claim token, then we swap from claim token to token0
1768
+ if (postFeeAmount.greaterThan(0) && !isToken0ClaimToken) {
1769
+ const avnuWrapper = new AvnuWrapper();
1770
+ const quote = await avnuWrapper.getQuotes(
1771
+ claim.token.address,
1772
+ token0Info.address.address,
1773
+ postFeeAmount.toWei(),
1774
+ this.address.address
1775
+ );
1776
+ baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
1777
+ } else if (postFeeAmount.greaterThan(0) && isToken0ClaimToken) {
1778
+ // if token0 == claim token, then we swap from claim token to token1
1779
+ const avnuWrapper = new AvnuWrapper();
1780
+ const quote = await avnuWrapper.getQuotes(
1781
+ claim.token.address,
1782
+ token1Info.address.address,
1783
+ postFeeAmount.toWei(),
1784
+ this.address.address
1785
+ );
1786
+ baseSwapInfo = await avnuWrapper.getSwapInfo(quote, this.address.address, 0, this.address.address);
1787
+ }
1741
1788
  const _callsFinal = await this.rebalanceIter(
1742
- swapInfo,
1789
+ baseSwapInfo,
1743
1790
  acc,
1744
1791
  harvestEstimateCall,
1745
1792
  claim.token.eq(poolKey.token0),
@@ -1809,39 +1856,47 @@ export class EkuboCLVault extends BaseStrategy<
1809
1856
  }) {
1810
1857
  const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
1811
1858
  let harvestCall: Call | null = null;
1859
+ logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => postFeeAmount: ${postFeeAmount.toString()}`);
1812
1860
 
1861
+ let attempt = 0;
1862
+ let MAX_ATTEMPTS = 50;
1813
1863
  const binarySearchCallbackFn = async (mid: bigint) => {
1864
+ attempt++;
1865
+ logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => mid: ${mid}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
1814
1866
  const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
1815
1867
  const avnuWrapper = new AvnuWrapper();
1816
1868
  const beneficiary = this.address.address;
1817
1869
 
1818
1870
  // get quote for 1st part
1819
- const quote1 = await avnuWrapper.getQuotes(
1871
+ const quote1Prom = avnuWrapper.getQuotes(
1820
1872
  claim.token.address,
1821
1873
  token0Info.address.address,
1822
1874
  mid.toString(),
1823
1875
  beneficiary
1824
1876
  );
1877
+ const quote2Prom = avnuWrapper.getQuotes(
1878
+ claim.token.address,
1879
+ token1Info.address.address,
1880
+ rewardPart2.toString(),
1881
+ beneficiary
1882
+ );
1883
+ const [quote1, quote2] = await Promise.all([quote1Prom, quote2Prom]);
1884
+
1825
1885
  // default min amount is ok
1826
1886
  const swapInfo1 = await avnuWrapper.getSwapInfo(
1827
1887
  quote1,
1828
1888
  beneficiary,
1829
- 0,
1889
+ 0, // fee bps
1830
1890
  beneficiary
1831
1891
  );
1832
1892
 
1833
1893
  // get quote for 2nd part
1834
- const quote2 = await avnuWrapper.getQuotes(
1835
- claim.token.address,
1836
- token1Info.address.address,
1837
- rewardPart2.toString(),
1838
- beneficiary
1839
- );
1894
+
1840
1895
  // default min amount is ok
1841
1896
  const swapInfo2 = await avnuWrapper.getSwapInfo(
1842
1897
  quote2,
1843
1898
  beneficiary,
1844
- 0,
1899
+ 0, // fee bps
1845
1900
  beneficiary
1846
1901
  );
1847
1902
 
@@ -1860,15 +1915,19 @@ export class EkuboCLVault extends BaseStrategy<
1860
1915
  ];
1861
1916
  harvestCall = this.contract.populate("harvest", calldata)
1862
1917
  const gas = await acc.estimateInvokeFee(harvestCall);
1918
+ logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => gas: ${gas.overall_fee.toString()}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
1863
1919
  return 'found';
1864
1920
  } catch (err: any) {
1865
1921
  if (err.message.includes('invalid token0 amount')) {
1922
+ logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token0 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
1866
1923
  // too much token0 amount left, may be swap less to token0
1867
1924
  return 'go_low';
1868
1925
  } else if (err.message.includes('invalid token1 amount')) {
1926
+ logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => invalid token1 amount, attempt: ${attempt}/${MAX_ATTEMPTS}`);
1869
1927
  // too much token1 balance left, may be swap more to token0
1870
1928
  return 'go_high';
1871
1929
  }
1930
+ logger.verbose(`${EkuboCLVault.name}: harvestMismatchEstimateCallFn => error: ${err.message}, attempt: ${attempt}/${MAX_ATTEMPTS}`);
1872
1931
  return 'retry';
1873
1932
  }
1874
1933
  }