@strkfarm/sdk 1.1.39 → 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.browser.global.js +723 -179
- package/dist/index.browser.mjs +722 -176
- package/dist/index.d.ts +126 -13
- package/dist/index.js +723 -176
- package/dist/index.mjs +722 -176
- package/package.json +1 -1
- package/src/global.ts +18 -0
- package/src/modules/avnu.ts +5 -4
- package/src/modules/harvests.ts +16 -15
- package/src/strategies/ekubo-cl-vault.tsx +255 -79
- package/src/strategies/universal-adapters/baseAdapter.ts +184 -2
- package/src/strategies/universal-adapters/vesu-adapter.ts +34 -17
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +322 -0
- package/src/strategies/universal-lst-muliplier-strategy.tsx +226 -67
- package/src/strategies/universal-strategy.tsx +5 -5
- package/src/utils/health-factor-math.ts +83 -0
- package/src/utils/math-utils.ts +150 -0
package/dist/index.browser.mjs
CHANGED
|
@@ -274,6 +274,25 @@ var defaultTokens = [{
|
|
|
274
274
|
priceProxySymbol: "WBTC",
|
|
275
275
|
priceCheckAmount: 1e-4
|
|
276
276
|
// 112000 * 0.0001 = $11.2
|
|
277
|
+
}, {
|
|
278
|
+
name: "mRe7BTC",
|
|
279
|
+
symbol: "mRe7BTC",
|
|
280
|
+
logo: "https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/3a62ecee-1e58-45d3-9862-3ce90dff1900/logo",
|
|
281
|
+
address: ContractAddr.from("0x4e4fb1a9ca7e84bae609b9dc0078ad7719e49187ae7e425bb47d131710eddac"),
|
|
282
|
+
decimals: 18,
|
|
283
|
+
coingeckId: void 0,
|
|
284
|
+
displayDecimals: 6,
|
|
285
|
+
priceCheckAmount: 1e-4
|
|
286
|
+
// 112000 * 0.0001 = $11.2
|
|
287
|
+
}, {
|
|
288
|
+
name: "mRe7YIELD",
|
|
289
|
+
symbol: "mRe7YIELD",
|
|
290
|
+
logo: "https://midas.app/assets/mre7-BcOOHm7i.svg",
|
|
291
|
+
address: ContractAddr.from("0x4be8945e61dc3e19ebadd1579a6bd53b262f51ba89e6f8b0c4bc9a7e3c633fc"),
|
|
292
|
+
decimals: 18,
|
|
293
|
+
coingeckId: void 0,
|
|
294
|
+
displayDecimals: 2,
|
|
295
|
+
priceCheckAmount: 100
|
|
277
296
|
}];
|
|
278
297
|
var tokens = defaultTokens;
|
|
279
298
|
var _Global = class _Global {
|
|
@@ -2159,16 +2178,16 @@ var AvnuWrapper = class _AvnuWrapper {
|
|
|
2159
2178
|
};
|
|
2160
2179
|
return swapInfo;
|
|
2161
2180
|
}
|
|
2162
|
-
static buildZeroSwap(tokenToSell,
|
|
2181
|
+
static buildZeroSwap(tokenToSell, beneficiary, tokenToBuy = tokenToSell) {
|
|
2163
2182
|
return {
|
|
2164
2183
|
token_from_address: tokenToSell.address,
|
|
2165
2184
|
token_from_amount: uint256.bnToUint256(0),
|
|
2166
|
-
token_to_address:
|
|
2185
|
+
token_to_address: tokenToBuy.address,
|
|
2167
2186
|
token_to_amount: uint256.bnToUint256(0),
|
|
2168
2187
|
token_to_min_amount: uint256.bnToUint256(0),
|
|
2169
|
-
beneficiary
|
|
2188
|
+
beneficiary,
|
|
2170
2189
|
integrator_fee_amount_bps: 0,
|
|
2171
|
-
integrator_fee_recipient:
|
|
2190
|
+
integrator_fee_recipient: beneficiary,
|
|
2172
2191
|
routes: []
|
|
2173
2192
|
};
|
|
2174
2193
|
}
|
|
@@ -4120,21 +4139,20 @@ var Harvests = class _Harvests {
|
|
|
4120
4139
|
const rewards = await this.getHarvests(addr);
|
|
4121
4140
|
if (rewards.length == 0) return [];
|
|
4122
4141
|
const unClaimed = [];
|
|
4123
|
-
const
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
}
|
|
4131
|
-
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4132
|
-
if (bal.lessThan(reward.claim.amount)) {
|
|
4133
|
-
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4134
|
-
continue;
|
|
4135
|
-
}
|
|
4136
|
-
unClaimed.unshift(reward);
|
|
4142
|
+
const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
|
|
4143
|
+
const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
|
|
4144
|
+
const contract = new Contract4({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
|
|
4145
|
+
const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
|
|
4146
|
+
logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
|
|
4147
|
+
if (isClaimed) {
|
|
4148
|
+
return unClaimed;
|
|
4137
4149
|
}
|
|
4150
|
+
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4151
|
+
if (bal.lessThan(reward.claim.amount)) {
|
|
4152
|
+
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4153
|
+
return unClaimed;
|
|
4154
|
+
}
|
|
4155
|
+
unClaimed.unshift(reward);
|
|
4138
4156
|
return unClaimed;
|
|
4139
4157
|
}
|
|
4140
4158
|
};
|
|
@@ -15401,6 +15419,91 @@ var apolloClient = new ApolloClient({
|
|
|
15401
15419
|
});
|
|
15402
15420
|
var apollo_client_default = apolloClient;
|
|
15403
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
|
+
|
|
15404
15507
|
// src/strategies/ekubo-cl-vault.tsx
|
|
15405
15508
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
15406
15509
|
var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
@@ -16523,62 +16626,193 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16523
16626
|
logger.verbose(
|
|
16524
16627
|
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
16525
16628
|
);
|
|
16526
|
-
const
|
|
16527
|
-
|
|
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
|
+
uint2564.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 = uint2564.bnToUint256(swap1Amount.toWei());
|
|
16698
|
+
swapInfo.token_to_min_amount = uint2564.bnToUint256(
|
|
16699
|
+
swap1Amount.multipliedBy(0).toWei()
|
|
16700
|
+
// placeholder
|
|
16701
|
+
);
|
|
16528
16702
|
logger.verbose(
|
|
16529
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16703
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
16530
16704
|
);
|
|
16531
|
-
const
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
token1Amt,
|
|
16535
|
-
bounds,
|
|
16536
|
-
maxIterations,
|
|
16537
|
-
priceRatioPrecision
|
|
16705
|
+
const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
|
|
16706
|
+
logger.verbose(
|
|
16707
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
16538
16708
|
);
|
|
16539
|
-
|
|
16709
|
+
const swapInfo2 = {
|
|
16710
|
+
...swapInfo,
|
|
16711
|
+
token_from_amount: uint2564.bnToUint256(remainingAmount.toWei())
|
|
16712
|
+
};
|
|
16713
|
+
swapInfo2.token_to_address = token1Info.address.address;
|
|
16540
16714
|
logger.verbose(
|
|
16541
|
-
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16715
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16716
|
+
swapInfo
|
|
16717
|
+
)}`
|
|
16542
16718
|
);
|
|
16543
16719
|
logger.verbose(
|
|
16544
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16720
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
16721
|
+
swapInfo2
|
|
16722
|
+
)}`
|
|
16545
16723
|
);
|
|
16546
|
-
const
|
|
16547
|
-
|
|
16548
|
-
|
|
16549
|
-
|
|
16550
|
-
|
|
16551
|
-
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
|
|
16563
|
-
|
|
16564
|
-
|
|
16565
|
-
|
|
16566
|
-
|
|
16567
|
-
|
|
16568
|
-
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
16580
|
-
|
|
16581
|
-
|
|
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) => num5.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 {
|
|
16582
16816
|
const calldata = [
|
|
16583
16817
|
claim.rewardsContract.address,
|
|
16584
16818
|
{
|
|
@@ -16587,34 +16821,24 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16587
16821
|
claimee: claim.claim.claimee.address
|
|
16588
16822
|
},
|
|
16589
16823
|
claim.proof.map((p) => num5.getDecimalString(p)),
|
|
16590
|
-
|
|
16824
|
+
swapInfo1,
|
|
16591
16825
|
swapInfo2
|
|
16592
16826
|
];
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
);
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
|
|
16607
|
-
|
|
16608
|
-
// upper limit is the post fee amount
|
|
16609
|
-
);
|
|
16610
|
-
logger.verbose(
|
|
16611
|
-
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
16612
|
-
_callsFinal
|
|
16613
|
-
)}`
|
|
16614
|
-
);
|
|
16615
|
-
calls.push(..._callsFinal);
|
|
16616
|
-
}
|
|
16617
|
-
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;
|
|
16618
16842
|
}
|
|
16619
16843
|
async getInvestmentFlows() {
|
|
16620
16844
|
const netYield = await this.netAPY();
|
|
@@ -19146,7 +19370,58 @@ function toBigInt(value) {
|
|
|
19146
19370
|
}
|
|
19147
19371
|
|
|
19148
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 || {});
|
|
19149
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
|
+
// }
|
|
19150
19425
|
constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
|
|
19151
19426
|
const { id, target, method, packedArguments } = params;
|
|
19152
19427
|
return {
|
|
@@ -19164,6 +19439,94 @@ var BaseAdapter = class extends CacheClass {
|
|
|
19164
19439
|
]
|
|
19165
19440
|
};
|
|
19166
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
|
+
// }
|
|
19167
19530
|
};
|
|
19168
19531
|
|
|
19169
19532
|
// src/strategies/universal-adapters/common-adapter.ts
|
|
@@ -26766,7 +27129,20 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26766
27129
|
}
|
|
26767
27130
|
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
26768
27131
|
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
|
|
26769
|
-
|
|
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);
|
|
26770
27146
|
}
|
|
26771
27147
|
async getMaxBorrowableByInterestRate(config, asset, maxBorrowAPY) {
|
|
26772
27148
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
@@ -26799,16 +27175,17 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26799
27175
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
26800
27176
|
const timeDelta = assetConfig.last_updated;
|
|
26801
27177
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
26802
|
-
const
|
|
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));
|
|
26803
27180
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
26804
27181
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
26805
27182
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
26806
27183
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
26807
|
-
|
|
27184
|
+
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
26808
27185
|
return maxDebtToHave.minus(currentDebt);
|
|
26809
27186
|
}
|
|
26810
|
-
async getLTVConfig(config) {
|
|
26811
|
-
const CACHE_KEY =
|
|
27187
|
+
async getLTVConfig(config, blockNumber = "latest") {
|
|
27188
|
+
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
26812
27189
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26813
27190
|
if (cacheData) {
|
|
26814
27191
|
return cacheData;
|
|
@@ -26816,10 +27193,10 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26816
27193
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
26817
27194
|
let ltv = 0;
|
|
26818
27195
|
if (isV2) {
|
|
26819
|
-
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 });
|
|
26820
27197
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26821
27198
|
} else {
|
|
26822
|
-
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 });
|
|
26823
27200
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26824
27201
|
}
|
|
26825
27202
|
if (ltv == 0) {
|
|
@@ -26828,11 +27205,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26828
27205
|
this.setCache(CACHE_KEY, ltv, 3e5);
|
|
26829
27206
|
return this.getCache(CACHE_KEY);
|
|
26830
27207
|
}
|
|
26831
|
-
async getPositions(config) {
|
|
27208
|
+
async getPositions(config, blockNumber = "latest") {
|
|
26832
27209
|
if (!this.pricer) {
|
|
26833
27210
|
throw new Error("Pricer is not initialized");
|
|
26834
27211
|
}
|
|
26835
|
-
const CACHE_KEY =
|
|
27212
|
+
const CACHE_KEY = `positions_${blockNumber}`;
|
|
26836
27213
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26837
27214
|
if (cacheData) {
|
|
26838
27215
|
return cacheData;
|
|
@@ -26844,7 +27221,8 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26844
27221
|
this.config.collateral.address.address,
|
|
26845
27222
|
this.config.debt.address.address,
|
|
26846
27223
|
this.config.vaultAllocator.address
|
|
26847
|
-
]);
|
|
27224
|
+
], { blockIdentifier: blockNumber });
|
|
27225
|
+
console.log(output);
|
|
26848
27226
|
const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
|
|
26849
27227
|
const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
|
|
26850
27228
|
logger.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
|
|
@@ -26864,11 +27242,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26864
27242
|
this.setCache(CACHE_KEY, value, 6e4);
|
|
26865
27243
|
return value;
|
|
26866
27244
|
}
|
|
26867
|
-
async getCollateralization(config) {
|
|
27245
|
+
async getCollateralization(config, blockNumber = "latest") {
|
|
26868
27246
|
if (!this.pricer) {
|
|
26869
27247
|
throw new Error("Pricer is not initialized");
|
|
26870
27248
|
}
|
|
26871
|
-
const CACHE_KEY =
|
|
27249
|
+
const CACHE_KEY = `collateralization_${blockNumber}`;
|
|
26872
27250
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26873
27251
|
if (cacheData) {
|
|
26874
27252
|
return cacheData;
|
|
@@ -26880,7 +27258,7 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26880
27258
|
this.config.collateral.address.address,
|
|
26881
27259
|
this.config.debt.address.address,
|
|
26882
27260
|
this.config.vaultAllocator.address
|
|
26883
|
-
]);
|
|
27261
|
+
], { blockIdentifier: blockNumber });
|
|
26884
27262
|
const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
|
|
26885
27263
|
const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
|
|
26886
27264
|
const value = [{
|
|
@@ -26917,9 +27295,9 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26917
27295
|
ltv
|
|
26918
27296
|
};
|
|
26919
27297
|
}
|
|
26920
|
-
async getHealthFactor() {
|
|
26921
|
-
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
26922
|
-
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);
|
|
26923
27301
|
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
26924
27302
|
}
|
|
26925
27303
|
static async getVesuPools(retry = 0) {
|
|
@@ -29581,11 +29959,11 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29581
29959
|
vesuAdapter2.networkConfig = this.config;
|
|
29582
29960
|
return [vesuAdapter1, vesuAdapter2];
|
|
29583
29961
|
}
|
|
29584
|
-
async getVesuPositions() {
|
|
29962
|
+
async getVesuPositions(blockNumber = "latest") {
|
|
29585
29963
|
const adapters = this.getVesuAdapters();
|
|
29586
29964
|
const positions = [];
|
|
29587
29965
|
for (const adapter of adapters) {
|
|
29588
|
-
positions.push(...await adapter.getPositions(this.config));
|
|
29966
|
+
positions.push(...await adapter.getPositions(this.config, blockNumber));
|
|
29589
29967
|
}
|
|
29590
29968
|
return positions;
|
|
29591
29969
|
}
|
|
@@ -29654,8 +30032,8 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29654
30032
|
async getLSTAPR(address) {
|
|
29655
30033
|
return 0;
|
|
29656
30034
|
}
|
|
29657
|
-
async getVesuHealthFactors() {
|
|
29658
|
-
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)));
|
|
29659
30037
|
}
|
|
29660
30038
|
async computeRebalanceConditionAndReturnCalls() {
|
|
29661
30039
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -30251,6 +30629,42 @@ var UniversalStrategies = [
|
|
|
30251
30629
|
|
|
30252
30630
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30253
30631
|
import { Contract as Contract10, uint256 as uint2569 } from "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
|
|
30254
30668
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
30255
30669
|
var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
|
|
30256
30670
|
constructor(config, pricer, metadata) {
|
|
@@ -30265,15 +30679,14 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30265
30679
|
}
|
|
30266
30680
|
}
|
|
30267
30681
|
asset() {
|
|
30268
|
-
|
|
30269
|
-
return vesuAdapter1.config.collateral;
|
|
30682
|
+
return this.getVesuSameTokenAdapter().config.collateral;
|
|
30270
30683
|
}
|
|
30271
30684
|
getTag() {
|
|
30272
30685
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
30273
30686
|
}
|
|
30274
30687
|
// Vesu adapter with LST and base token match
|
|
30275
30688
|
getVesuSameTokenAdapter() {
|
|
30276
|
-
const baseAdapter = this.getAdapter("
|
|
30689
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
30277
30690
|
baseAdapter.networkConfig = this.config;
|
|
30278
30691
|
baseAdapter.pricer = this.pricer;
|
|
30279
30692
|
return baseAdapter;
|
|
@@ -30321,20 +30734,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30321
30734
|
return price;
|
|
30322
30735
|
}
|
|
30323
30736
|
async getAvnuSwapMultiplyCall(params) {
|
|
30324
|
-
|
|
30325
|
-
|
|
30326
|
-
|
|
30327
|
-
|
|
30328
|
-
|
|
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`);
|
|
30329
30774
|
}
|
|
30330
30775
|
async _getAvnuDepositSwapLegCall(params) {
|
|
30776
|
+
const { vesuAdapter } = params;
|
|
30331
30777
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
|
|
30332
30778
|
assert(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
|
|
30333
|
-
const
|
|
30334
|
-
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
30779
|
+
const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30335
30780
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
30336
|
-
const existingPositions = await
|
|
30337
|
-
const collateralisation = await
|
|
30781
|
+
const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
30782
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30338
30783
|
const existingCollateralInfo = existingPositions[0];
|
|
30339
30784
|
const existingDebtInfo = existingPositions[1];
|
|
30340
30785
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
@@ -30342,11 +30787,40 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30342
30787
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30343
30788
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30344
30789
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30790
|
+
const debtTokenInfo = vesuAdapter.config.debt;
|
|
30791
|
+
let newDepositAmount = params.leg1DepositAmount;
|
|
30345
30792
|
const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
|
|
30346
30793
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
|
|
30347
|
-
const totalDebtAmount =
|
|
30348
|
-
|
|
30349
|
-
|
|
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
|
+
}
|
|
30350
30824
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
30351
30825
|
if (debtAmount.lt(0)) {
|
|
30352
30826
|
const lstDEXPrice = await this.getLSTDexPrice();
|
|
@@ -30358,32 +30832,34 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30358
30832
|
assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
30359
30833
|
return calls[0];
|
|
30360
30834
|
}
|
|
30835
|
+
console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
|
|
30361
30836
|
const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
|
|
30362
30837
|
const manage0Info = this.getProofs(STEP0);
|
|
30363
30838
|
const manageCall0 = manage0Info.callConstructor({
|
|
30364
|
-
amount:
|
|
30839
|
+
amount: newDepositAmount
|
|
30365
30840
|
});
|
|
30366
|
-
const STEP1 = "vesu_leg1" /* VESU_LEG1
|
|
30841
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30367
30842
|
const manage1Info = this.getProofs(STEP1);
|
|
30368
30843
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30369
|
-
collateralAmount:
|
|
30844
|
+
collateralAmount: newDepositAmount,
|
|
30370
30845
|
isAddCollateral: params.isDeposit,
|
|
30371
30846
|
debtAmount,
|
|
30372
30847
|
isBorrow: params.isDeposit
|
|
30373
30848
|
}));
|
|
30849
|
+
console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
30374
30850
|
const proofIds = [STEP0, STEP1];
|
|
30375
30851
|
const manageCalls = [manageCall0, manageCall1];
|
|
30376
30852
|
if (debtAmount.gt(0)) {
|
|
30377
|
-
const STEP2 = "
|
|
30853
|
+
const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30378
30854
|
const manage2Info = this.getProofs(STEP2);
|
|
30379
30855
|
const manageCall2 = manage2Info.callConstructor({
|
|
30380
30856
|
amount: debtAmount
|
|
30381
30857
|
});
|
|
30382
|
-
const
|
|
30858
|
+
const debtTokenInfo2 = vesuAdapter.config.debt;
|
|
30383
30859
|
const lstTokenInfo = this.asset();
|
|
30384
30860
|
const avnuModule = new AvnuWrapper();
|
|
30385
30861
|
const quote = await avnuModule.getQuotes(
|
|
30386
|
-
|
|
30862
|
+
debtTokenInfo2.address.address,
|
|
30387
30863
|
lstTokenInfo.address.address,
|
|
30388
30864
|
debtAmount.toWei(),
|
|
30389
30865
|
this.metadata.additionalInfo.vaultAllocator.address
|
|
@@ -30399,7 +30875,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30399
30875
|
minAmountWei
|
|
30400
30876
|
);
|
|
30401
30877
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
|
|
30402
|
-
const STEP3 = "
|
|
30878
|
+
const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30403
30879
|
const manage3Info = this.getProofs(STEP3);
|
|
30404
30880
|
const manageCall3 = manage3Info.callConstructor({
|
|
30405
30881
|
props: swapInfo
|
|
@@ -30417,7 +30893,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30417
30893
|
const manageCall4 = manage4Info.callConstructor({
|
|
30418
30894
|
amount: minAmount
|
|
30419
30895
|
});
|
|
30420
|
-
const STEP5 = "vesu_leg1" /* VESU_LEG1
|
|
30896
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30421
30897
|
const manage5Info = this.getProofs(STEP5);
|
|
30422
30898
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30423
30899
|
collateralAmount: minAmount,
|
|
@@ -30434,28 +30910,41 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30434
30910
|
}
|
|
30435
30911
|
// todo unwind or not deposit when the yield is bad.
|
|
30436
30912
|
async getLSTMultiplierRebalanceCall() {
|
|
30437
|
-
|
|
30438
|
-
|
|
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");
|
|
30439
30928
|
const existingCollateralInfo = positions[0];
|
|
30440
30929
|
const existingDebtInfo = positions[1];
|
|
30441
|
-
const unusedBalance =
|
|
30442
|
-
const
|
|
30443
|
-
const
|
|
30444
|
-
|
|
30445
|
-
const collateralisation = await vesuAdapter1.getCollateralization(this.config);
|
|
30446
|
-
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)},
|
|
30447
30934
|
existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
30448
30935
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30449
30936
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30450
30937
|
logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30938
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
|
|
30451
30939
|
const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
30452
30940
|
const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
30453
|
-
if (isHFTooLow || isHFTooHigh) {
|
|
30941
|
+
if (isHFTooLow || isHFTooHigh || 1) {
|
|
30454
30942
|
const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
30455
30943
|
isDeposit: true,
|
|
30456
30944
|
leg1DepositAmount: unusedBalance.amount,
|
|
30457
|
-
minHF: 1.02
|
|
30945
|
+
minHF: 1.02,
|
|
30458
30946
|
// todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
30947
|
+
vesuAdapter
|
|
30459
30948
|
});
|
|
30460
30949
|
return { shouldRebalance: true, manageCall };
|
|
30461
30950
|
} else {
|
|
@@ -30488,7 +30977,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30488
30977
|
async _getMinOutputAmountLSTBuy(amountInUnderlying) {
|
|
30489
30978
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
30490
30979
|
const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
|
|
30491
|
-
return minOutputAmount;
|
|
30980
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
30492
30981
|
}
|
|
30493
30982
|
async _getMinOutputAmountLSTSell(amountInLST) {
|
|
30494
30983
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
@@ -30545,21 +31034,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30545
31034
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
30546
31035
|
return vesuAdapter1.config.debt;
|
|
30547
31036
|
}
|
|
30548
|
-
async getMaxBorrowableAmount() {
|
|
31037
|
+
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
30549
31038
|
const vesuAdapters = this.getVesuAdapters();
|
|
30550
31039
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
30551
31040
|
const maxBorrowables = [];
|
|
30552
|
-
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30553
|
-
const maxInterestRate = lstAPY * 0.8;
|
|
30554
31041
|
for (const vesuAdapter of vesuAdapters) {
|
|
30555
|
-
|
|
30556
|
-
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
30557
|
-
maxBorrowables.push({ amount: maxBorrowableAmount.minimum(debtCap), borrowableAsset: vesuAdapter.config.debt });
|
|
31042
|
+
maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
|
|
30558
31043
|
}
|
|
30559
31044
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
30560
31045
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
30561
31046
|
return { netMaxBorrowableAmount, maxBorrowables };
|
|
30562
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
|
+
}
|
|
30563
31083
|
// todo how much to unwind to get back healthy APY zone again
|
|
30564
31084
|
// if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
|
|
30565
31085
|
// For xSTRK, simply deposit in Vesu if looping is not viable
|
|
@@ -30583,7 +31103,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30583
31103
|
// todo undo this
|
|
30584
31104
|
async netAPY() {
|
|
30585
31105
|
const unusedBalance = await this.getUnusedBalance();
|
|
30586
|
-
const maxNewDeposits = await this.maxNewDeposits();
|
|
31106
|
+
const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
30587
31107
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30588
31108
|
if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
30589
31109
|
logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
|
|
@@ -30600,8 +31120,8 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30600
31120
|
return output;
|
|
30601
31121
|
}
|
|
30602
31122
|
}
|
|
30603
|
-
async maxNewDeposits() {
|
|
30604
|
-
const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
|
|
31123
|
+
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
31124
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
30605
31125
|
let ltv = void 0;
|
|
30606
31126
|
for (let adapter of this.getVesuAdapters()) {
|
|
30607
31127
|
const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
|
|
@@ -30704,7 +31224,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30704
31224
|
const manageCall2 = manage2Info.callConstructor({
|
|
30705
31225
|
delegation: true
|
|
30706
31226
|
});
|
|
30707
|
-
const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU
|
|
31227
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
30708
31228
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
30709
31229
|
const multiplyParams = params.isIncrease ? {
|
|
30710
31230
|
isIncrease: true,
|
|
@@ -30788,6 +31308,12 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
|
|
|
30788
31308
|
function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
30789
31309
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
30790
31310
|
}
|
|
31311
|
+
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
31312
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31313
|
+
}
|
|
31314
|
+
function getVesuLegId(baseID, debtTokenSymbol) {
|
|
31315
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31316
|
+
}
|
|
30791
31317
|
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
30792
31318
|
vaultSettings.leafAdapters = [];
|
|
30793
31319
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
@@ -30797,7 +31323,7 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30797
31323
|
collateral: lstToken,
|
|
30798
31324
|
debt: underlyingToken,
|
|
30799
31325
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
30800
|
-
id: "vesu_leg1" /* VESU_LEG1
|
|
31326
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
30801
31327
|
});
|
|
30802
31328
|
const commonAdapter = new CommonAdapter({
|
|
30803
31329
|
manager: vaultSettings.manager,
|
|
@@ -30806,25 +31332,39 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30806
31332
|
vaultAddress: vaultSettings.vaultAddress,
|
|
30807
31333
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
30808
31334
|
});
|
|
30809
|
-
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
30810
|
-
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
30811
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
30812
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter("multiply_vesu" /* MULTIPLY_VESU */).bind(vesuAdapterLST));
|
|
30813
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
30814
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
30815
31335
|
vaultSettings.adapters.push(...[{
|
|
30816
|
-
id: "
|
|
31336
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
30817
31337
|
adapter: vesuAdapterLST
|
|
30818
31338
|
}, {
|
|
30819
31339
|
id: "common_adapter" /* COMMON */,
|
|
30820
31340
|
adapter: commonAdapter
|
|
30821
31341
|
}]);
|
|
30822
|
-
|
|
30823
|
-
|
|
30824
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address,
|
|
30825
|
-
vaultSettings.leafAdapters.push(
|
|
30826
|
-
vaultSettings.leafAdapters.push(
|
|
30827
|
-
vaultSettings.leafAdapters.push(
|
|
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
|
+
}
|
|
30828
31368
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30829
31369
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30830
31370
|
vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
|
|
@@ -30902,7 +31442,8 @@ var hyperxSTRK = {
|
|
|
30902
31442
|
adapters: [],
|
|
30903
31443
|
targetHealthFactor: 1.1,
|
|
30904
31444
|
minHealthFactor: 1.05,
|
|
30905
|
-
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")
|
|
30906
31447
|
};
|
|
30907
31448
|
var hyperxWBTC = {
|
|
30908
31449
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -30914,7 +31455,8 @@ var hyperxWBTC = {
|
|
|
30914
31455
|
adapters: [],
|
|
30915
31456
|
targetHealthFactor: 1.1,
|
|
30916
31457
|
minHealthFactor: 1.05,
|
|
30917
|
-
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")
|
|
30918
31460
|
};
|
|
30919
31461
|
var hyperxtBTC = {
|
|
30920
31462
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -30926,7 +31468,8 @@ var hyperxtBTC = {
|
|
|
30926
31468
|
adapters: [],
|
|
30927
31469
|
targetHealthFactor: 1.1,
|
|
30928
31470
|
minHealthFactor: 1.05,
|
|
30929
|
-
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")
|
|
30930
31473
|
};
|
|
30931
31474
|
var hyperxsBTC = {
|
|
30932
31475
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -30938,7 +31481,8 @@ var hyperxsBTC = {
|
|
|
30938
31481
|
adapters: [],
|
|
30939
31482
|
targetHealthFactor: 1.1,
|
|
30940
31483
|
minHealthFactor: 1.05,
|
|
30941
|
-
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")
|
|
30942
31486
|
};
|
|
30943
31487
|
var hyperxLBTC = {
|
|
30944
31488
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -30950,7 +31494,8 @@ var hyperxLBTC = {
|
|
|
30950
31494
|
adapters: [],
|
|
30951
31495
|
targetHealthFactor: 1.1,
|
|
30952
31496
|
minHealthFactor: 1.05,
|
|
30953
|
-
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")
|
|
30954
31499
|
};
|
|
30955
31500
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
30956
31501
|
return [
|
|
@@ -30993,6 +31538,7 @@ var HyperLSTStrategies = [
|
|
|
30993
31538
|
getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false)
|
|
30994
31539
|
];
|
|
30995
31540
|
export {
|
|
31541
|
+
APYType,
|
|
30996
31542
|
AUMTypes,
|
|
30997
31543
|
AVNU_EXCHANGE,
|
|
30998
31544
|
AVNU_MIDDLEWARE,
|