@strkfarm/sdk 1.1.38 → 1.1.40

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.
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ APYType: () => APYType,
33
34
  AUMTypes: () => AUMTypes,
34
35
  AVNU_EXCHANGE: () => AVNU_EXCHANGE,
35
36
  AVNU_MIDDLEWARE: () => AVNU_MIDDLEWARE,
@@ -420,6 +421,25 @@ var defaultTokens = [{
420
421
  priceProxySymbol: "WBTC",
421
422
  priceCheckAmount: 1e-4
422
423
  // 112000 * 0.0001 = $11.2
424
+ }, {
425
+ name: "mRe7BTC",
426
+ symbol: "mRe7BTC",
427
+ logo: "https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/3a62ecee-1e58-45d3-9862-3ce90dff1900/logo",
428
+ address: ContractAddr.from("0x4e4fb1a9ca7e84bae609b9dc0078ad7719e49187ae7e425bb47d131710eddac"),
429
+ decimals: 18,
430
+ coingeckId: void 0,
431
+ displayDecimals: 6,
432
+ priceCheckAmount: 1e-4
433
+ // 112000 * 0.0001 = $11.2
434
+ }, {
435
+ name: "mRe7YIELD",
436
+ symbol: "mRe7YIELD",
437
+ logo: "https://midas.app/assets/mre7-BcOOHm7i.svg",
438
+ address: ContractAddr.from("0x4be8945e61dc3e19ebadd1579a6bd53b262f51ba89e6f8b0c4bc9a7e3c633fc"),
439
+ decimals: 18,
440
+ coingeckId: void 0,
441
+ displayDecimals: 2,
442
+ priceCheckAmount: 100
423
443
  }];
424
444
  var tokens = defaultTokens;
425
445
  var _Global = class _Global {
@@ -2313,16 +2333,16 @@ var AvnuWrapper = class _AvnuWrapper {
2313
2333
  };
2314
2334
  return swapInfo;
2315
2335
  }
2316
- static buildZeroSwap(tokenToSell, address) {
2336
+ static buildZeroSwap(tokenToSell, beneficiary, tokenToBuy = tokenToSell) {
2317
2337
  return {
2318
2338
  token_from_address: tokenToSell.address,
2319
2339
  token_from_amount: import_starknet6.uint256.bnToUint256(0),
2320
- token_to_address: tokenToSell.address,
2340
+ token_to_address: tokenToBuy.address,
2321
2341
  token_to_amount: import_starknet6.uint256.bnToUint256(0),
2322
2342
  token_to_min_amount: import_starknet6.uint256.bnToUint256(0),
2323
- beneficiary: address,
2343
+ beneficiary,
2324
2344
  integrator_fee_amount_bps: 0,
2325
- integrator_fee_recipient: address,
2345
+ integrator_fee_recipient: beneficiary,
2326
2346
  routes: []
2327
2347
  };
2328
2348
  }
@@ -4123,21 +4143,20 @@ var Harvests = class _Harvests {
4123
4143
  const rewards = await this.getHarvests(addr);
4124
4144
  if (rewards.length == 0) return [];
4125
4145
  const unClaimed = [];
4126
- const cls = await this.config.provider.getClassAt(rewards[0].rewardsContract.address);
4127
- for (let reward of rewards) {
4128
- const contract = new import_starknet9.Contract({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
4129
- const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
4130
- logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
4131
- if (isClaimed) {
4132
- return unClaimed;
4133
- }
4134
- const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
4135
- if (bal.lessThan(reward.claim.amount)) {
4136
- logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
4137
- continue;
4138
- }
4139
- unClaimed.unshift(reward);
4146
+ const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
4147
+ const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
4148
+ const contract = new import_starknet9.Contract({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
4149
+ const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
4150
+ logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
4151
+ if (isClaimed) {
4152
+ return unClaimed;
4140
4153
  }
4154
+ const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
4155
+ if (bal.lessThan(reward.claim.amount)) {
4156
+ logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
4157
+ return unClaimed;
4158
+ }
4159
+ unClaimed.unshift(reward);
4141
4160
  return unClaimed;
4142
4161
  }
4143
4162
  };
@@ -15400,6 +15419,91 @@ var apolloClient = new import_client.ApolloClient({
15400
15419
  });
15401
15420
  var apollo_client_default = apolloClient;
15402
15421
 
15422
+ // src/utils/math-utils.ts
15423
+ async function binarySearch(lowWei, highWei, callback) {
15424
+ while (lowWei <= highWei) {
15425
+ const diff = highWei - lowWei;
15426
+ const mid = lowWei + diff / 2n;
15427
+ const result = await callback(mid);
15428
+ if (result === "found") {
15429
+ return mid;
15430
+ } else if (result == "retry") {
15431
+ } else if (result === "go_low") {
15432
+ highWei = mid - BigInt(1);
15433
+ } else {
15434
+ lowWei = mid + BigInt(1);
15435
+ }
15436
+ }
15437
+ return null;
15438
+ }
15439
+ async function findMaxInputWithSlippage(options) {
15440
+ const {
15441
+ apiGetOutput,
15442
+ maxInput,
15443
+ maxSlippagePercent,
15444
+ tolerance,
15445
+ minInput = 0,
15446
+ referenceAmountMultiplier = 1e-3,
15447
+ referenceRate = 0
15448
+ } = options;
15449
+ let apiCalls = 0;
15450
+ if (!referenceRate && !referenceAmountMultiplier) {
15451
+ throw new Error("One of referenceRate or referenceAmountMultiplier must be provided");
15452
+ }
15453
+ let _referenceRate = referenceRate;
15454
+ if (!_referenceRate) {
15455
+ const smallAmount = maxInput * referenceAmountMultiplier;
15456
+ const referenceOutput = await apiGetOutput(smallAmount);
15457
+ apiCalls++;
15458
+ _referenceRate = referenceOutput / smallAmount;
15459
+ }
15460
+ async function checkSlippage(inputAmount) {
15461
+ const actualOutput = await apiGetOutput(inputAmount);
15462
+ apiCalls++;
15463
+ const expectedOutput = inputAmount * referenceRate;
15464
+ const slippage = (expectedOutput - actualOutput) / expectedOutput;
15465
+ logger.verbose(`findMaxInputWithSlippage::checkSlippage inputAmount: ${inputAmount}, actualOutput: ${actualOutput}, slippage: ${slippage}, maxSlippagePercent: ${maxSlippagePercent}`);
15466
+ return {
15467
+ acceptable: slippage <= maxSlippagePercent,
15468
+ slippage,
15469
+ output: actualOutput
15470
+ };
15471
+ }
15472
+ const maxCheck = await checkSlippage(maxInput);
15473
+ if (maxCheck.acceptable) {
15474
+ return {
15475
+ optimalInput: maxInput,
15476
+ actualOutput: maxCheck.output,
15477
+ actualSlippage: maxCheck.slippage,
15478
+ apiCallsUsed: apiCalls
15479
+ };
15480
+ }
15481
+ let left = minInput;
15482
+ let right = maxInput;
15483
+ let bestInput = minInput;
15484
+ let bestOutput = 0;
15485
+ let bestSlippage = 0;
15486
+ const convergenceThreshold = tolerance * maxInput;
15487
+ while (right - left > convergenceThreshold) {
15488
+ const mid = (left + right) / 2;
15489
+ const midCheck = await checkSlippage(mid);
15490
+ if (midCheck.acceptable) {
15491
+ bestInput = mid;
15492
+ bestOutput = midCheck.output;
15493
+ bestSlippage = midCheck.slippage;
15494
+ left = mid;
15495
+ } else {
15496
+ right = mid;
15497
+ }
15498
+ }
15499
+ return {
15500
+ optimalInput: bestInput,
15501
+ actualOutput: bestOutput,
15502
+ actualSlippage: bestSlippage,
15503
+ apiCallsUsed: apiCalls
15504
+ };
15505
+ }
15506
+
15403
15507
  // src/strategies/ekubo-cl-vault.tsx
15404
15508
  var import_jsx_runtime3 = require("react/jsx-runtime");
15405
15509
  var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
@@ -16522,62 +16626,193 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16522
16626
  logger.verbose(
16523
16627
  `${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
16524
16628
  );
16525
- const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
16526
- const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
16629
+ const isRewardTokenMatch = claim.token.eq(poolKey.token0) || claim.token.eq(poolKey.token1);
16630
+ if (isRewardTokenMatch) {
16631
+ const _callsFinal = await this._handleRewardAndVaultTokenMatchHarvest({
16632
+ acc,
16633
+ claim,
16634
+ isToken1,
16635
+ token0Info,
16636
+ token1Info,
16637
+ postFeeAmount,
16638
+ poolKey,
16639
+ bounds,
16640
+ maxIterations,
16641
+ priceRatioPrecision
16642
+ });
16643
+ calls.push(..._callsFinal);
16644
+ } else {
16645
+ const _callsFinal = await this._handleRewardAndVaultTokenMismatchHarvest({
16646
+ claim,
16647
+ token0Info,
16648
+ token1Info,
16649
+ postFeeAmount,
16650
+ poolKey,
16651
+ bounds,
16652
+ maxIterations,
16653
+ priceRatioPrecision,
16654
+ acc
16655
+ });
16656
+ calls.push(..._callsFinal);
16657
+ }
16658
+ }
16659
+ return calls;
16660
+ }
16661
+ /**
16662
+ * @description This funciton requires atleast one of the pool tokens to be reward token
16663
+ * i.e. STRK.
16664
+ * @param params
16665
+ */
16666
+ async _handleRewardAndVaultTokenMatchHarvest(params) {
16667
+ const { acc, claim, isToken1, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
16668
+ const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
16669
+ const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
16670
+ logger.verbose(
16671
+ `${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
16672
+ );
16673
+ const swapInfo = await this.getSwapInfoGivenAmounts(
16674
+ poolKey,
16675
+ token0Amt,
16676
+ token1Amt,
16677
+ bounds,
16678
+ maxIterations,
16679
+ priceRatioPrecision
16680
+ );
16681
+ swapInfo.token_to_address = token0Info.address.address;
16682
+ logger.verbose(
16683
+ `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
16684
+ );
16685
+ logger.verbose(
16686
+ `${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
16687
+ );
16688
+ const harvestEstimateCall = async (swapInfo1) => {
16689
+ const swap1Amount = Web3Number.fromWei(
16690
+ import_starknet11.uint256.uint256ToBN(swapInfo1.token_from_amount).toString(),
16691
+ 18
16692
+ // cause its always STRK?
16693
+ ).minimum(
16694
+ postFeeAmount.toFixed(18)
16695
+ // cause always strk
16696
+ );
16697
+ swapInfo.token_from_amount = import_starknet11.uint256.bnToUint256(swap1Amount.toWei());
16698
+ swapInfo.token_to_min_amount = import_starknet11.uint256.bnToUint256(
16699
+ swap1Amount.multipliedBy(0).toWei()
16700
+ // placeholder
16701
+ );
16527
16702
  logger.verbose(
16528
- `${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
16703
+ `${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
16529
16704
  );
16530
- const swapInfo = await this.getSwapInfoGivenAmounts(
16531
- poolKey,
16532
- token0Amt,
16533
- token1Amt,
16534
- bounds,
16535
- maxIterations,
16536
- priceRatioPrecision
16705
+ const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
16706
+ logger.verbose(
16707
+ `${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
16537
16708
  );
16538
- swapInfo.token_to_address = token0Info.address.address;
16709
+ const swapInfo2 = {
16710
+ ...swapInfo,
16711
+ token_from_amount: import_starknet11.uint256.bnToUint256(remainingAmount.toWei())
16712
+ };
16713
+ swapInfo2.token_to_address = token1Info.address.address;
16539
16714
  logger.verbose(
16540
- `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
16715
+ `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
16716
+ swapInfo
16717
+ )}`
16541
16718
  );
16542
16719
  logger.verbose(
16543
- `${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
16720
+ `${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
16721
+ swapInfo2
16722
+ )}`
16544
16723
  );
16545
- const harvestEstimateCall = async (swapInfo1) => {
16546
- const swap1Amount = Web3Number.fromWei(
16547
- import_starknet11.uint256.uint256ToBN(swapInfo1.token_from_amount).toString(),
16548
- 18
16549
- // cause its always STRK?
16550
- ).minimum(
16551
- postFeeAmount.toFixed(18)
16552
- // cause always strk
16553
- );
16554
- swapInfo.token_from_amount = import_starknet11.uint256.bnToUint256(swap1Amount.toWei());
16555
- swapInfo.token_to_min_amount = import_starknet11.uint256.bnToUint256(
16556
- swap1Amount.multipliedBy(0).toWei()
16557
- // placeholder
16558
- );
16559
- logger.verbose(
16560
- `${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
16561
- );
16562
- const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
16563
- logger.verbose(
16564
- `${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
16565
- );
16566
- const swapInfo2 = {
16567
- ...swapInfo,
16568
- token_from_amount: import_starknet11.uint256.bnToUint256(remainingAmount.toWei())
16569
- };
16570
- swapInfo2.token_to_address = token1Info.address.address;
16571
- logger.verbose(
16572
- `${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
16573
- swapInfo
16574
- )}`
16575
- );
16576
- logger.verbose(
16577
- `${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
16578
- swapInfo2
16579
- )}`
16580
- );
16724
+ const calldata = [
16725
+ claim.rewardsContract.address,
16726
+ {
16727
+ id: claim.claim.id,
16728
+ amount: claim.claim.amount.toWei(),
16729
+ claimee: claim.claim.claimee.address
16730
+ },
16731
+ claim.proof.map((p) => import_starknet11.num.getDecimalString(p)),
16732
+ swapInfo,
16733
+ swapInfo2
16734
+ ];
16735
+ logger.verbose(
16736
+ `${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
16737
+ calldata
16738
+ )}`
16739
+ );
16740
+ return [this.contract.populate("harvest", calldata)];
16741
+ };
16742
+ const _callsFinal = await this.rebalanceIter(
16743
+ swapInfo,
16744
+ acc,
16745
+ harvestEstimateCall,
16746
+ claim.token.eq(poolKey.token0),
16747
+ 0,
16748
+ 0n,
16749
+ BigInt(postFeeAmount.toWei())
16750
+ // upper limit is the post fee amount
16751
+ );
16752
+ logger.verbose(
16753
+ `${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
16754
+ _callsFinal
16755
+ )}`
16756
+ );
16757
+ return _callsFinal;
16758
+ }
16759
+ /**
16760
+ * @description This function handles harvesting of reward token that is not the same as any of the vault token
16761
+ * i.e. STRK is not part of vault tokens like BTC/ETH
16762
+ * @param params
16763
+ * @returns
16764
+ */
16765
+ async _handleRewardAndVaultTokenMismatchHarvest(params) {
16766
+ const { acc, claim, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
16767
+ let token0Amt = postFeeAmount;
16768
+ const beneficiary = this.address.address;
16769
+ let harvestCall = null;
16770
+ harvestCall = await this.harvestMismatchEstimateCallFn({
16771
+ postFeeAmount,
16772
+ claim,
16773
+ token0Info,
16774
+ token1Info,
16775
+ acc
16776
+ });
16777
+ if (!harvestCall) {
16778
+ throw new Error("Harvest call not found");
16779
+ }
16780
+ return [harvestCall];
16781
+ }
16782
+ // given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
16783
+ // amount for binary search
16784
+ async harvestMismatchEstimateCallFn(params) {
16785
+ const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
16786
+ let harvestCall = null;
16787
+ const binarySearchCallbackFn = async (mid) => {
16788
+ const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
16789
+ const avnuWrapper = new AvnuWrapper();
16790
+ const beneficiary = this.address.address;
16791
+ const quote1 = await avnuWrapper.getQuotes(
16792
+ claim.token.address,
16793
+ token0Info.address.address,
16794
+ mid.toString(),
16795
+ beneficiary
16796
+ );
16797
+ const swapInfo1 = await avnuWrapper.getSwapInfo(
16798
+ quote1,
16799
+ beneficiary,
16800
+ 0,
16801
+ beneficiary
16802
+ );
16803
+ const quote2 = await avnuWrapper.getQuotes(
16804
+ claim.token.address,
16805
+ token1Info.address.address,
16806
+ rewardPart2.toString(),
16807
+ beneficiary
16808
+ );
16809
+ const swapInfo2 = await avnuWrapper.getSwapInfo(
16810
+ quote2,
16811
+ beneficiary,
16812
+ 0,
16813
+ beneficiary
16814
+ );
16815
+ try {
16581
16816
  const calldata = [
16582
16817
  claim.rewardsContract.address,
16583
16818
  {
@@ -16586,34 +16821,24 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
16586
16821
  claimee: claim.claim.claimee.address
16587
16822
  },
16588
16823
  claim.proof.map((p) => import_starknet11.num.getDecimalString(p)),
16589
- swapInfo,
16824
+ swapInfo1,
16590
16825
  swapInfo2
16591
16826
  ];
16592
- logger.verbose(
16593
- `${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
16594
- calldata
16595
- )}`
16596
- );
16597
- return [this.contract.populate("harvest", calldata)];
16598
- };
16599
- const _callsFinal = await this.rebalanceIter(
16600
- swapInfo,
16601
- acc,
16602
- harvestEstimateCall,
16603
- claim.token.eq(poolKey.token0),
16604
- 0,
16605
- 0n,
16606
- BigInt(postFeeAmount.toWei())
16607
- // upper limit is the post fee amount
16608
- );
16609
- logger.verbose(
16610
- `${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
16611
- _callsFinal
16612
- )}`
16613
- );
16614
- calls.push(..._callsFinal);
16615
- }
16616
- return calls;
16827
+ harvestCall = this.contract.populate("harvest", calldata);
16828
+ const gas = await acc.estimateInvokeFee(harvestCall);
16829
+ return "found";
16830
+ } catch (err) {
16831
+ console.error(err);
16832
+ if (err.message.includes("invalid token0 amount")) {
16833
+ return "go_low";
16834
+ } else if (err.message.includes("invalid token1 amount")) {
16835
+ return "go_high";
16836
+ }
16837
+ return "retry";
16838
+ }
16839
+ };
16840
+ await binarySearch(0n, BigInt(postFeeAmount.toWei()), binarySearchCallbackFn);
16841
+ return harvestCall;
16617
16842
  }
16618
16843
  async getInvestmentFlows() {
16619
16844
  const netYield = await this.netAPY();
@@ -19145,7 +19370,58 @@ function toBigInt(value) {
19145
19370
  }
19146
19371
 
19147
19372
  // src/strategies/universal-adapters/baseAdapter.ts
19373
+ var APYType = /* @__PURE__ */ ((APYType2) => {
19374
+ APYType2["BASE"] = "base";
19375
+ APYType2["REWARD"] = "reward";
19376
+ APYType2["LST"] = "lst";
19377
+ return APYType2;
19378
+ })(APYType || {});
19148
19379
  var BaseAdapter = class extends CacheClass {
19380
+ // readonly config: BaseAdapterConfig;
19381
+ // constructor(config: BaseAdapterConfig) {
19382
+ // super();
19383
+ // this.config = config;
19384
+ // }
19385
+ constructor() {
19386
+ super();
19387
+ }
19388
+ // /**
19389
+ // * Loop through all supported positions and return amount, usd value, remarks and apy for each
19390
+ // */
19391
+ // async getPositions(): Promise<PositionInfo[]> {
19392
+ // const results: PositionInfo[] = [];
19393
+ // for (const supported of this.config.supportedPositions) {
19394
+ // const amount = await this.getPosition(supported);
19395
+ // const usdValue = await this.getUSDValue(supported.asset, amount);
19396
+ // const apy = await this.getAPY(supported);
19397
+ // results.push({ amount, usdValue, apy });
19398
+ // }
19399
+ // return results;
19400
+ // }
19401
+ // /**
19402
+ // * Implemented by child adapters to compute APY for a given supported position
19403
+ // */
19404
+ // protected abstract getAPY(supportedPosition: SupportedPosition): Promise<PositionAPY>;
19405
+ // /**
19406
+ // * Implemented by child adapters to fetch amount for a given supported position
19407
+ // */
19408
+ // protected abstract getPosition(supportedPosition: SupportedPosition): Promise<Web3Number>;
19409
+ // /**
19410
+ // * Implemented by child adapters to calculate maximum deposit positions
19411
+ // * @param amount Optional amount in baseToken to deposit
19412
+ // */
19413
+ // protected abstract maxDeposit(amount?: Web3Number): Promise<PositionInfo[]>;
19414
+ // /**
19415
+ // * Implemented by child adapters to calculate maximum withdraw positions
19416
+ // */
19417
+ // protected abstract maxWithdraw(): Promise<PositionInfo[]>;
19418
+ // /**
19419
+ // * Uses pricer to convert an amount of an asset to USD value
19420
+ // */
19421
+ // protected async getUSDValue(asset: TokenInfo, amount: Web3Number): Promise<number> {
19422
+ // const priceInfo = await this.config.pricer.getPrice(asset.symbol);
19423
+ // return amount.toNumber() * priceInfo.price;
19424
+ // }
19149
19425
  constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
19150
19426
  const { id, target, method, packedArguments } = params;
19151
19427
  return {
@@ -19163,6 +19439,94 @@ var BaseAdapter = class extends CacheClass {
19163
19439
  ]
19164
19440
  };
19165
19441
  }
19442
+ // /**
19443
+ // * Implementor must provide target/method/packedArguments/sanitizer for deposit leaf construction
19444
+ // */
19445
+ // protected abstract _getDepositLeaf(): {
19446
+ // target: ContractAddr,
19447
+ // method: string,
19448
+ // packedArguments: bigint[],
19449
+ // sanitizer: ContractAddr,
19450
+ // id: string
19451
+ // }[];
19452
+ // /**
19453
+ // * Implementor must provide target/method/packedArguments/sanitizer for withdraw leaf construction
19454
+ // */
19455
+ // protected abstract _getWithdrawLeaf(): {
19456
+ // target: ContractAddr,
19457
+ // method: string,
19458
+ // packedArguments: bigint[],
19459
+ // sanitizer: ContractAddr,
19460
+ // id: string
19461
+ // }[];
19462
+ // /**
19463
+ // * Returns deposit leaf adapter using configured proof id
19464
+ // */
19465
+ // getDepositLeaf(): AdapterLeafType<T1> {
19466
+ // const leafConfigs = this._getDepositLeaf();
19467
+ // const leaves = leafConfigs.map(config => {
19468
+ // const { target, method, packedArguments, sanitizer, id } = config;
19469
+ // const leaf = this.constructSimpleLeafData({
19470
+ // id: id,
19471
+ // target,
19472
+ // method,
19473
+ // packedArguments
19474
+ // }, sanitizer);
19475
+ // return leaf;
19476
+ // });
19477
+ // return { leaves, callConstructor: this.getDepositCall.bind(this) as unknown as GenerateCallFn<T1> };
19478
+ // }
19479
+ // /**
19480
+ // * Returns withdraw leaf adapter using configured proof id
19481
+ // */
19482
+ // getWithdrawLeaf(): AdapterLeafType<T2> {
19483
+ // const leafConfigs = this._getWithdrawLeaf();
19484
+ // const leaves = leafConfigs.map(config => {
19485
+ // const { target, method, packedArguments, sanitizer, id } = config;
19486
+ // const leaf = this.constructSimpleLeafData({
19487
+ // id: id,
19488
+ // target,
19489
+ // method,
19490
+ // packedArguments
19491
+ // }, sanitizer ?? SIMPLE_SANITIZER);
19492
+ // return leaf;
19493
+ // });
19494
+ // return { leaves, callConstructor: this.getWithdrawCall.bind(this) as unknown as GenerateCallFn<T2> };
19495
+ // }
19496
+ // /**
19497
+ // * Default deposit callConstructor: expects params as calldata (bigint[])
19498
+ // */
19499
+ // protected getDepositCall<T1 = bigint[]>(params: T1): ManageCall[] {
19500
+ // const leafConfigs = this._getDepositLeaf();
19501
+ // return leafConfigs.map(config => {
19502
+ // const { target, method, sanitizer } = config;
19503
+ // return {
19504
+ // sanitizer: sanitizer ?? SIMPLE_SANITIZER,
19505
+ // call: {
19506
+ // contractAddress: target,
19507
+ // selector: hash.getSelectorFromName(method),
19508
+ // calldata: params as unknown as bigint[]
19509
+ // }
19510
+ // };
19511
+ // });
19512
+ // }
19513
+ // /**
19514
+ // * Default withdraw callConstructor: expects params as calldata (bigint[])
19515
+ // */
19516
+ // protected getWithdrawCall<T2 = bigint[]>(params: T2): ManageCall[] {
19517
+ // const leafConfigs = this._getWithdrawLeaf();
19518
+ // return leafConfigs.map(config => {
19519
+ // const { target, method, sanitizer } = config;
19520
+ // return {
19521
+ // sanitizer: sanitizer ?? SIMPLE_SANITIZER,
19522
+ // call: {
19523
+ // contractAddress: target,
19524
+ // selector: hash.getSelectorFromName(method),
19525
+ // calldata: params as unknown as bigint[]
19526
+ // }
19527
+ // };
19528
+ // });
19529
+ // }
19166
19530
  };
19167
19531
 
19168
19532
  // src/strategies/universal-adapters/common-adapter.ts
@@ -26765,7 +27129,20 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26765
27129
  }
26766
27130
  const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
26767
27131
  logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
26768
- return Web3Number.fromWei(output.debt_cap.toString(), this.config.debt.decimals);
27132
+ if (!isV2) {
27133
+ throw new Error("getDebtCap is not supported for v1");
27134
+ }
27135
+ const currentDebt = await this.getCurrentDebtUtilisationAmount(config);
27136
+ logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap currentDebt: ${currentDebt.toString()}`);
27137
+ return Web3Number.fromWei(output.debt_cap.toString(), this.config.debt.decimals).minus(currentDebt);
27138
+ }
27139
+ async getCurrentDebtUtilisationAmount(config) {
27140
+ const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
27141
+ if (!isV2) {
27142
+ throw new Error("getCurrentDebtUtilisationAmount is not supported for v1");
27143
+ }
27144
+ const output = await contract.call("pairs", [this.config.collateral.address.address, this.config.debt.address.address]);
27145
+ return new Web3Number((Number(output.total_nominal_debt) / 1e18).toFixed(9), this.config.debt.decimals);
26769
27146
  }
26770
27147
  async getMaxBorrowableByInterestRate(config, asset, maxBorrowAPY) {
26771
27148
  const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
@@ -26798,16 +27175,17 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26798
27175
  const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
26799
27176
  const timeDelta = assetConfig.last_updated;
26800
27177
  const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
26801
- const totalSupply = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals).plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
27178
+ const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals);
27179
+ const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
26802
27180
  const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
26803
27181
  const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
26804
27182
  logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
26805
27183
  const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
26806
- const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals);
27184
+ logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
26807
27185
  return maxDebtToHave.minus(currentDebt);
26808
27186
  }
26809
- async getLTVConfig(config) {
26810
- const CACHE_KEY = "ltv_config";
27187
+ async getLTVConfig(config, blockNumber = "latest") {
27188
+ const CACHE_KEY = `ltv_config_${blockNumber}`;
26811
27189
  const cacheData = this.getCache(CACHE_KEY);
26812
27190
  if (cacheData) {
26813
27191
  return cacheData;
@@ -26815,10 +27193,10 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26815
27193
  const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
26816
27194
  let ltv = 0;
26817
27195
  if (isV2) {
26818
- const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
27196
+ const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
26819
27197
  ltv = Number(output.max_ltv) / 1e18;
26820
27198
  } else {
26821
- const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
27199
+ const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
26822
27200
  ltv = Number(output.max_ltv) / 1e18;
26823
27201
  }
26824
27202
  if (ltv == 0) {
@@ -26827,11 +27205,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26827
27205
  this.setCache(CACHE_KEY, ltv, 3e5);
26828
27206
  return this.getCache(CACHE_KEY);
26829
27207
  }
26830
- async getPositions(config) {
27208
+ async getPositions(config, blockNumber = "latest") {
26831
27209
  if (!this.pricer) {
26832
27210
  throw new Error("Pricer is not initialized");
26833
27211
  }
26834
- const CACHE_KEY = "positions";
27212
+ const CACHE_KEY = `positions_${blockNumber}`;
26835
27213
  const cacheData = this.getCache(CACHE_KEY);
26836
27214
  if (cacheData) {
26837
27215
  return cacheData;
@@ -26843,7 +27221,8 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26843
27221
  this.config.collateral.address.address,
26844
27222
  this.config.debt.address.address,
26845
27223
  this.config.vaultAllocator.address
26846
- ]);
27224
+ ], { blockIdentifier: blockNumber });
27225
+ console.log(output);
26847
27226
  const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
26848
27227
  const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
26849
27228
  logger.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
@@ -26863,11 +27242,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26863
27242
  this.setCache(CACHE_KEY, value, 6e4);
26864
27243
  return value;
26865
27244
  }
26866
- async getCollateralization(config) {
27245
+ async getCollateralization(config, blockNumber = "latest") {
26867
27246
  if (!this.pricer) {
26868
27247
  throw new Error("Pricer is not initialized");
26869
27248
  }
26870
- const CACHE_KEY = "collateralization";
27249
+ const CACHE_KEY = `collateralization_${blockNumber}`;
26871
27250
  const cacheData = this.getCache(CACHE_KEY);
26872
27251
  if (cacheData) {
26873
27252
  return cacheData;
@@ -26879,7 +27258,7 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26879
27258
  this.config.collateral.address.address,
26880
27259
  this.config.debt.address.address,
26881
27260
  this.config.vaultAllocator.address
26882
- ]);
27261
+ ], { blockIdentifier: blockNumber });
26883
27262
  const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
26884
27263
  const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
26885
27264
  const value = [{
@@ -26916,9 +27295,9 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
26916
27295
  ltv
26917
27296
  };
26918
27297
  }
26919
- async getHealthFactor() {
26920
- const ltv = await this.getLTVConfig(this.networkConfig);
26921
- const collateralisation = await this.getCollateralization(this.networkConfig);
27298
+ async getHealthFactor(blockNumber = "latest") {
27299
+ const ltv = await this.getLTVConfig(this.networkConfig, blockNumber);
27300
+ const collateralisation = await this.getCollateralization(this.networkConfig, blockNumber);
26922
27301
  return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
26923
27302
  }
26924
27303
  static async getVesuPools(retry = 0) {
@@ -29580,11 +29959,11 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
29580
29959
  vesuAdapter2.networkConfig = this.config;
29581
29960
  return [vesuAdapter1, vesuAdapter2];
29582
29961
  }
29583
- async getVesuPositions() {
29962
+ async getVesuPositions(blockNumber = "latest") {
29584
29963
  const adapters = this.getVesuAdapters();
29585
29964
  const positions = [];
29586
29965
  for (const adapter of adapters) {
29587
- positions.push(...await adapter.getPositions(this.config));
29966
+ positions.push(...await adapter.getPositions(this.config, blockNumber));
29588
29967
  }
29589
29968
  return positions;
29590
29969
  }
@@ -29653,8 +30032,8 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
29653
30032
  async getLSTAPR(address) {
29654
30033
  return 0;
29655
30034
  }
29656
- async getVesuHealthFactors() {
29657
- return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
30035
+ async getVesuHealthFactors(blockNumber = "latest") {
30036
+ return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor(blockNumber)));
29658
30037
  }
29659
30038
  async computeRebalanceConditionAndReturnCalls() {
29660
30039
  const vesuAdapters = this.getVesuAdapters();
@@ -30250,6 +30629,42 @@ var UniversalStrategies = [
30250
30629
 
30251
30630
  // src/strategies/universal-lst-muliplier-strategy.tsx
30252
30631
  var import_starknet17 = require("starknet");
30632
+
30633
+ // src/utils/health-factor-math.ts
30634
+ var HealthFactorMath = class {
30635
+ static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
30636
+ const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
30637
+ const denominator = collateralPrice * maxLTV;
30638
+ const collateralAmount = numerator.dividedBy(denominator);
30639
+ const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
30640
+ return netCollateral;
30641
+ }
30642
+ static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
30643
+ const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
30644
+ const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
30645
+ return netCollateral.minus(collateralFromDebt);
30646
+ }
30647
+ static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
30648
+ const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
30649
+ const denominator = debtAmount.multipliedBy(debtPrice);
30650
+ const healthFactor = numerator.dividedBy(denominator);
30651
+ return healthFactor.toNumber();
30652
+ }
30653
+ static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
30654
+ const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
30655
+ const denominator = targetHF - maxLTV;
30656
+ const debtAmount = numerator.dividedBy(denominator);
30657
+ return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
30658
+ }
30659
+ static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
30660
+ const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
30661
+ const denominator = targetHF * debtPrice;
30662
+ const debtAmount = numerator.dividedBy(denominator);
30663
+ return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
30664
+ }
30665
+ };
30666
+
30667
+ // src/strategies/universal-lst-muliplier-strategy.tsx
30253
30668
  var import_jsx_runtime5 = require("react/jsx-runtime");
30254
30669
  var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
30255
30670
  constructor(config, pricer, metadata) {
@@ -30264,15 +30679,14 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30264
30679
  }
30265
30680
  }
30266
30681
  asset() {
30267
- const vesuAdapter1 = this.getAdapter("vesu_leg1_adapter" /* VESU_LEG1 */);
30268
- return vesuAdapter1.config.collateral;
30682
+ return this.getVesuSameTokenAdapter().config.collateral;
30269
30683
  }
30270
30684
  getTag() {
30271
30685
  return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
30272
30686
  }
30273
30687
  // Vesu adapter with LST and base token match
30274
30688
  getVesuSameTokenAdapter() {
30275
- const baseAdapter = this.getAdapter("vesu_leg1_adapter" /* VESU_LEG1 */);
30689
+ const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
30276
30690
  baseAdapter.networkConfig = this.config;
30277
30691
  baseAdapter.pricer = this.pricer;
30278
30692
  return baseAdapter;
@@ -30320,20 +30734,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30320
30734
  return price;
30321
30735
  }
30322
30736
  async getAvnuSwapMultiplyCall(params) {
30323
- return this._getAvnuDepositSwapLegCall({
30324
- ...params,
30325
- minHF: 1.1
30326
- // undo
30327
- });
30737
+ assert(params.isDeposit, "Only deposit is supported in getAvnuSwapMultiplyCall");
30738
+ const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
30739
+ const allVesuAdapters = this.getVesuAdapters();
30740
+ let remainingAmount = params.leg1DepositAmount;
30741
+ const lstExRate = await this.getLSTExchangeRate();
30742
+ const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
30743
+ const lstPrice = baseAssetPrice.price * lstExRate;
30744
+ for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
30745
+ const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
30746
+ const vesuAdapter = allVesuAdapters.find((adapter) => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
30747
+ if (!vesuAdapter) {
30748
+ throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
30749
+ }
30750
+ const maxLTV = await vesuAdapter.getLTVConfig(this.config);
30751
+ const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
30752
+ const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
30753
+ maxBorrowable.amount,
30754
+ debtPrice.price,
30755
+ this.metadata.additionalInfo.targetHealthFactor,
30756
+ maxLTV,
30757
+ lstPrice,
30758
+ this.asset()
30759
+ );
30760
+ const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
30761
+ logger.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
30762
+ const call = await this._getAvnuDepositSwapLegCall({
30763
+ isDeposit: params.isDeposit,
30764
+ // adjust decimals of debt asset
30765
+ leg1DepositAmount: amountToDeposit,
30766
+ minHF: 1.1,
30767
+ // undo
30768
+ vesuAdapter
30769
+ });
30770
+ remainingAmount = remainingAmount.minus(amountToDeposit);
30771
+ return { call, vesuAdapter };
30772
+ }
30773
+ throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
30328
30774
  }
30329
30775
  async _getAvnuDepositSwapLegCall(params) {
30776
+ const { vesuAdapter } = params;
30330
30777
  logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
30331
30778
  assert(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
30332
- const [vesuAdapter1] = this.getVesuAdapters();
30333
- const legLTV = await vesuAdapter1.getLTVConfig(this.config);
30779
+ const legLTV = await vesuAdapter.getLTVConfig(this.config);
30334
30780
  logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
30335
- const existingPositions = await vesuAdapter1.getPositions(this.config);
30336
- const collateralisation = await vesuAdapter1.getCollateralization(this.config);
30781
+ const existingPositions = await vesuAdapter.getPositions(this.config);
30782
+ const collateralisation = await vesuAdapter.getCollateralization(this.config);
30337
30783
  const existingCollateralInfo = existingPositions[0];
30338
30784
  const existingDebtInfo = existingPositions[1];
30339
30785
  logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
@@ -30341,11 +30787,40 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30341
30787
  const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
30342
30788
  const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
30343
30789
  logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
30790
+ const debtTokenInfo = vesuAdapter.config.debt;
30791
+ let newDepositAmount = params.leg1DepositAmount;
30344
30792
  const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
30345
30793
  logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
30346
- const totalDebtAmount = totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF);
30347
- logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}`);
30348
- const debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
30794
+ const totalDebtAmount = new Web3Number(
30795
+ totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
30796
+ debtTokenInfo.decimals
30797
+ );
30798
+ let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
30799
+ logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
30800
+ const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
30801
+ if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
30802
+ logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
30803
+ return void 0;
30804
+ } else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
30805
+ debtAmount = maxBorrowable.amount.minimum(debtAmount);
30806
+ const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
30807
+ const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
30808
+ debtAmount.plus(existingDebtInfo.amount),
30809
+ debtPrice,
30810
+ params.minHF,
30811
+ legLTV,
30812
+ collateralPrice,
30813
+ this.asset()
30814
+ );
30815
+ newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
30816
+ if (newDepositAmount.lt(0)) {
30817
+ throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
30818
+ }
30819
+ if (newDebtUSDValue.toNumber() < 100) {
30820
+ logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
30821
+ return void 0;
30822
+ }
30823
+ }
30349
30824
  logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
30350
30825
  if (debtAmount.lt(0)) {
30351
30826
  const lstDEXPrice = await this.getLSTDexPrice();
@@ -30357,32 +30832,34 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30357
30832
  assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
30358
30833
  return calls[0];
30359
30834
  }
30835
+ console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
30360
30836
  const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
30361
30837
  const manage0Info = this.getProofs(STEP0);
30362
30838
  const manageCall0 = manage0Info.callConstructor({
30363
- amount: params.leg1DepositAmount
30839
+ amount: newDepositAmount
30364
30840
  });
30365
- const STEP1 = "vesu_leg1" /* VESU_LEG1 */;
30841
+ const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
30366
30842
  const manage1Info = this.getProofs(STEP1);
30367
30843
  const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
30368
- collateralAmount: params.leg1DepositAmount,
30844
+ collateralAmount: newDepositAmount,
30369
30845
  isAddCollateral: params.isDeposit,
30370
30846
  debtAmount,
30371
30847
  isBorrow: params.isDeposit
30372
30848
  }));
30849
+ console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
30373
30850
  const proofIds = [STEP0, STEP1];
30374
30851
  const manageCalls = [manageCall0, manageCall1];
30375
30852
  if (debtAmount.gt(0)) {
30376
- const STEP2 = "avnu_multiply_approve_deposit" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */;
30853
+ const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
30377
30854
  const manage2Info = this.getProofs(STEP2);
30378
30855
  const manageCall2 = manage2Info.callConstructor({
30379
30856
  amount: debtAmount
30380
30857
  });
30381
- const debtTokenInfo = vesuAdapter1.config.debt;
30858
+ const debtTokenInfo2 = vesuAdapter.config.debt;
30382
30859
  const lstTokenInfo = this.asset();
30383
30860
  const avnuModule = new AvnuWrapper();
30384
30861
  const quote = await avnuModule.getQuotes(
30385
- debtTokenInfo.address.address,
30862
+ debtTokenInfo2.address.address,
30386
30863
  lstTokenInfo.address.address,
30387
30864
  debtAmount.toWei(),
30388
30865
  this.metadata.additionalInfo.vaultAllocator.address
@@ -30398,7 +30875,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30398
30875
  minAmountWei
30399
30876
  );
30400
30877
  logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
30401
- const STEP3 = "avnu_multiply_swap_deposit" /* AVNU_MULTIPLY_SWAP_DEPOSIT */;
30878
+ const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
30402
30879
  const manage3Info = this.getProofs(STEP3);
30403
30880
  const manageCall3 = manage3Info.callConstructor({
30404
30881
  props: swapInfo
@@ -30416,7 +30893,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30416
30893
  const manageCall4 = manage4Info.callConstructor({
30417
30894
  amount: minAmount
30418
30895
  });
30419
- const STEP5 = "vesu_leg1" /* VESU_LEG1 */;
30896
+ const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
30420
30897
  const manage5Info = this.getProofs(STEP5);
30421
30898
  const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
30422
30899
  collateralAmount: minAmount,
@@ -30433,28 +30910,41 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30433
30910
  }
30434
30911
  // todo unwind or not deposit when the yield is bad.
30435
30912
  async getLSTMultiplierRebalanceCall() {
30436
- const positions = await this.getVaultPositions();
30437
- assert(positions.length == 3, "Rebalance call is only supported for 3 positions");
30913
+ let shouldRebalance = false;
30914
+ const calls = [];
30915
+ const allVesuAdapters = this.getVesuAdapters().filter((vesuAdapter) => vesuAdapter.config.debt.symbol === "LBTC");
30916
+ for (const vesuAdapter of allVesuAdapters) {
30917
+ const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
30918
+ if (call.shouldRebalance && call.manageCall) {
30919
+ shouldRebalance = true;
30920
+ calls.push({ vesuAdapter, manageCall: call.manageCall });
30921
+ }
30922
+ }
30923
+ return { shouldRebalance, manageCalls: calls };
30924
+ }
30925
+ async _getLSTMultiplierRebalanceCall(vesuAdapter) {
30926
+ const positions = await vesuAdapter.getPositions(this.config);
30927
+ assert(positions.length == 2, "Rebalance call is only supported for 2 positions");
30438
30928
  const existingCollateralInfo = positions[0];
30439
30929
  const existingDebtInfo = positions[1];
30440
- const unusedBalance = positions[2];
30441
- const [healthFactor] = await this.getVesuHealthFactors();
30442
- const [vesuAdapter1] = this.getVesuAdapters();
30443
- const legLTV = await vesuAdapter1.getLTVConfig(this.config);
30444
- const collateralisation = await vesuAdapter1.getCollateralization(this.config);
30445
- logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
30930
+ const unusedBalance = await this.getUnusedBalance();
30931
+ const healthFactor = await vesuAdapter.getHealthFactor();
30932
+ const collateralisation = await vesuAdapter.getCollateralization(this.config);
30933
+ logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
30446
30934
  existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
30447
30935
  const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
30448
30936
  const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
30449
30937
  logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
30938
+ logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
30450
30939
  const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
30451
30940
  const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
30452
- if (isHFTooLow || isHFTooHigh) {
30941
+ if (isHFTooLow || isHFTooHigh || 1) {
30453
30942
  const manageCall = await this._getAvnuDepositSwapLegCall({
30454
30943
  isDeposit: true,
30455
30944
  leg1DepositAmount: unusedBalance.amount,
30456
- minHF: 1.02
30945
+ minHF: 1.02,
30457
30946
  // todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
30947
+ vesuAdapter
30458
30948
  });
30459
30949
  return { shouldRebalance: true, manageCall };
30460
30950
  } else {
@@ -30487,7 +30977,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30487
30977
  async _getMinOutputAmountLSTBuy(amountInUnderlying) {
30488
30978
  const lstTruePrice = await this.getLSTExchangeRate();
30489
30979
  const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
30490
- return minOutputAmount;
30980
+ return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
30491
30981
  }
30492
30982
  async _getMinOutputAmountLSTSell(amountInLST) {
30493
30983
  const lstTruePrice = await this.getLSTExchangeRate();
@@ -30544,21 +31034,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30544
31034
  const vesuAdapter1 = this.getVesuSameTokenAdapter();
30545
31035
  return vesuAdapter1.config.debt;
30546
31036
  }
30547
- async getMaxBorrowableAmount() {
31037
+ async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
30548
31038
  const vesuAdapters = this.getVesuAdapters();
30549
31039
  let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
30550
31040
  const maxBorrowables = [];
30551
- const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
30552
- const maxInterestRate = lstAPY * 0.8;
30553
31041
  for (const vesuAdapter of vesuAdapters) {
30554
- const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
30555
- const debtCap = await vesuAdapter.getDebtCap(this.config);
30556
- maxBorrowables.push({ amount: maxBorrowableAmount.minimum(debtCap), borrowableAsset: vesuAdapter.config.debt });
31042
+ maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
30557
31043
  }
30558
31044
  maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
30559
31045
  netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
30560
31046
  return { netMaxBorrowableAmount, maxBorrowables };
30561
31047
  }
31048
+ // recursively, using binary search computes max swappable.
31049
+ // @dev assumes 1 token of from == 1 token of to
31050
+ async getMaxSwappableWithMaxSlippage(fromToken, toToken, maxSlippage, maxAmount) {
31051
+ const output = await findMaxInputWithSlippage({
31052
+ apiGetOutput: async (inputAmount) => {
31053
+ const ekuboQuoter = new EkuboQuoter(this.config);
31054
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
31055
+ const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
31056
+ return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
31057
+ },
31058
+ maxInput: maxAmount.toNumber(),
31059
+ maxSlippagePercent: maxSlippage,
31060
+ tolerance: 1e-3,
31061
+ referenceRate: 1
31062
+ });
31063
+ return new Web3Number(output.optimalInput, fromToken.decimals);
31064
+ }
31065
+ async getMaxBorrowableAmountByVesuAdapter(vesuAdapter, isAPYComputation) {
31066
+ const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
31067
+ const maxInterestRate = lstAPY * 0.8;
31068
+ const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
31069
+ const debtCap = await vesuAdapter.getDebtCap(this.config);
31070
+ const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
31071
+ if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
31072
+ return { amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
31073
+ }
31074
+ try {
31075
+ const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 2e-4, maxBorrowable);
31076
+ return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
31077
+ } catch (error) {
31078
+ logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
31079
+ const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
31080
+ return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
31081
+ }
31082
+ }
30562
31083
  // todo how much to unwind to get back healthy APY zone again
30563
31084
  // if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
30564
31085
  // For xSTRK, simply deposit in Vesu if looping is not viable
@@ -30582,7 +31103,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30582
31103
  // todo undo this
30583
31104
  async netAPY() {
30584
31105
  const unusedBalance = await this.getUnusedBalance();
30585
- const maxNewDeposits = await this.maxNewDeposits();
31106
+ const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
30586
31107
  const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
30587
31108
  if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
30588
31109
  logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
@@ -30599,8 +31120,8 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30599
31120
  return output;
30600
31121
  }
30601
31122
  }
30602
- async maxNewDeposits() {
30603
- const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
31123
+ async maxNewDeposits(params = { isAPYComputation: false }) {
31124
+ const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
30604
31125
  let ltv = void 0;
30605
31126
  for (let adapter of this.getVesuAdapters()) {
30606
31127
  const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
@@ -30703,7 +31224,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
30703
31224
  const manageCall2 = manage2Info.callConstructor({
30704
31225
  delegation: true
30705
31226
  });
30706
- const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU */;
31227
+ const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
30707
31228
  const manage3Info = this.getProofs(STEP3_ID);
30708
31229
  const multiplyParams = params.isIncrease ? {
30709
31230
  isIncrease: true,
@@ -30769,6 +31290,7 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
30769
31290
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }, children: [
30770
31291
  "This vault uses Vesu for lending and borrowing. The oracle used by this pool is a ",
30771
31292
  highlightTextWithLinks("conversion rate oracle", [{ highlight: "conversion rate oracle", link: "https://docs.pragma.build/starknet/development#conversion-rate" }]),
31293
+ " ",
30772
31294
  "which is resilient to liquidity issues and price volatility, hence reducing the risk of liquidation. However, overtime, if left un-monitored, debt can increase enough to trigger a liquidation. But no worries, our continuous monitoring systems look for situations with reduced health factor and balance collateral/debt to bring it back to safe levels. With Troves, you can have a peaceful sleep."
30773
31295
  ] }),
30774
31296
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
@@ -30779,17 +31301,19 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
30779
31301
  ] }) }),
30780
31302
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
30781
31303
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Debt limits:" }),
30782
- " Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited LSTs remain in the vault, generating a shared net return for all depositors."
30783
- ] }) }),
30784
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
30785
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "APY assumptions:" }),
30786
- " APY shown is the max possible value given current LST and borrowing rates. True APY will be subject to the actual leverage, based on above point. More insights on exact APY will be added soon."
31304
+ " Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited LSTs remain in the vault, generating a shared net return for all depositors. There is no additional fee taken by Troves on LST APY, its only on added gain."
30787
31305
  ] }) })
30788
31306
  ] });
30789
31307
  }
30790
31308
  function getDescription2(tokenSymbol, underlyingSymbol) {
30791
31309
  return VaultDescription(tokenSymbol, underlyingSymbol);
30792
31310
  }
31311
+ function getAvnuManageIDs(baseID, debtTokenSymbol) {
31312
+ return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
31313
+ }
31314
+ function getVesuLegId(baseID, debtTokenSymbol) {
31315
+ return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
31316
+ }
30793
31317
  function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
30794
31318
  vaultSettings.leafAdapters = [];
30795
31319
  const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
@@ -30799,7 +31323,7 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
30799
31323
  collateral: lstToken,
30800
31324
  debt: underlyingToken,
30801
31325
  vaultAllocator: vaultSettings.vaultAllocator,
30802
- id: "vesu_leg1" /* VESU_LEG1 */
31326
+ id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
30803
31327
  });
30804
31328
  const commonAdapter = new CommonAdapter({
30805
31329
  manager: vaultSettings.manager,
@@ -30808,25 +31332,39 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
30808
31332
  vaultAddress: vaultSettings.vaultAddress,
30809
31333
  vaultAllocator: vaultSettings.vaultAllocator
30810
31334
  });
30811
- const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
30812
- const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
30813
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
30814
- vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter("multiply_vesu" /* MULTIPLY_VESU */).bind(vesuAdapterLST));
30815
- vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
30816
- vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
30817
31335
  vaultSettings.adapters.push(...[{
30818
- id: "vesu_leg1_adapter" /* VESU_LEG1 */,
31336
+ id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
30819
31337
  adapter: vesuAdapterLST
30820
31338
  }, {
30821
31339
  id: "common_adapter" /* COMMON */,
30822
31340
  adapter: commonAdapter
30823
31341
  }]);
30824
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(underlyingToken.address, AVNU_EXCHANGE, "avnu_multiply_approve_deposit" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */).bind(commonAdapter));
30825
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(underlyingToken.address, lstToken.address, "avnu_multiply_swap_deposit" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, false).bind(commonAdapter));
30826
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_multiply_approve_withdraw" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
30827
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, underlyingToken.address, "avnu_multiply_swap_withdraw" /* AVNU_MULTIPLY_SWAP_WITHDRAW */, false).bind(commonAdapter));
30828
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
30829
- vaultSettings.leafAdapters.push(vesuAdapterLST.getModifyPosition.bind(vesuAdapterLST));
31342
+ const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
31343
+ const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
31344
+ vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
31345
+ vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
31346
+ vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
31347
+ vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_mul_approve_withdr" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
31348
+ for (let borrowableAsset of vaultSettings.borrowable_assets) {
31349
+ const debtAsset = borrowableAsset;
31350
+ const approve_debt_token_id = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, debtAsset.symbol);
31351
+ const swap_debt_token_id = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, debtAsset.symbol);
31352
+ const swap_lst_token_id = getAvnuManageIDs("avnu_mul_swap_withdr" /* AVNU_MULTIPLY_SWAP_WITHDRAW */, debtAsset.symbol);
31353
+ vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
31354
+ vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
31355
+ vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
31356
+ const vesuAdapter = new VesuAdapter({
31357
+ poolId: pool1,
31358
+ collateral: lstToken,
31359
+ debt: debtAsset,
31360
+ vaultAllocator: vaultSettings.vaultAllocator,
31361
+ id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol)
31362
+ });
31363
+ vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
31364
+ vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
31365
+ const multiplID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, debtAsset.symbol);
31366
+ vaultSettings.leafAdapters.push(vesuAdapter.getMultiplyAdapter(multiplID).bind(vesuAdapter));
31367
+ }
30830
31368
  vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
30831
31369
  vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
30832
31370
  vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
@@ -30904,7 +31442,8 @@ var hyperxSTRK = {
30904
31442
  adapters: [],
30905
31443
  targetHealthFactor: 1.1,
30906
31444
  minHealthFactor: 1.05,
30907
- borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK")
31445
+ borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK"),
31446
+ underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK")
30908
31447
  };
30909
31448
  var hyperxWBTC = {
30910
31449
  vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
@@ -30916,7 +31455,8 @@ var hyperxWBTC = {
30916
31455
  adapters: [],
30917
31456
  targetHealthFactor: 1.1,
30918
31457
  minHealthFactor: 1.05,
30919
- borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
31458
+ borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
31459
+ underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC")
30920
31460
  };
30921
31461
  var hyperxtBTC = {
30922
31462
  vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
@@ -30928,7 +31468,8 @@ var hyperxtBTC = {
30928
31468
  adapters: [],
30929
31469
  targetHealthFactor: 1.1,
30930
31470
  minHealthFactor: 1.05,
30931
- borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
31471
+ borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
31472
+ underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC")
30932
31473
  };
30933
31474
  var hyperxsBTC = {
30934
31475
  vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
@@ -30940,7 +31481,8 @@ var hyperxsBTC = {
30940
31481
  adapters: [],
30941
31482
  targetHealthFactor: 1.1,
30942
31483
  minHealthFactor: 1.05,
30943
- borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
31484
+ borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
31485
+ underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC")
30944
31486
  };
30945
31487
  var hyperxLBTC = {
30946
31488
  vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
@@ -30952,7 +31494,8 @@ var hyperxLBTC = {
30952
31494
  adapters: [],
30953
31495
  targetHealthFactor: 1.1,
30954
31496
  minHealthFactor: 1.05,
30955
- borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
31497
+ borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
31498
+ underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC")
30956
31499
  };
30957
31500
  function getInvestmentSteps(lstSymbol, underlyingSymbol) {
30958
31501
  return [
@@ -30984,7 +31527,7 @@ function getStrategySettings(lstSymbol, underlyingSymbol, addresses, isPreview =
30984
31527
  faqs: getFAQs2(lstSymbol, underlyingSymbol),
30985
31528
  investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
30986
31529
  isPreview,
30987
- apyMethodology: "Current annualized APY in terms of base asset of the LST"
31530
+ apyMethodology: "Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown."
30988
31531
  };
30989
31532
  }
30990
31533
  var HyperLSTStrategies = [
@@ -31655,6 +32198,7 @@ var Deployer = {
31655
32198
  var deployer_default = Deployer;
31656
32199
  // Annotate the CommonJS export names for ESM import in node:
31657
32200
  0 && (module.exports = {
32201
+ APYType,
31658
32202
  AUMTypes,
31659
32203
  AVNU_EXCHANGE,
31660
32204
  AVNU_MIDDLEWARE,