@strkfarm/sdk 1.1.39 → 1.1.41
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 +722 -186
- package/dist/index.browser.mjs +721 -183
- package/dist/index.d.ts +126 -13
- package/dist/index.js +722 -183
- package/dist/index.mjs +721 -183
- 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 +254 -86
- 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 {
|
|
@@ -15687,7 +15790,6 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
15687
15790
|
for (let i = len - 1; i >= 0; --i) {
|
|
15688
15791
|
let record = await this.contract.call("get_rewards_info", [i]);
|
|
15689
15792
|
logger.verbose(`${_EkuboCLVault.name}: getHarvestRewardShares: ${i}`);
|
|
15690
|
-
console.log(record);
|
|
15691
15793
|
const block = Number(record.block_number);
|
|
15692
15794
|
if (block < fromBlock) {
|
|
15693
15795
|
return shares;
|
|
@@ -15887,16 +15989,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
15887
15989
|
const sqrtRatio = _EkuboCLVault.div2Power128(
|
|
15888
15990
|
BigInt(priceInfo.sqrt_ratio.toString())
|
|
15889
15991
|
);
|
|
15890
|
-
console.log(
|
|
15891
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, sqrtRatio: ${sqrtRatio}, ${priceInfo.sqrt_ratio.toString()}`
|
|
15892
|
-
);
|
|
15893
15992
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
15894
15993
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
15895
15994
|
const price = sqrtRatio * sqrtRatio * 10 ** token0Info.decimals / 10 ** token1Info.decimals;
|
|
15896
15995
|
const tick = priceInfo.tick;
|
|
15897
|
-
console.log(
|
|
15898
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, price: ${price}, tick: ${tick.mag}, ${tick.sign}`
|
|
15899
|
-
);
|
|
15900
15996
|
return {
|
|
15901
15997
|
price,
|
|
15902
15998
|
tick: Number(tick.mag) * (tick.sign ? -1 : 1),
|
|
@@ -16523,62 +16619,193 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16523
16619
|
logger.verbose(
|
|
16524
16620
|
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
16525
16621
|
);
|
|
16526
|
-
const
|
|
16527
|
-
|
|
16622
|
+
const isRewardTokenMatch = claim.token.eq(poolKey.token0) || claim.token.eq(poolKey.token1);
|
|
16623
|
+
if (isRewardTokenMatch) {
|
|
16624
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMatchHarvest({
|
|
16625
|
+
acc,
|
|
16626
|
+
claim,
|
|
16627
|
+
isToken1,
|
|
16628
|
+
token0Info,
|
|
16629
|
+
token1Info,
|
|
16630
|
+
postFeeAmount,
|
|
16631
|
+
poolKey,
|
|
16632
|
+
bounds,
|
|
16633
|
+
maxIterations,
|
|
16634
|
+
priceRatioPrecision
|
|
16635
|
+
});
|
|
16636
|
+
calls.push(..._callsFinal);
|
|
16637
|
+
} else {
|
|
16638
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMismatchHarvest({
|
|
16639
|
+
claim,
|
|
16640
|
+
token0Info,
|
|
16641
|
+
token1Info,
|
|
16642
|
+
postFeeAmount,
|
|
16643
|
+
poolKey,
|
|
16644
|
+
bounds,
|
|
16645
|
+
maxIterations,
|
|
16646
|
+
priceRatioPrecision,
|
|
16647
|
+
acc
|
|
16648
|
+
});
|
|
16649
|
+
calls.push(..._callsFinal);
|
|
16650
|
+
}
|
|
16651
|
+
}
|
|
16652
|
+
return calls;
|
|
16653
|
+
}
|
|
16654
|
+
/**
|
|
16655
|
+
* @description This funciton requires atleast one of the pool tokens to be reward token
|
|
16656
|
+
* i.e. STRK.
|
|
16657
|
+
* @param params
|
|
16658
|
+
*/
|
|
16659
|
+
async _handleRewardAndVaultTokenMatchHarvest(params) {
|
|
16660
|
+
const { acc, claim, isToken1, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
16661
|
+
const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
|
|
16662
|
+
const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
|
|
16663
|
+
logger.verbose(
|
|
16664
|
+
`${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
|
|
16665
|
+
);
|
|
16666
|
+
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
16667
|
+
poolKey,
|
|
16668
|
+
token0Amt,
|
|
16669
|
+
token1Amt,
|
|
16670
|
+
bounds,
|
|
16671
|
+
maxIterations,
|
|
16672
|
+
priceRatioPrecision
|
|
16673
|
+
);
|
|
16674
|
+
swapInfo.token_to_address = token0Info.address.address;
|
|
16675
|
+
logger.verbose(
|
|
16676
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
16677
|
+
);
|
|
16678
|
+
logger.verbose(
|
|
16679
|
+
`${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
16680
|
+
);
|
|
16681
|
+
const harvestEstimateCall = async (swapInfo1) => {
|
|
16682
|
+
const swap1Amount = Web3Number.fromWei(
|
|
16683
|
+
uint2564.uint256ToBN(swapInfo1.token_from_amount).toString(),
|
|
16684
|
+
18
|
|
16685
|
+
// cause its always STRK?
|
|
16686
|
+
).minimum(
|
|
16687
|
+
postFeeAmount.toFixed(18)
|
|
16688
|
+
// cause always strk
|
|
16689
|
+
);
|
|
16690
|
+
swapInfo.token_from_amount = uint2564.bnToUint256(swap1Amount.toWei());
|
|
16691
|
+
swapInfo.token_to_min_amount = uint2564.bnToUint256(
|
|
16692
|
+
swap1Amount.multipliedBy(0).toWei()
|
|
16693
|
+
// placeholder
|
|
16694
|
+
);
|
|
16528
16695
|
logger.verbose(
|
|
16529
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16696
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
16530
16697
|
);
|
|
16531
|
-
const
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
token1Amt,
|
|
16535
|
-
bounds,
|
|
16536
|
-
maxIterations,
|
|
16537
|
-
priceRatioPrecision
|
|
16698
|
+
const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
|
|
16699
|
+
logger.verbose(
|
|
16700
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
16538
16701
|
);
|
|
16539
|
-
|
|
16702
|
+
const swapInfo2 = {
|
|
16703
|
+
...swapInfo,
|
|
16704
|
+
token_from_amount: uint2564.bnToUint256(remainingAmount.toWei())
|
|
16705
|
+
};
|
|
16706
|
+
swapInfo2.token_to_address = token1Info.address.address;
|
|
16540
16707
|
logger.verbose(
|
|
16541
|
-
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16708
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16709
|
+
swapInfo
|
|
16710
|
+
)}`
|
|
16542
16711
|
);
|
|
16543
16712
|
logger.verbose(
|
|
16544
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16713
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
16714
|
+
swapInfo2
|
|
16715
|
+
)}`
|
|
16545
16716
|
);
|
|
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
|
-
|
|
16717
|
+
const calldata = [
|
|
16718
|
+
claim.rewardsContract.address,
|
|
16719
|
+
{
|
|
16720
|
+
id: claim.claim.id,
|
|
16721
|
+
amount: claim.claim.amount.toWei(),
|
|
16722
|
+
claimee: claim.claim.claimee.address
|
|
16723
|
+
},
|
|
16724
|
+
claim.proof.map((p) => num5.getDecimalString(p)),
|
|
16725
|
+
swapInfo,
|
|
16726
|
+
swapInfo2
|
|
16727
|
+
];
|
|
16728
|
+
logger.verbose(
|
|
16729
|
+
`${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
16730
|
+
calldata
|
|
16731
|
+
)}`
|
|
16732
|
+
);
|
|
16733
|
+
return [this.contract.populate("harvest", calldata)];
|
|
16734
|
+
};
|
|
16735
|
+
const _callsFinal = await this.rebalanceIter(
|
|
16736
|
+
swapInfo,
|
|
16737
|
+
acc,
|
|
16738
|
+
harvestEstimateCall,
|
|
16739
|
+
claim.token.eq(poolKey.token0),
|
|
16740
|
+
0,
|
|
16741
|
+
0n,
|
|
16742
|
+
BigInt(postFeeAmount.toWei())
|
|
16743
|
+
// upper limit is the post fee amount
|
|
16744
|
+
);
|
|
16745
|
+
logger.verbose(
|
|
16746
|
+
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
16747
|
+
_callsFinal
|
|
16748
|
+
)}`
|
|
16749
|
+
);
|
|
16750
|
+
return _callsFinal;
|
|
16751
|
+
}
|
|
16752
|
+
/**
|
|
16753
|
+
* @description This function handles harvesting of reward token that is not the same as any of the vault token
|
|
16754
|
+
* i.e. STRK is not part of vault tokens like BTC/ETH
|
|
16755
|
+
* @param params
|
|
16756
|
+
* @returns
|
|
16757
|
+
*/
|
|
16758
|
+
async _handleRewardAndVaultTokenMismatchHarvest(params) {
|
|
16759
|
+
const { acc, claim, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
16760
|
+
let token0Amt = postFeeAmount;
|
|
16761
|
+
const beneficiary = this.address.address;
|
|
16762
|
+
let harvestCall = null;
|
|
16763
|
+
harvestCall = await this.harvestMismatchEstimateCallFn({
|
|
16764
|
+
postFeeAmount,
|
|
16765
|
+
claim,
|
|
16766
|
+
token0Info,
|
|
16767
|
+
token1Info,
|
|
16768
|
+
acc
|
|
16769
|
+
});
|
|
16770
|
+
if (!harvestCall) {
|
|
16771
|
+
throw new Error("Harvest call not found");
|
|
16772
|
+
}
|
|
16773
|
+
return [harvestCall];
|
|
16774
|
+
}
|
|
16775
|
+
// given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
|
|
16776
|
+
// amount for binary search
|
|
16777
|
+
async harvestMismatchEstimateCallFn(params) {
|
|
16778
|
+
const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
|
|
16779
|
+
let harvestCall = null;
|
|
16780
|
+
const binarySearchCallbackFn = async (mid) => {
|
|
16781
|
+
const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
|
|
16782
|
+
const avnuWrapper = new AvnuWrapper();
|
|
16783
|
+
const beneficiary = this.address.address;
|
|
16784
|
+
const quote1 = await avnuWrapper.getQuotes(
|
|
16785
|
+
claim.token.address,
|
|
16786
|
+
token0Info.address.address,
|
|
16787
|
+
mid.toString(),
|
|
16788
|
+
beneficiary
|
|
16789
|
+
);
|
|
16790
|
+
const swapInfo1 = await avnuWrapper.getSwapInfo(
|
|
16791
|
+
quote1,
|
|
16792
|
+
beneficiary,
|
|
16793
|
+
0,
|
|
16794
|
+
beneficiary
|
|
16795
|
+
);
|
|
16796
|
+
const quote2 = await avnuWrapper.getQuotes(
|
|
16797
|
+
claim.token.address,
|
|
16798
|
+
token1Info.address.address,
|
|
16799
|
+
rewardPart2.toString(),
|
|
16800
|
+
beneficiary
|
|
16801
|
+
);
|
|
16802
|
+
const swapInfo2 = await avnuWrapper.getSwapInfo(
|
|
16803
|
+
quote2,
|
|
16804
|
+
beneficiary,
|
|
16805
|
+
0,
|
|
16806
|
+
beneficiary
|
|
16807
|
+
);
|
|
16808
|
+
try {
|
|
16582
16809
|
const calldata = [
|
|
16583
16810
|
claim.rewardsContract.address,
|
|
16584
16811
|
{
|
|
@@ -16587,34 +16814,23 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16587
16814
|
claimee: claim.claim.claimee.address
|
|
16588
16815
|
},
|
|
16589
16816
|
claim.proof.map((p) => num5.getDecimalString(p)),
|
|
16590
|
-
|
|
16817
|
+
swapInfo1,
|
|
16591
16818
|
swapInfo2
|
|
16592
16819
|
];
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
)
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
|
|
16607
|
-
BigInt(postFeeAmount.toWei())
|
|
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;
|
|
16820
|
+
harvestCall = this.contract.populate("harvest", calldata);
|
|
16821
|
+
const gas = await acc.estimateInvokeFee(harvestCall);
|
|
16822
|
+
return "found";
|
|
16823
|
+
} catch (err) {
|
|
16824
|
+
if (err.message.includes("invalid token0 amount")) {
|
|
16825
|
+
return "go_low";
|
|
16826
|
+
} else if (err.message.includes("invalid token1 amount")) {
|
|
16827
|
+
return "go_high";
|
|
16828
|
+
}
|
|
16829
|
+
return "retry";
|
|
16830
|
+
}
|
|
16831
|
+
};
|
|
16832
|
+
await binarySearch(0n, BigInt(postFeeAmount.toWei()), binarySearchCallbackFn);
|
|
16833
|
+
return harvestCall;
|
|
16618
16834
|
}
|
|
16619
16835
|
async getInvestmentFlows() {
|
|
16620
16836
|
const netYield = await this.netAPY();
|
|
@@ -19146,7 +19362,58 @@ function toBigInt(value) {
|
|
|
19146
19362
|
}
|
|
19147
19363
|
|
|
19148
19364
|
// src/strategies/universal-adapters/baseAdapter.ts
|
|
19365
|
+
var APYType = /* @__PURE__ */ ((APYType2) => {
|
|
19366
|
+
APYType2["BASE"] = "base";
|
|
19367
|
+
APYType2["REWARD"] = "reward";
|
|
19368
|
+
APYType2["LST"] = "lst";
|
|
19369
|
+
return APYType2;
|
|
19370
|
+
})(APYType || {});
|
|
19149
19371
|
var BaseAdapter = class extends CacheClass {
|
|
19372
|
+
// readonly config: BaseAdapterConfig;
|
|
19373
|
+
// constructor(config: BaseAdapterConfig) {
|
|
19374
|
+
// super();
|
|
19375
|
+
// this.config = config;
|
|
19376
|
+
// }
|
|
19377
|
+
constructor() {
|
|
19378
|
+
super();
|
|
19379
|
+
}
|
|
19380
|
+
// /**
|
|
19381
|
+
// * Loop through all supported positions and return amount, usd value, remarks and apy for each
|
|
19382
|
+
// */
|
|
19383
|
+
// async getPositions(): Promise<PositionInfo[]> {
|
|
19384
|
+
// const results: PositionInfo[] = [];
|
|
19385
|
+
// for (const supported of this.config.supportedPositions) {
|
|
19386
|
+
// const amount = await this.getPosition(supported);
|
|
19387
|
+
// const usdValue = await this.getUSDValue(supported.asset, amount);
|
|
19388
|
+
// const apy = await this.getAPY(supported);
|
|
19389
|
+
// results.push({ amount, usdValue, apy });
|
|
19390
|
+
// }
|
|
19391
|
+
// return results;
|
|
19392
|
+
// }
|
|
19393
|
+
// /**
|
|
19394
|
+
// * Implemented by child adapters to compute APY for a given supported position
|
|
19395
|
+
// */
|
|
19396
|
+
// protected abstract getAPY(supportedPosition: SupportedPosition): Promise<PositionAPY>;
|
|
19397
|
+
// /**
|
|
19398
|
+
// * Implemented by child adapters to fetch amount for a given supported position
|
|
19399
|
+
// */
|
|
19400
|
+
// protected abstract getPosition(supportedPosition: SupportedPosition): Promise<Web3Number>;
|
|
19401
|
+
// /**
|
|
19402
|
+
// * Implemented by child adapters to calculate maximum deposit positions
|
|
19403
|
+
// * @param amount Optional amount in baseToken to deposit
|
|
19404
|
+
// */
|
|
19405
|
+
// protected abstract maxDeposit(amount?: Web3Number): Promise<PositionInfo[]>;
|
|
19406
|
+
// /**
|
|
19407
|
+
// * Implemented by child adapters to calculate maximum withdraw positions
|
|
19408
|
+
// */
|
|
19409
|
+
// protected abstract maxWithdraw(): Promise<PositionInfo[]>;
|
|
19410
|
+
// /**
|
|
19411
|
+
// * Uses pricer to convert an amount of an asset to USD value
|
|
19412
|
+
// */
|
|
19413
|
+
// protected async getUSDValue(asset: TokenInfo, amount: Web3Number): Promise<number> {
|
|
19414
|
+
// const priceInfo = await this.config.pricer.getPrice(asset.symbol);
|
|
19415
|
+
// return amount.toNumber() * priceInfo.price;
|
|
19416
|
+
// }
|
|
19150
19417
|
constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
|
|
19151
19418
|
const { id, target, method, packedArguments } = params;
|
|
19152
19419
|
return {
|
|
@@ -19164,6 +19431,94 @@ var BaseAdapter = class extends CacheClass {
|
|
|
19164
19431
|
]
|
|
19165
19432
|
};
|
|
19166
19433
|
}
|
|
19434
|
+
// /**
|
|
19435
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for deposit leaf construction
|
|
19436
|
+
// */
|
|
19437
|
+
// protected abstract _getDepositLeaf(): {
|
|
19438
|
+
// target: ContractAddr,
|
|
19439
|
+
// method: string,
|
|
19440
|
+
// packedArguments: bigint[],
|
|
19441
|
+
// sanitizer: ContractAddr,
|
|
19442
|
+
// id: string
|
|
19443
|
+
// }[];
|
|
19444
|
+
// /**
|
|
19445
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for withdraw leaf construction
|
|
19446
|
+
// */
|
|
19447
|
+
// protected abstract _getWithdrawLeaf(): {
|
|
19448
|
+
// target: ContractAddr,
|
|
19449
|
+
// method: string,
|
|
19450
|
+
// packedArguments: bigint[],
|
|
19451
|
+
// sanitizer: ContractAddr,
|
|
19452
|
+
// id: string
|
|
19453
|
+
// }[];
|
|
19454
|
+
// /**
|
|
19455
|
+
// * Returns deposit leaf adapter using configured proof id
|
|
19456
|
+
// */
|
|
19457
|
+
// getDepositLeaf(): AdapterLeafType<T1> {
|
|
19458
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
19459
|
+
// const leaves = leafConfigs.map(config => {
|
|
19460
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
19461
|
+
// const leaf = this.constructSimpleLeafData({
|
|
19462
|
+
// id: id,
|
|
19463
|
+
// target,
|
|
19464
|
+
// method,
|
|
19465
|
+
// packedArguments
|
|
19466
|
+
// }, sanitizer);
|
|
19467
|
+
// return leaf;
|
|
19468
|
+
// });
|
|
19469
|
+
// return { leaves, callConstructor: this.getDepositCall.bind(this) as unknown as GenerateCallFn<T1> };
|
|
19470
|
+
// }
|
|
19471
|
+
// /**
|
|
19472
|
+
// * Returns withdraw leaf adapter using configured proof id
|
|
19473
|
+
// */
|
|
19474
|
+
// getWithdrawLeaf(): AdapterLeafType<T2> {
|
|
19475
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
19476
|
+
// const leaves = leafConfigs.map(config => {
|
|
19477
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
19478
|
+
// const leaf = this.constructSimpleLeafData({
|
|
19479
|
+
// id: id,
|
|
19480
|
+
// target,
|
|
19481
|
+
// method,
|
|
19482
|
+
// packedArguments
|
|
19483
|
+
// }, sanitizer ?? SIMPLE_SANITIZER);
|
|
19484
|
+
// return leaf;
|
|
19485
|
+
// });
|
|
19486
|
+
// return { leaves, callConstructor: this.getWithdrawCall.bind(this) as unknown as GenerateCallFn<T2> };
|
|
19487
|
+
// }
|
|
19488
|
+
// /**
|
|
19489
|
+
// * Default deposit callConstructor: expects params as calldata (bigint[])
|
|
19490
|
+
// */
|
|
19491
|
+
// protected getDepositCall<T1 = bigint[]>(params: T1): ManageCall[] {
|
|
19492
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
19493
|
+
// return leafConfigs.map(config => {
|
|
19494
|
+
// const { target, method, sanitizer } = config;
|
|
19495
|
+
// return {
|
|
19496
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
19497
|
+
// call: {
|
|
19498
|
+
// contractAddress: target,
|
|
19499
|
+
// selector: hash.getSelectorFromName(method),
|
|
19500
|
+
// calldata: params as unknown as bigint[]
|
|
19501
|
+
// }
|
|
19502
|
+
// };
|
|
19503
|
+
// });
|
|
19504
|
+
// }
|
|
19505
|
+
// /**
|
|
19506
|
+
// * Default withdraw callConstructor: expects params as calldata (bigint[])
|
|
19507
|
+
// */
|
|
19508
|
+
// protected getWithdrawCall<T2 = bigint[]>(params: T2): ManageCall[] {
|
|
19509
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
19510
|
+
// return leafConfigs.map(config => {
|
|
19511
|
+
// const { target, method, sanitizer } = config;
|
|
19512
|
+
// return {
|
|
19513
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
19514
|
+
// call: {
|
|
19515
|
+
// contractAddress: target,
|
|
19516
|
+
// selector: hash.getSelectorFromName(method),
|
|
19517
|
+
// calldata: params as unknown as bigint[]
|
|
19518
|
+
// }
|
|
19519
|
+
// };
|
|
19520
|
+
// });
|
|
19521
|
+
// }
|
|
19167
19522
|
};
|
|
19168
19523
|
|
|
19169
19524
|
// src/strategies/universal-adapters/common-adapter.ts
|
|
@@ -26766,7 +27121,20 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26766
27121
|
}
|
|
26767
27122
|
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
26768
27123
|
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
|
|
26769
|
-
|
|
27124
|
+
if (!isV2) {
|
|
27125
|
+
throw new Error("getDebtCap is not supported for v1");
|
|
27126
|
+
}
|
|
27127
|
+
const currentDebt = await this.getCurrentDebtUtilisationAmount(config);
|
|
27128
|
+
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap currentDebt: ${currentDebt.toString()}`);
|
|
27129
|
+
return Web3Number.fromWei(output.debt_cap.toString(), this.config.debt.decimals).minus(currentDebt);
|
|
27130
|
+
}
|
|
27131
|
+
async getCurrentDebtUtilisationAmount(config) {
|
|
27132
|
+
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
27133
|
+
if (!isV2) {
|
|
27134
|
+
throw new Error("getCurrentDebtUtilisationAmount is not supported for v1");
|
|
27135
|
+
}
|
|
27136
|
+
const output = await contract.call("pairs", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27137
|
+
return new Web3Number((Number(output.total_nominal_debt) / 1e18).toFixed(9), this.config.debt.decimals);
|
|
26770
27138
|
}
|
|
26771
27139
|
async getMaxBorrowableByInterestRate(config, asset, maxBorrowAPY) {
|
|
26772
27140
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
@@ -26799,16 +27167,17 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26799
27167
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
26800
27168
|
const timeDelta = assetConfig.last_updated;
|
|
26801
27169
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
26802
|
-
const
|
|
27170
|
+
const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals);
|
|
27171
|
+
const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
|
|
26803
27172
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
26804
27173
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
26805
27174
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
26806
27175
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
26807
|
-
|
|
27176
|
+
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
26808
27177
|
return maxDebtToHave.minus(currentDebt);
|
|
26809
27178
|
}
|
|
26810
|
-
async getLTVConfig(config) {
|
|
26811
|
-
const CACHE_KEY =
|
|
27179
|
+
async getLTVConfig(config, blockNumber = "latest") {
|
|
27180
|
+
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
26812
27181
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26813
27182
|
if (cacheData) {
|
|
26814
27183
|
return cacheData;
|
|
@@ -26816,10 +27185,10 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26816
27185
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
26817
27186
|
let ltv = 0;
|
|
26818
27187
|
if (isV2) {
|
|
26819
|
-
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27188
|
+
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
26820
27189
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26821
27190
|
} else {
|
|
26822
|
-
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27191
|
+
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
26823
27192
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26824
27193
|
}
|
|
26825
27194
|
if (ltv == 0) {
|
|
@@ -26828,11 +27197,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26828
27197
|
this.setCache(CACHE_KEY, ltv, 3e5);
|
|
26829
27198
|
return this.getCache(CACHE_KEY);
|
|
26830
27199
|
}
|
|
26831
|
-
async getPositions(config) {
|
|
27200
|
+
async getPositions(config, blockNumber = "latest") {
|
|
26832
27201
|
if (!this.pricer) {
|
|
26833
27202
|
throw new Error("Pricer is not initialized");
|
|
26834
27203
|
}
|
|
26835
|
-
const CACHE_KEY =
|
|
27204
|
+
const CACHE_KEY = `positions_${blockNumber}`;
|
|
26836
27205
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26837
27206
|
if (cacheData) {
|
|
26838
27207
|
return cacheData;
|
|
@@ -26844,7 +27213,8 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26844
27213
|
this.config.collateral.address.address,
|
|
26845
27214
|
this.config.debt.address.address,
|
|
26846
27215
|
this.config.vaultAllocator.address
|
|
26847
|
-
]);
|
|
27216
|
+
], { blockIdentifier: blockNumber });
|
|
27217
|
+
console.log(output);
|
|
26848
27218
|
const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
|
|
26849
27219
|
const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
|
|
26850
27220
|
logger.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
|
|
@@ -26864,11 +27234,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26864
27234
|
this.setCache(CACHE_KEY, value, 6e4);
|
|
26865
27235
|
return value;
|
|
26866
27236
|
}
|
|
26867
|
-
async getCollateralization(config) {
|
|
27237
|
+
async getCollateralization(config, blockNumber = "latest") {
|
|
26868
27238
|
if (!this.pricer) {
|
|
26869
27239
|
throw new Error("Pricer is not initialized");
|
|
26870
27240
|
}
|
|
26871
|
-
const CACHE_KEY =
|
|
27241
|
+
const CACHE_KEY = `collateralization_${blockNumber}`;
|
|
26872
27242
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26873
27243
|
if (cacheData) {
|
|
26874
27244
|
return cacheData;
|
|
@@ -26880,7 +27250,7 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26880
27250
|
this.config.collateral.address.address,
|
|
26881
27251
|
this.config.debt.address.address,
|
|
26882
27252
|
this.config.vaultAllocator.address
|
|
26883
|
-
]);
|
|
27253
|
+
], { blockIdentifier: blockNumber });
|
|
26884
27254
|
const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
|
|
26885
27255
|
const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
|
|
26886
27256
|
const value = [{
|
|
@@ -26917,9 +27287,9 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26917
27287
|
ltv
|
|
26918
27288
|
};
|
|
26919
27289
|
}
|
|
26920
|
-
async getHealthFactor() {
|
|
26921
|
-
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
26922
|
-
const collateralisation = await this.getCollateralization(this.networkConfig);
|
|
27290
|
+
async getHealthFactor(blockNumber = "latest") {
|
|
27291
|
+
const ltv = await this.getLTVConfig(this.networkConfig, blockNumber);
|
|
27292
|
+
const collateralisation = await this.getCollateralization(this.networkConfig, blockNumber);
|
|
26923
27293
|
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
26924
27294
|
}
|
|
26925
27295
|
static async getVesuPools(retry = 0) {
|
|
@@ -29581,11 +29951,11 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29581
29951
|
vesuAdapter2.networkConfig = this.config;
|
|
29582
29952
|
return [vesuAdapter1, vesuAdapter2];
|
|
29583
29953
|
}
|
|
29584
|
-
async getVesuPositions() {
|
|
29954
|
+
async getVesuPositions(blockNumber = "latest") {
|
|
29585
29955
|
const adapters = this.getVesuAdapters();
|
|
29586
29956
|
const positions = [];
|
|
29587
29957
|
for (const adapter of adapters) {
|
|
29588
|
-
positions.push(...await adapter.getPositions(this.config));
|
|
29958
|
+
positions.push(...await adapter.getPositions(this.config, blockNumber));
|
|
29589
29959
|
}
|
|
29590
29960
|
return positions;
|
|
29591
29961
|
}
|
|
@@ -29654,8 +30024,8 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29654
30024
|
async getLSTAPR(address) {
|
|
29655
30025
|
return 0;
|
|
29656
30026
|
}
|
|
29657
|
-
async getVesuHealthFactors() {
|
|
29658
|
-
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
|
|
30027
|
+
async getVesuHealthFactors(blockNumber = "latest") {
|
|
30028
|
+
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor(blockNumber)));
|
|
29659
30029
|
}
|
|
29660
30030
|
async computeRebalanceConditionAndReturnCalls() {
|
|
29661
30031
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -30251,6 +30621,42 @@ var UniversalStrategies = [
|
|
|
30251
30621
|
|
|
30252
30622
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30253
30623
|
import { Contract as Contract10, uint256 as uint2569 } from "starknet";
|
|
30624
|
+
|
|
30625
|
+
// src/utils/health-factor-math.ts
|
|
30626
|
+
var HealthFactorMath = class {
|
|
30627
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
30628
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
30629
|
+
const denominator = collateralPrice * maxLTV;
|
|
30630
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
30631
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
30632
|
+
return netCollateral;
|
|
30633
|
+
}
|
|
30634
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
30635
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
30636
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
30637
|
+
return netCollateral.minus(collateralFromDebt);
|
|
30638
|
+
}
|
|
30639
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
30640
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30641
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
30642
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
30643
|
+
return healthFactor.toNumber();
|
|
30644
|
+
}
|
|
30645
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
30646
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30647
|
+
const denominator = targetHF - maxLTV;
|
|
30648
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
30649
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
30650
|
+
}
|
|
30651
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
30652
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30653
|
+
const denominator = targetHF * debtPrice;
|
|
30654
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
30655
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
30656
|
+
}
|
|
30657
|
+
};
|
|
30658
|
+
|
|
30659
|
+
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30254
30660
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
30255
30661
|
var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
|
|
30256
30662
|
constructor(config, pricer, metadata) {
|
|
@@ -30265,15 +30671,14 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30265
30671
|
}
|
|
30266
30672
|
}
|
|
30267
30673
|
asset() {
|
|
30268
|
-
|
|
30269
|
-
return vesuAdapter1.config.collateral;
|
|
30674
|
+
return this.getVesuSameTokenAdapter().config.collateral;
|
|
30270
30675
|
}
|
|
30271
30676
|
getTag() {
|
|
30272
30677
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
30273
30678
|
}
|
|
30274
30679
|
// Vesu adapter with LST and base token match
|
|
30275
30680
|
getVesuSameTokenAdapter() {
|
|
30276
|
-
const baseAdapter = this.getAdapter("
|
|
30681
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
30277
30682
|
baseAdapter.networkConfig = this.config;
|
|
30278
30683
|
baseAdapter.pricer = this.pricer;
|
|
30279
30684
|
return baseAdapter;
|
|
@@ -30321,20 +30726,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30321
30726
|
return price;
|
|
30322
30727
|
}
|
|
30323
30728
|
async getAvnuSwapMultiplyCall(params) {
|
|
30324
|
-
|
|
30325
|
-
|
|
30326
|
-
|
|
30327
|
-
|
|
30328
|
-
|
|
30729
|
+
assert(params.isDeposit, "Only deposit is supported in getAvnuSwapMultiplyCall");
|
|
30730
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
|
|
30731
|
+
const allVesuAdapters = this.getVesuAdapters();
|
|
30732
|
+
let remainingAmount = params.leg1DepositAmount;
|
|
30733
|
+
const lstExRate = await this.getLSTExchangeRate();
|
|
30734
|
+
const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
|
|
30735
|
+
const lstPrice = baseAssetPrice.price * lstExRate;
|
|
30736
|
+
for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
|
|
30737
|
+
const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
|
|
30738
|
+
const vesuAdapter = allVesuAdapters.find((adapter) => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
|
|
30739
|
+
if (!vesuAdapter) {
|
|
30740
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
|
|
30741
|
+
}
|
|
30742
|
+
const maxLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30743
|
+
const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
|
|
30744
|
+
const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
|
|
30745
|
+
maxBorrowable.amount,
|
|
30746
|
+
debtPrice.price,
|
|
30747
|
+
this.metadata.additionalInfo.targetHealthFactor,
|
|
30748
|
+
maxLTV,
|
|
30749
|
+
lstPrice,
|
|
30750
|
+
this.asset()
|
|
30751
|
+
);
|
|
30752
|
+
const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
|
|
30753
|
+
logger.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
|
|
30754
|
+
const call = await this._getAvnuDepositSwapLegCall({
|
|
30755
|
+
isDeposit: params.isDeposit,
|
|
30756
|
+
// adjust decimals of debt asset
|
|
30757
|
+
leg1DepositAmount: amountToDeposit,
|
|
30758
|
+
minHF: 1.1,
|
|
30759
|
+
// undo
|
|
30760
|
+
vesuAdapter
|
|
30761
|
+
});
|
|
30762
|
+
remainingAmount = remainingAmount.minus(amountToDeposit);
|
|
30763
|
+
return { call, vesuAdapter };
|
|
30764
|
+
}
|
|
30765
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
|
|
30329
30766
|
}
|
|
30330
30767
|
async _getAvnuDepositSwapLegCall(params) {
|
|
30768
|
+
const { vesuAdapter } = params;
|
|
30331
30769
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
|
|
30332
30770
|
assert(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
|
|
30333
|
-
const
|
|
30334
|
-
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
30771
|
+
const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30335
30772
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
30336
|
-
const existingPositions = await
|
|
30337
|
-
const collateralisation = await
|
|
30773
|
+
const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
30774
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30338
30775
|
const existingCollateralInfo = existingPositions[0];
|
|
30339
30776
|
const existingDebtInfo = existingPositions[1];
|
|
30340
30777
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
@@ -30342,11 +30779,40 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30342
30779
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30343
30780
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30344
30781
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30782
|
+
const debtTokenInfo = vesuAdapter.config.debt;
|
|
30783
|
+
let newDepositAmount = params.leg1DepositAmount;
|
|
30345
30784
|
const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
|
|
30346
30785
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
|
|
30347
|
-
const totalDebtAmount =
|
|
30348
|
-
|
|
30349
|
-
|
|
30786
|
+
const totalDebtAmount = new Web3Number(
|
|
30787
|
+
totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
|
|
30788
|
+
debtTokenInfo.decimals
|
|
30789
|
+
);
|
|
30790
|
+
let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
|
|
30791
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
|
|
30792
|
+
const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
|
|
30793
|
+
if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
|
|
30794
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
|
|
30795
|
+
return void 0;
|
|
30796
|
+
} else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
|
|
30797
|
+
debtAmount = maxBorrowable.amount.minimum(debtAmount);
|
|
30798
|
+
const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
|
|
30799
|
+
const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
|
|
30800
|
+
debtAmount.plus(existingDebtInfo.amount),
|
|
30801
|
+
debtPrice,
|
|
30802
|
+
params.minHF,
|
|
30803
|
+
legLTV,
|
|
30804
|
+
collateralPrice,
|
|
30805
|
+
this.asset()
|
|
30806
|
+
);
|
|
30807
|
+
newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
|
|
30808
|
+
if (newDepositAmount.lt(0)) {
|
|
30809
|
+
throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
|
|
30810
|
+
}
|
|
30811
|
+
if (newDebtUSDValue.toNumber() < 100) {
|
|
30812
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
|
|
30813
|
+
return void 0;
|
|
30814
|
+
}
|
|
30815
|
+
}
|
|
30350
30816
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
30351
30817
|
if (debtAmount.lt(0)) {
|
|
30352
30818
|
const lstDEXPrice = await this.getLSTDexPrice();
|
|
@@ -30358,32 +30824,34 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30358
30824
|
assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
30359
30825
|
return calls[0];
|
|
30360
30826
|
}
|
|
30827
|
+
console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
|
|
30361
30828
|
const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
|
|
30362
30829
|
const manage0Info = this.getProofs(STEP0);
|
|
30363
30830
|
const manageCall0 = manage0Info.callConstructor({
|
|
30364
|
-
amount:
|
|
30831
|
+
amount: newDepositAmount
|
|
30365
30832
|
});
|
|
30366
|
-
const STEP1 = "vesu_leg1" /* VESU_LEG1
|
|
30833
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30367
30834
|
const manage1Info = this.getProofs(STEP1);
|
|
30368
30835
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30369
|
-
collateralAmount:
|
|
30836
|
+
collateralAmount: newDepositAmount,
|
|
30370
30837
|
isAddCollateral: params.isDeposit,
|
|
30371
30838
|
debtAmount,
|
|
30372
30839
|
isBorrow: params.isDeposit
|
|
30373
30840
|
}));
|
|
30841
|
+
console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
30374
30842
|
const proofIds = [STEP0, STEP1];
|
|
30375
30843
|
const manageCalls = [manageCall0, manageCall1];
|
|
30376
30844
|
if (debtAmount.gt(0)) {
|
|
30377
|
-
const STEP2 = "
|
|
30845
|
+
const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30378
30846
|
const manage2Info = this.getProofs(STEP2);
|
|
30379
30847
|
const manageCall2 = manage2Info.callConstructor({
|
|
30380
30848
|
amount: debtAmount
|
|
30381
30849
|
});
|
|
30382
|
-
const
|
|
30850
|
+
const debtTokenInfo2 = vesuAdapter.config.debt;
|
|
30383
30851
|
const lstTokenInfo = this.asset();
|
|
30384
30852
|
const avnuModule = new AvnuWrapper();
|
|
30385
30853
|
const quote = await avnuModule.getQuotes(
|
|
30386
|
-
|
|
30854
|
+
debtTokenInfo2.address.address,
|
|
30387
30855
|
lstTokenInfo.address.address,
|
|
30388
30856
|
debtAmount.toWei(),
|
|
30389
30857
|
this.metadata.additionalInfo.vaultAllocator.address
|
|
@@ -30399,7 +30867,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30399
30867
|
minAmountWei
|
|
30400
30868
|
);
|
|
30401
30869
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
|
|
30402
|
-
const STEP3 = "
|
|
30870
|
+
const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30403
30871
|
const manage3Info = this.getProofs(STEP3);
|
|
30404
30872
|
const manageCall3 = manage3Info.callConstructor({
|
|
30405
30873
|
props: swapInfo
|
|
@@ -30417,7 +30885,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30417
30885
|
const manageCall4 = manage4Info.callConstructor({
|
|
30418
30886
|
amount: minAmount
|
|
30419
30887
|
});
|
|
30420
|
-
const STEP5 = "vesu_leg1" /* VESU_LEG1
|
|
30888
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30421
30889
|
const manage5Info = this.getProofs(STEP5);
|
|
30422
30890
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30423
30891
|
collateralAmount: minAmount,
|
|
@@ -30434,28 +30902,41 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30434
30902
|
}
|
|
30435
30903
|
// todo unwind or not deposit when the yield is bad.
|
|
30436
30904
|
async getLSTMultiplierRebalanceCall() {
|
|
30437
|
-
|
|
30438
|
-
|
|
30905
|
+
let shouldRebalance = false;
|
|
30906
|
+
const calls = [];
|
|
30907
|
+
const allVesuAdapters = this.getVesuAdapters().filter((vesuAdapter) => vesuAdapter.config.debt.symbol === "LBTC");
|
|
30908
|
+
for (const vesuAdapter of allVesuAdapters) {
|
|
30909
|
+
const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
|
|
30910
|
+
if (call.shouldRebalance && call.manageCall) {
|
|
30911
|
+
shouldRebalance = true;
|
|
30912
|
+
calls.push({ vesuAdapter, manageCall: call.manageCall });
|
|
30913
|
+
}
|
|
30914
|
+
}
|
|
30915
|
+
return { shouldRebalance, manageCalls: calls };
|
|
30916
|
+
}
|
|
30917
|
+
async _getLSTMultiplierRebalanceCall(vesuAdapter) {
|
|
30918
|
+
const positions = await vesuAdapter.getPositions(this.config);
|
|
30919
|
+
assert(positions.length == 2, "Rebalance call is only supported for 2 positions");
|
|
30439
30920
|
const existingCollateralInfo = positions[0];
|
|
30440
30921
|
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)},
|
|
30922
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
30923
|
+
const healthFactor = await vesuAdapter.getHealthFactor();
|
|
30924
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30925
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
30447
30926
|
existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
30448
30927
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30449
30928
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30450
30929
|
logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30930
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
|
|
30451
30931
|
const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
30452
30932
|
const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
30453
|
-
if (isHFTooLow || isHFTooHigh) {
|
|
30933
|
+
if (isHFTooLow || isHFTooHigh || 1) {
|
|
30454
30934
|
const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
30455
30935
|
isDeposit: true,
|
|
30456
30936
|
leg1DepositAmount: unusedBalance.amount,
|
|
30457
|
-
minHF: 1.02
|
|
30937
|
+
minHF: 1.02,
|
|
30458
30938
|
// todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
30939
|
+
vesuAdapter
|
|
30459
30940
|
});
|
|
30460
30941
|
return { shouldRebalance: true, manageCall };
|
|
30461
30942
|
} else {
|
|
@@ -30488,7 +30969,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30488
30969
|
async _getMinOutputAmountLSTBuy(amountInUnderlying) {
|
|
30489
30970
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
30490
30971
|
const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
|
|
30491
|
-
return minOutputAmount;
|
|
30972
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
30492
30973
|
}
|
|
30493
30974
|
async _getMinOutputAmountLSTSell(amountInLST) {
|
|
30494
30975
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
@@ -30545,21 +31026,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30545
31026
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
30546
31027
|
return vesuAdapter1.config.debt;
|
|
30547
31028
|
}
|
|
30548
|
-
async getMaxBorrowableAmount() {
|
|
31029
|
+
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
30549
31030
|
const vesuAdapters = this.getVesuAdapters();
|
|
30550
31031
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
30551
31032
|
const maxBorrowables = [];
|
|
30552
|
-
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30553
|
-
const maxInterestRate = lstAPY * 0.8;
|
|
30554
31033
|
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 });
|
|
31034
|
+
maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
|
|
30558
31035
|
}
|
|
30559
31036
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
30560
31037
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
30561
31038
|
return { netMaxBorrowableAmount, maxBorrowables };
|
|
30562
31039
|
}
|
|
31040
|
+
// recursively, using binary search computes max swappable.
|
|
31041
|
+
// @dev assumes 1 token of from == 1 token of to
|
|
31042
|
+
async getMaxSwappableWithMaxSlippage(fromToken, toToken, maxSlippage, maxAmount) {
|
|
31043
|
+
const output = await findMaxInputWithSlippage({
|
|
31044
|
+
apiGetOutput: async (inputAmount) => {
|
|
31045
|
+
const ekuboQuoter = new EkuboQuoter(this.config);
|
|
31046
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
31047
|
+
const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
|
|
31048
|
+
return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
|
|
31049
|
+
},
|
|
31050
|
+
maxInput: maxAmount.toNumber(),
|
|
31051
|
+
maxSlippagePercent: maxSlippage,
|
|
31052
|
+
tolerance: 1e-3,
|
|
31053
|
+
referenceRate: 1
|
|
31054
|
+
});
|
|
31055
|
+
return new Web3Number(output.optimalInput, fromToken.decimals);
|
|
31056
|
+
}
|
|
31057
|
+
async getMaxBorrowableAmountByVesuAdapter(vesuAdapter, isAPYComputation) {
|
|
31058
|
+
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
31059
|
+
const maxInterestRate = lstAPY * 0.8;
|
|
31060
|
+
const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
|
|
31061
|
+
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
31062
|
+
const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
|
|
31063
|
+
if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
|
|
31064
|
+
return { amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
31065
|
+
}
|
|
31066
|
+
try {
|
|
31067
|
+
const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 2e-4, maxBorrowable);
|
|
31068
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
31069
|
+
} catch (error) {
|
|
31070
|
+
logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
|
|
31071
|
+
const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
|
|
31072
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
31073
|
+
}
|
|
31074
|
+
}
|
|
30563
31075
|
// todo how much to unwind to get back healthy APY zone again
|
|
30564
31076
|
// if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
|
|
30565
31077
|
// For xSTRK, simply deposit in Vesu if looping is not viable
|
|
@@ -30583,7 +31095,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30583
31095
|
// todo undo this
|
|
30584
31096
|
async netAPY() {
|
|
30585
31097
|
const unusedBalance = await this.getUnusedBalance();
|
|
30586
|
-
const maxNewDeposits = await this.maxNewDeposits();
|
|
31098
|
+
const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
30587
31099
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30588
31100
|
if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
30589
31101
|
logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
|
|
@@ -30600,8 +31112,8 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30600
31112
|
return output;
|
|
30601
31113
|
}
|
|
30602
31114
|
}
|
|
30603
|
-
async maxNewDeposits() {
|
|
30604
|
-
const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
|
|
31115
|
+
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
31116
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
30605
31117
|
let ltv = void 0;
|
|
30606
31118
|
for (let adapter of this.getVesuAdapters()) {
|
|
30607
31119
|
const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
|
|
@@ -30704,7 +31216,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30704
31216
|
const manageCall2 = manage2Info.callConstructor({
|
|
30705
31217
|
delegation: true
|
|
30706
31218
|
});
|
|
30707
|
-
const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU
|
|
31219
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
30708
31220
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
30709
31221
|
const multiplyParams = params.isIncrease ? {
|
|
30710
31222
|
isIncrease: true,
|
|
@@ -30788,6 +31300,12 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
|
|
|
30788
31300
|
function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
30789
31301
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
30790
31302
|
}
|
|
31303
|
+
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
31304
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31305
|
+
}
|
|
31306
|
+
function getVesuLegId(baseID, debtTokenSymbol) {
|
|
31307
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31308
|
+
}
|
|
30791
31309
|
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
30792
31310
|
vaultSettings.leafAdapters = [];
|
|
30793
31311
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
@@ -30797,7 +31315,7 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30797
31315
|
collateral: lstToken,
|
|
30798
31316
|
debt: underlyingToken,
|
|
30799
31317
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
30800
|
-
id: "vesu_leg1" /* VESU_LEG1
|
|
31318
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
30801
31319
|
});
|
|
30802
31320
|
const commonAdapter = new CommonAdapter({
|
|
30803
31321
|
manager: vaultSettings.manager,
|
|
@@ -30806,25 +31324,39 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30806
31324
|
vaultAddress: vaultSettings.vaultAddress,
|
|
30807
31325
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
30808
31326
|
});
|
|
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
31327
|
vaultSettings.adapters.push(...[{
|
|
30816
|
-
id: "
|
|
31328
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
30817
31329
|
adapter: vesuAdapterLST
|
|
30818
31330
|
}, {
|
|
30819
31331
|
id: "common_adapter" /* COMMON */,
|
|
30820
31332
|
adapter: commonAdapter
|
|
30821
31333
|
}]);
|
|
30822
|
-
|
|
30823
|
-
|
|
30824
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address,
|
|
30825
|
-
vaultSettings.leafAdapters.push(
|
|
30826
|
-
vaultSettings.leafAdapters.push(
|
|
30827
|
-
vaultSettings.leafAdapters.push(
|
|
31334
|
+
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
31335
|
+
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
31336
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
31337
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
31338
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
31339
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_mul_approve_withdr" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
|
|
31340
|
+
for (let borrowableAsset of vaultSettings.borrowable_assets) {
|
|
31341
|
+
const debtAsset = borrowableAsset;
|
|
31342
|
+
const approve_debt_token_id = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, debtAsset.symbol);
|
|
31343
|
+
const swap_debt_token_id = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, debtAsset.symbol);
|
|
31344
|
+
const swap_lst_token_id = getAvnuManageIDs("avnu_mul_swap_withdr" /* AVNU_MULTIPLY_SWAP_WITHDRAW */, debtAsset.symbol);
|
|
31345
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
|
|
31346
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
|
|
31347
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
|
|
31348
|
+
const vesuAdapter = new VesuAdapter({
|
|
31349
|
+
poolId: pool1,
|
|
31350
|
+
collateral: lstToken,
|
|
31351
|
+
debt: debtAsset,
|
|
31352
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
31353
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol)
|
|
31354
|
+
});
|
|
31355
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
|
|
31356
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
|
|
31357
|
+
const multiplID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, debtAsset.symbol);
|
|
31358
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getMultiplyAdapter(multiplID).bind(vesuAdapter));
|
|
31359
|
+
}
|
|
30828
31360
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30829
31361
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30830
31362
|
vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
|
|
@@ -30902,7 +31434,8 @@ var hyperxSTRK = {
|
|
|
30902
31434
|
adapters: [],
|
|
30903
31435
|
targetHealthFactor: 1.1,
|
|
30904
31436
|
minHealthFactor: 1.05,
|
|
30905
|
-
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK")
|
|
31437
|
+
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK"),
|
|
31438
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK")
|
|
30906
31439
|
};
|
|
30907
31440
|
var hyperxWBTC = {
|
|
30908
31441
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -30914,7 +31447,8 @@ var hyperxWBTC = {
|
|
|
30914
31447
|
adapters: [],
|
|
30915
31448
|
targetHealthFactor: 1.1,
|
|
30916
31449
|
minHealthFactor: 1.05,
|
|
30917
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31450
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31451
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC")
|
|
30918
31452
|
};
|
|
30919
31453
|
var hyperxtBTC = {
|
|
30920
31454
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -30926,7 +31460,8 @@ var hyperxtBTC = {
|
|
|
30926
31460
|
adapters: [],
|
|
30927
31461
|
targetHealthFactor: 1.1,
|
|
30928
31462
|
minHealthFactor: 1.05,
|
|
30929
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31463
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31464
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC")
|
|
30930
31465
|
};
|
|
30931
31466
|
var hyperxsBTC = {
|
|
30932
31467
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -30938,7 +31473,8 @@ var hyperxsBTC = {
|
|
|
30938
31473
|
adapters: [],
|
|
30939
31474
|
targetHealthFactor: 1.1,
|
|
30940
31475
|
minHealthFactor: 1.05,
|
|
30941
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31476
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31477
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC")
|
|
30942
31478
|
};
|
|
30943
31479
|
var hyperxLBTC = {
|
|
30944
31480
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -30950,7 +31486,8 @@ var hyperxLBTC = {
|
|
|
30950
31486
|
adapters: [],
|
|
30951
31487
|
targetHealthFactor: 1.1,
|
|
30952
31488
|
minHealthFactor: 1.05,
|
|
30953
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31489
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31490
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC")
|
|
30954
31491
|
};
|
|
30955
31492
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
30956
31493
|
return [
|
|
@@ -30993,6 +31530,7 @@ var HyperLSTStrategies = [
|
|
|
30993
31530
|
getStrategySettings("xLBTC", "LBTC", hyperxLBTC, false)
|
|
30994
31531
|
];
|
|
30995
31532
|
export {
|
|
31533
|
+
APYType,
|
|
30996
31534
|
AUMTypes,
|
|
30997
31535
|
AVNU_EXCHANGE,
|
|
30998
31536
|
AVNU_MIDDLEWARE,
|