@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.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
APYType: () => APYType,
|
|
33
34
|
AUMTypes: () => AUMTypes,
|
|
34
35
|
AVNU_EXCHANGE: () => AVNU_EXCHANGE,
|
|
35
36
|
AVNU_MIDDLEWARE: () => AVNU_MIDDLEWARE,
|
|
@@ -420,6 +421,25 @@ var defaultTokens = [{
|
|
|
420
421
|
priceProxySymbol: "WBTC",
|
|
421
422
|
priceCheckAmount: 1e-4
|
|
422
423
|
// 112000 * 0.0001 = $11.2
|
|
424
|
+
}, {
|
|
425
|
+
name: "mRe7BTC",
|
|
426
|
+
symbol: "mRe7BTC",
|
|
427
|
+
logo: "https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/3a62ecee-1e58-45d3-9862-3ce90dff1900/logo",
|
|
428
|
+
address: ContractAddr.from("0x4e4fb1a9ca7e84bae609b9dc0078ad7719e49187ae7e425bb47d131710eddac"),
|
|
429
|
+
decimals: 18,
|
|
430
|
+
coingeckId: void 0,
|
|
431
|
+
displayDecimals: 6,
|
|
432
|
+
priceCheckAmount: 1e-4
|
|
433
|
+
// 112000 * 0.0001 = $11.2
|
|
434
|
+
}, {
|
|
435
|
+
name: "mRe7YIELD",
|
|
436
|
+
symbol: "mRe7YIELD",
|
|
437
|
+
logo: "https://midas.app/assets/mre7-BcOOHm7i.svg",
|
|
438
|
+
address: ContractAddr.from("0x4be8945e61dc3e19ebadd1579a6bd53b262f51ba89e6f8b0c4bc9a7e3c633fc"),
|
|
439
|
+
decimals: 18,
|
|
440
|
+
coingeckId: void 0,
|
|
441
|
+
displayDecimals: 2,
|
|
442
|
+
priceCheckAmount: 100
|
|
423
443
|
}];
|
|
424
444
|
var tokens = defaultTokens;
|
|
425
445
|
var _Global = class _Global {
|
|
@@ -2313,16 +2333,16 @@ var AvnuWrapper = class _AvnuWrapper {
|
|
|
2313
2333
|
};
|
|
2314
2334
|
return swapInfo;
|
|
2315
2335
|
}
|
|
2316
|
-
static buildZeroSwap(tokenToSell,
|
|
2336
|
+
static buildZeroSwap(tokenToSell, beneficiary, tokenToBuy = tokenToSell) {
|
|
2317
2337
|
return {
|
|
2318
2338
|
token_from_address: tokenToSell.address,
|
|
2319
2339
|
token_from_amount: import_starknet6.uint256.bnToUint256(0),
|
|
2320
|
-
token_to_address:
|
|
2340
|
+
token_to_address: tokenToBuy.address,
|
|
2321
2341
|
token_to_amount: import_starknet6.uint256.bnToUint256(0),
|
|
2322
2342
|
token_to_min_amount: import_starknet6.uint256.bnToUint256(0),
|
|
2323
|
-
beneficiary
|
|
2343
|
+
beneficiary,
|
|
2324
2344
|
integrator_fee_amount_bps: 0,
|
|
2325
|
-
integrator_fee_recipient:
|
|
2345
|
+
integrator_fee_recipient: beneficiary,
|
|
2326
2346
|
routes: []
|
|
2327
2347
|
};
|
|
2328
2348
|
}
|
|
@@ -4123,21 +4143,20 @@ var Harvests = class _Harvests {
|
|
|
4123
4143
|
const rewards = await this.getHarvests(addr);
|
|
4124
4144
|
if (rewards.length == 0) return [];
|
|
4125
4145
|
const unClaimed = [];
|
|
4126
|
-
const
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
}
|
|
4134
|
-
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4135
|
-
if (bal.lessThan(reward.claim.amount)) {
|
|
4136
|
-
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4137
|
-
continue;
|
|
4138
|
-
}
|
|
4139
|
-
unClaimed.unshift(reward);
|
|
4146
|
+
const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
|
|
4147
|
+
const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
|
|
4148
|
+
const contract = new import_starknet9.Contract({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
|
|
4149
|
+
const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
|
|
4150
|
+
logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
|
|
4151
|
+
if (isClaimed) {
|
|
4152
|
+
return unClaimed;
|
|
4140
4153
|
}
|
|
4154
|
+
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4155
|
+
if (bal.lessThan(reward.claim.amount)) {
|
|
4156
|
+
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4157
|
+
return unClaimed;
|
|
4158
|
+
}
|
|
4159
|
+
unClaimed.unshift(reward);
|
|
4141
4160
|
return unClaimed;
|
|
4142
4161
|
}
|
|
4143
4162
|
};
|
|
@@ -15400,6 +15419,91 @@ var apolloClient = new import_client.ApolloClient({
|
|
|
15400
15419
|
});
|
|
15401
15420
|
var apollo_client_default = apolloClient;
|
|
15402
15421
|
|
|
15422
|
+
// src/utils/math-utils.ts
|
|
15423
|
+
async function binarySearch(lowWei, highWei, callback) {
|
|
15424
|
+
while (lowWei <= highWei) {
|
|
15425
|
+
const diff = highWei - lowWei;
|
|
15426
|
+
const mid = lowWei + diff / 2n;
|
|
15427
|
+
const result = await callback(mid);
|
|
15428
|
+
if (result === "found") {
|
|
15429
|
+
return mid;
|
|
15430
|
+
} else if (result == "retry") {
|
|
15431
|
+
} else if (result === "go_low") {
|
|
15432
|
+
highWei = mid - BigInt(1);
|
|
15433
|
+
} else {
|
|
15434
|
+
lowWei = mid + BigInt(1);
|
|
15435
|
+
}
|
|
15436
|
+
}
|
|
15437
|
+
return null;
|
|
15438
|
+
}
|
|
15439
|
+
async function findMaxInputWithSlippage(options) {
|
|
15440
|
+
const {
|
|
15441
|
+
apiGetOutput,
|
|
15442
|
+
maxInput,
|
|
15443
|
+
maxSlippagePercent,
|
|
15444
|
+
tolerance,
|
|
15445
|
+
minInput = 0,
|
|
15446
|
+
referenceAmountMultiplier = 1e-3,
|
|
15447
|
+
referenceRate = 0
|
|
15448
|
+
} = options;
|
|
15449
|
+
let apiCalls = 0;
|
|
15450
|
+
if (!referenceRate && !referenceAmountMultiplier) {
|
|
15451
|
+
throw new Error("One of referenceRate or referenceAmountMultiplier must be provided");
|
|
15452
|
+
}
|
|
15453
|
+
let _referenceRate = referenceRate;
|
|
15454
|
+
if (!_referenceRate) {
|
|
15455
|
+
const smallAmount = maxInput * referenceAmountMultiplier;
|
|
15456
|
+
const referenceOutput = await apiGetOutput(smallAmount);
|
|
15457
|
+
apiCalls++;
|
|
15458
|
+
_referenceRate = referenceOutput / smallAmount;
|
|
15459
|
+
}
|
|
15460
|
+
async function checkSlippage(inputAmount) {
|
|
15461
|
+
const actualOutput = await apiGetOutput(inputAmount);
|
|
15462
|
+
apiCalls++;
|
|
15463
|
+
const expectedOutput = inputAmount * referenceRate;
|
|
15464
|
+
const slippage = (expectedOutput - actualOutput) / expectedOutput;
|
|
15465
|
+
logger.verbose(`findMaxInputWithSlippage::checkSlippage inputAmount: ${inputAmount}, actualOutput: ${actualOutput}, slippage: ${slippage}, maxSlippagePercent: ${maxSlippagePercent}`);
|
|
15466
|
+
return {
|
|
15467
|
+
acceptable: slippage <= maxSlippagePercent,
|
|
15468
|
+
slippage,
|
|
15469
|
+
output: actualOutput
|
|
15470
|
+
};
|
|
15471
|
+
}
|
|
15472
|
+
const maxCheck = await checkSlippage(maxInput);
|
|
15473
|
+
if (maxCheck.acceptable) {
|
|
15474
|
+
return {
|
|
15475
|
+
optimalInput: maxInput,
|
|
15476
|
+
actualOutput: maxCheck.output,
|
|
15477
|
+
actualSlippage: maxCheck.slippage,
|
|
15478
|
+
apiCallsUsed: apiCalls
|
|
15479
|
+
};
|
|
15480
|
+
}
|
|
15481
|
+
let left = minInput;
|
|
15482
|
+
let right = maxInput;
|
|
15483
|
+
let bestInput = minInput;
|
|
15484
|
+
let bestOutput = 0;
|
|
15485
|
+
let bestSlippage = 0;
|
|
15486
|
+
const convergenceThreshold = tolerance * maxInput;
|
|
15487
|
+
while (right - left > convergenceThreshold) {
|
|
15488
|
+
const mid = (left + right) / 2;
|
|
15489
|
+
const midCheck = await checkSlippage(mid);
|
|
15490
|
+
if (midCheck.acceptable) {
|
|
15491
|
+
bestInput = mid;
|
|
15492
|
+
bestOutput = midCheck.output;
|
|
15493
|
+
bestSlippage = midCheck.slippage;
|
|
15494
|
+
left = mid;
|
|
15495
|
+
} else {
|
|
15496
|
+
right = mid;
|
|
15497
|
+
}
|
|
15498
|
+
}
|
|
15499
|
+
return {
|
|
15500
|
+
optimalInput: bestInput,
|
|
15501
|
+
actualOutput: bestOutput,
|
|
15502
|
+
actualSlippage: bestSlippage,
|
|
15503
|
+
apiCallsUsed: apiCalls
|
|
15504
|
+
};
|
|
15505
|
+
}
|
|
15506
|
+
|
|
15403
15507
|
// src/strategies/ekubo-cl-vault.tsx
|
|
15404
15508
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
15405
15509
|
var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
@@ -15686,7 +15790,6 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
15686
15790
|
for (let i = len - 1; i >= 0; --i) {
|
|
15687
15791
|
let record = await this.contract.call("get_rewards_info", [i]);
|
|
15688
15792
|
logger.verbose(`${_EkuboCLVault.name}: getHarvestRewardShares: ${i}`);
|
|
15689
|
-
console.log(record);
|
|
15690
15793
|
const block = Number(record.block_number);
|
|
15691
15794
|
if (block < fromBlock) {
|
|
15692
15795
|
return shares;
|
|
@@ -15886,16 +15989,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
15886
15989
|
const sqrtRatio = _EkuboCLVault.div2Power128(
|
|
15887
15990
|
BigInt(priceInfo.sqrt_ratio.toString())
|
|
15888
15991
|
);
|
|
15889
|
-
console.log(
|
|
15890
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, sqrtRatio: ${sqrtRatio}, ${priceInfo.sqrt_ratio.toString()}`
|
|
15891
|
-
);
|
|
15892
15992
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
15893
15993
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
15894
15994
|
const price = sqrtRatio * sqrtRatio * 10 ** token0Info.decimals / 10 ** token1Info.decimals;
|
|
15895
15995
|
const tick = priceInfo.tick;
|
|
15896
|
-
console.log(
|
|
15897
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, price: ${price}, tick: ${tick.mag}, ${tick.sign}`
|
|
15898
|
-
);
|
|
15899
15996
|
return {
|
|
15900
15997
|
price,
|
|
15901
15998
|
tick: Number(tick.mag) * (tick.sign ? -1 : 1),
|
|
@@ -16522,62 +16619,193 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16522
16619
|
logger.verbose(
|
|
16523
16620
|
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
16524
16621
|
);
|
|
16525
|
-
const
|
|
16526
|
-
|
|
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
|
+
import_starknet11.uint256.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 = import_starknet11.uint256.bnToUint256(swap1Amount.toWei());
|
|
16691
|
+
swapInfo.token_to_min_amount = import_starknet11.uint256.bnToUint256(
|
|
16692
|
+
swap1Amount.multipliedBy(0).toWei()
|
|
16693
|
+
// placeholder
|
|
16694
|
+
);
|
|
16527
16695
|
logger.verbose(
|
|
16528
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16696
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
16529
16697
|
);
|
|
16530
|
-
const
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
token1Amt,
|
|
16534
|
-
bounds,
|
|
16535
|
-
maxIterations,
|
|
16536
|
-
priceRatioPrecision
|
|
16698
|
+
const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
|
|
16699
|
+
logger.verbose(
|
|
16700
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
16537
16701
|
);
|
|
16538
|
-
|
|
16702
|
+
const swapInfo2 = {
|
|
16703
|
+
...swapInfo,
|
|
16704
|
+
token_from_amount: import_starknet11.uint256.bnToUint256(remainingAmount.toWei())
|
|
16705
|
+
};
|
|
16706
|
+
swapInfo2.token_to_address = token1Info.address.address;
|
|
16539
16707
|
logger.verbose(
|
|
16540
|
-
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16708
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16709
|
+
swapInfo
|
|
16710
|
+
)}`
|
|
16541
16711
|
);
|
|
16542
16712
|
logger.verbose(
|
|
16543
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16713
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
16714
|
+
swapInfo2
|
|
16715
|
+
)}`
|
|
16544
16716
|
);
|
|
16545
|
-
const
|
|
16546
|
-
|
|
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
|
-
|
|
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) => import_starknet11.num.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 {
|
|
16581
16809
|
const calldata = [
|
|
16582
16810
|
claim.rewardsContract.address,
|
|
16583
16811
|
{
|
|
@@ -16586,34 +16814,23 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16586
16814
|
claimee: claim.claim.claimee.address
|
|
16587
16815
|
},
|
|
16588
16816
|
claim.proof.map((p) => import_starknet11.num.getDecimalString(p)),
|
|
16589
|
-
|
|
16817
|
+
swapInfo1,
|
|
16590
16818
|
swapInfo2
|
|
16591
16819
|
];
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
)
|
|
16597
|
-
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
BigInt(postFeeAmount.toWei())
|
|
16607
|
-
// upper limit is the post fee amount
|
|
16608
|
-
);
|
|
16609
|
-
logger.verbose(
|
|
16610
|
-
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
16611
|
-
_callsFinal
|
|
16612
|
-
)}`
|
|
16613
|
-
);
|
|
16614
|
-
calls.push(..._callsFinal);
|
|
16615
|
-
}
|
|
16616
|
-
return calls;
|
|
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;
|
|
16617
16834
|
}
|
|
16618
16835
|
async getInvestmentFlows() {
|
|
16619
16836
|
const netYield = await this.netAPY();
|
|
@@ -19145,7 +19362,58 @@ function toBigInt(value) {
|
|
|
19145
19362
|
}
|
|
19146
19363
|
|
|
19147
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 || {});
|
|
19148
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
|
+
// }
|
|
19149
19417
|
constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
|
|
19150
19418
|
const { id, target, method, packedArguments } = params;
|
|
19151
19419
|
return {
|
|
@@ -19163,6 +19431,94 @@ var BaseAdapter = class extends CacheClass {
|
|
|
19163
19431
|
]
|
|
19164
19432
|
};
|
|
19165
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
|
+
// }
|
|
19166
19522
|
};
|
|
19167
19523
|
|
|
19168
19524
|
// src/strategies/universal-adapters/common-adapter.ts
|
|
@@ -26765,7 +27121,20 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26765
27121
|
}
|
|
26766
27122
|
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
26767
27123
|
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
|
|
26768
|
-
|
|
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);
|
|
26769
27138
|
}
|
|
26770
27139
|
async getMaxBorrowableByInterestRate(config, asset, maxBorrowAPY) {
|
|
26771
27140
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
@@ -26798,16 +27167,17 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26798
27167
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
26799
27168
|
const timeDelta = assetConfig.last_updated;
|
|
26800
27169
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
26801
|
-
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));
|
|
26802
27172
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
26803
27173
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
26804
27174
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
26805
27175
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
26806
|
-
|
|
27176
|
+
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
26807
27177
|
return maxDebtToHave.minus(currentDebt);
|
|
26808
27178
|
}
|
|
26809
|
-
async getLTVConfig(config) {
|
|
26810
|
-
const CACHE_KEY =
|
|
27179
|
+
async getLTVConfig(config, blockNumber = "latest") {
|
|
27180
|
+
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
26811
27181
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26812
27182
|
if (cacheData) {
|
|
26813
27183
|
return cacheData;
|
|
@@ -26815,10 +27185,10 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26815
27185
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
26816
27186
|
let ltv = 0;
|
|
26817
27187
|
if (isV2) {
|
|
26818
|
-
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 });
|
|
26819
27189
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26820
27190
|
} else {
|
|
26821
|
-
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 });
|
|
26822
27192
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26823
27193
|
}
|
|
26824
27194
|
if (ltv == 0) {
|
|
@@ -26827,11 +27197,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26827
27197
|
this.setCache(CACHE_KEY, ltv, 3e5);
|
|
26828
27198
|
return this.getCache(CACHE_KEY);
|
|
26829
27199
|
}
|
|
26830
|
-
async getPositions(config) {
|
|
27200
|
+
async getPositions(config, blockNumber = "latest") {
|
|
26831
27201
|
if (!this.pricer) {
|
|
26832
27202
|
throw new Error("Pricer is not initialized");
|
|
26833
27203
|
}
|
|
26834
|
-
const CACHE_KEY =
|
|
27204
|
+
const CACHE_KEY = `positions_${blockNumber}`;
|
|
26835
27205
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26836
27206
|
if (cacheData) {
|
|
26837
27207
|
return cacheData;
|
|
@@ -26843,7 +27213,8 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26843
27213
|
this.config.collateral.address.address,
|
|
26844
27214
|
this.config.debt.address.address,
|
|
26845
27215
|
this.config.vaultAllocator.address
|
|
26846
|
-
]);
|
|
27216
|
+
], { blockIdentifier: blockNumber });
|
|
27217
|
+
console.log(output);
|
|
26847
27218
|
const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
|
|
26848
27219
|
const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
|
|
26849
27220
|
logger.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
|
|
@@ -26863,11 +27234,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26863
27234
|
this.setCache(CACHE_KEY, value, 6e4);
|
|
26864
27235
|
return value;
|
|
26865
27236
|
}
|
|
26866
|
-
async getCollateralization(config) {
|
|
27237
|
+
async getCollateralization(config, blockNumber = "latest") {
|
|
26867
27238
|
if (!this.pricer) {
|
|
26868
27239
|
throw new Error("Pricer is not initialized");
|
|
26869
27240
|
}
|
|
26870
|
-
const CACHE_KEY =
|
|
27241
|
+
const CACHE_KEY = `collateralization_${blockNumber}`;
|
|
26871
27242
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26872
27243
|
if (cacheData) {
|
|
26873
27244
|
return cacheData;
|
|
@@ -26879,7 +27250,7 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26879
27250
|
this.config.collateral.address.address,
|
|
26880
27251
|
this.config.debt.address.address,
|
|
26881
27252
|
this.config.vaultAllocator.address
|
|
26882
|
-
]);
|
|
27253
|
+
], { blockIdentifier: blockNumber });
|
|
26883
27254
|
const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
|
|
26884
27255
|
const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
|
|
26885
27256
|
const value = [{
|
|
@@ -26916,9 +27287,9 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26916
27287
|
ltv
|
|
26917
27288
|
};
|
|
26918
27289
|
}
|
|
26919
|
-
async getHealthFactor() {
|
|
26920
|
-
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
26921
|
-
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);
|
|
26922
27293
|
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
26923
27294
|
}
|
|
26924
27295
|
static async getVesuPools(retry = 0) {
|
|
@@ -29580,11 +29951,11 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29580
29951
|
vesuAdapter2.networkConfig = this.config;
|
|
29581
29952
|
return [vesuAdapter1, vesuAdapter2];
|
|
29582
29953
|
}
|
|
29583
|
-
async getVesuPositions() {
|
|
29954
|
+
async getVesuPositions(blockNumber = "latest") {
|
|
29584
29955
|
const adapters = this.getVesuAdapters();
|
|
29585
29956
|
const positions = [];
|
|
29586
29957
|
for (const adapter of adapters) {
|
|
29587
|
-
positions.push(...await adapter.getPositions(this.config));
|
|
29958
|
+
positions.push(...await adapter.getPositions(this.config, blockNumber));
|
|
29588
29959
|
}
|
|
29589
29960
|
return positions;
|
|
29590
29961
|
}
|
|
@@ -29653,8 +30024,8 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29653
30024
|
async getLSTAPR(address) {
|
|
29654
30025
|
return 0;
|
|
29655
30026
|
}
|
|
29656
|
-
async getVesuHealthFactors() {
|
|
29657
|
-
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)));
|
|
29658
30029
|
}
|
|
29659
30030
|
async computeRebalanceConditionAndReturnCalls() {
|
|
29660
30031
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -30250,6 +30621,42 @@ var UniversalStrategies = [
|
|
|
30250
30621
|
|
|
30251
30622
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30252
30623
|
var import_starknet17 = require("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
|
|
30253
30660
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
30254
30661
|
var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
|
|
30255
30662
|
constructor(config, pricer, metadata) {
|
|
@@ -30264,15 +30671,14 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30264
30671
|
}
|
|
30265
30672
|
}
|
|
30266
30673
|
asset() {
|
|
30267
|
-
|
|
30268
|
-
return vesuAdapter1.config.collateral;
|
|
30674
|
+
return this.getVesuSameTokenAdapter().config.collateral;
|
|
30269
30675
|
}
|
|
30270
30676
|
getTag() {
|
|
30271
30677
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
30272
30678
|
}
|
|
30273
30679
|
// Vesu adapter with LST and base token match
|
|
30274
30680
|
getVesuSameTokenAdapter() {
|
|
30275
|
-
const baseAdapter = this.getAdapter("
|
|
30681
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
30276
30682
|
baseAdapter.networkConfig = this.config;
|
|
30277
30683
|
baseAdapter.pricer = this.pricer;
|
|
30278
30684
|
return baseAdapter;
|
|
@@ -30320,20 +30726,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30320
30726
|
return price;
|
|
30321
30727
|
}
|
|
30322
30728
|
async getAvnuSwapMultiplyCall(params) {
|
|
30323
|
-
|
|
30324
|
-
|
|
30325
|
-
|
|
30326
|
-
|
|
30327
|
-
|
|
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`);
|
|
30328
30766
|
}
|
|
30329
30767
|
async _getAvnuDepositSwapLegCall(params) {
|
|
30768
|
+
const { vesuAdapter } = params;
|
|
30330
30769
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
|
|
30331
30770
|
assert(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
|
|
30332
|
-
const
|
|
30333
|
-
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
30771
|
+
const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30334
30772
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
30335
|
-
const existingPositions = await
|
|
30336
|
-
const collateralisation = await
|
|
30773
|
+
const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
30774
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30337
30775
|
const existingCollateralInfo = existingPositions[0];
|
|
30338
30776
|
const existingDebtInfo = existingPositions[1];
|
|
30339
30777
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
@@ -30341,11 +30779,40 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30341
30779
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30342
30780
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30343
30781
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30782
|
+
const debtTokenInfo = vesuAdapter.config.debt;
|
|
30783
|
+
let newDepositAmount = params.leg1DepositAmount;
|
|
30344
30784
|
const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
|
|
30345
30785
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
|
|
30346
|
-
const totalDebtAmount =
|
|
30347
|
-
|
|
30348
|
-
|
|
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
|
+
}
|
|
30349
30816
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
30350
30817
|
if (debtAmount.lt(0)) {
|
|
30351
30818
|
const lstDEXPrice = await this.getLSTDexPrice();
|
|
@@ -30357,32 +30824,34 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30357
30824
|
assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
30358
30825
|
return calls[0];
|
|
30359
30826
|
}
|
|
30827
|
+
console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
|
|
30360
30828
|
const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
|
|
30361
30829
|
const manage0Info = this.getProofs(STEP0);
|
|
30362
30830
|
const manageCall0 = manage0Info.callConstructor({
|
|
30363
|
-
amount:
|
|
30831
|
+
amount: newDepositAmount
|
|
30364
30832
|
});
|
|
30365
|
-
const STEP1 = "vesu_leg1" /* VESU_LEG1
|
|
30833
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30366
30834
|
const manage1Info = this.getProofs(STEP1);
|
|
30367
30835
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30368
|
-
collateralAmount:
|
|
30836
|
+
collateralAmount: newDepositAmount,
|
|
30369
30837
|
isAddCollateral: params.isDeposit,
|
|
30370
30838
|
debtAmount,
|
|
30371
30839
|
isBorrow: params.isDeposit
|
|
30372
30840
|
}));
|
|
30841
|
+
console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
30373
30842
|
const proofIds = [STEP0, STEP1];
|
|
30374
30843
|
const manageCalls = [manageCall0, manageCall1];
|
|
30375
30844
|
if (debtAmount.gt(0)) {
|
|
30376
|
-
const STEP2 = "
|
|
30845
|
+
const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30377
30846
|
const manage2Info = this.getProofs(STEP2);
|
|
30378
30847
|
const manageCall2 = manage2Info.callConstructor({
|
|
30379
30848
|
amount: debtAmount
|
|
30380
30849
|
});
|
|
30381
|
-
const
|
|
30850
|
+
const debtTokenInfo2 = vesuAdapter.config.debt;
|
|
30382
30851
|
const lstTokenInfo = this.asset();
|
|
30383
30852
|
const avnuModule = new AvnuWrapper();
|
|
30384
30853
|
const quote = await avnuModule.getQuotes(
|
|
30385
|
-
|
|
30854
|
+
debtTokenInfo2.address.address,
|
|
30386
30855
|
lstTokenInfo.address.address,
|
|
30387
30856
|
debtAmount.toWei(),
|
|
30388
30857
|
this.metadata.additionalInfo.vaultAllocator.address
|
|
@@ -30398,7 +30867,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30398
30867
|
minAmountWei
|
|
30399
30868
|
);
|
|
30400
30869
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
|
|
30401
|
-
const STEP3 = "
|
|
30870
|
+
const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30402
30871
|
const manage3Info = this.getProofs(STEP3);
|
|
30403
30872
|
const manageCall3 = manage3Info.callConstructor({
|
|
30404
30873
|
props: swapInfo
|
|
@@ -30416,7 +30885,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30416
30885
|
const manageCall4 = manage4Info.callConstructor({
|
|
30417
30886
|
amount: minAmount
|
|
30418
30887
|
});
|
|
30419
|
-
const STEP5 = "vesu_leg1" /* VESU_LEG1
|
|
30888
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30420
30889
|
const manage5Info = this.getProofs(STEP5);
|
|
30421
30890
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30422
30891
|
collateralAmount: minAmount,
|
|
@@ -30433,28 +30902,41 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30433
30902
|
}
|
|
30434
30903
|
// todo unwind or not deposit when the yield is bad.
|
|
30435
30904
|
async getLSTMultiplierRebalanceCall() {
|
|
30436
|
-
|
|
30437
|
-
|
|
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");
|
|
30438
30920
|
const existingCollateralInfo = positions[0];
|
|
30439
30921
|
const existingDebtInfo = positions[1];
|
|
30440
|
-
const unusedBalance =
|
|
30441
|
-
const
|
|
30442
|
-
const
|
|
30443
|
-
|
|
30444
|
-
const collateralisation = await vesuAdapter1.getCollateralization(this.config);
|
|
30445
|
-
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)},
|
|
30446
30926
|
existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
30447
30927
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30448
30928
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30449
30929
|
logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30930
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
|
|
30450
30931
|
const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
30451
30932
|
const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
30452
|
-
if (isHFTooLow || isHFTooHigh) {
|
|
30933
|
+
if (isHFTooLow || isHFTooHigh || 1) {
|
|
30453
30934
|
const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
30454
30935
|
isDeposit: true,
|
|
30455
30936
|
leg1DepositAmount: unusedBalance.amount,
|
|
30456
|
-
minHF: 1.02
|
|
30937
|
+
minHF: 1.02,
|
|
30457
30938
|
// todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
30939
|
+
vesuAdapter
|
|
30458
30940
|
});
|
|
30459
30941
|
return { shouldRebalance: true, manageCall };
|
|
30460
30942
|
} else {
|
|
@@ -30487,7 +30969,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30487
30969
|
async _getMinOutputAmountLSTBuy(amountInUnderlying) {
|
|
30488
30970
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
30489
30971
|
const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
|
|
30490
|
-
return minOutputAmount;
|
|
30972
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
30491
30973
|
}
|
|
30492
30974
|
async _getMinOutputAmountLSTSell(amountInLST) {
|
|
30493
30975
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
@@ -30544,21 +31026,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30544
31026
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
30545
31027
|
return vesuAdapter1.config.debt;
|
|
30546
31028
|
}
|
|
30547
|
-
async getMaxBorrowableAmount() {
|
|
31029
|
+
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
30548
31030
|
const vesuAdapters = this.getVesuAdapters();
|
|
30549
31031
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
30550
31032
|
const maxBorrowables = [];
|
|
30551
|
-
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30552
|
-
const maxInterestRate = lstAPY * 0.8;
|
|
30553
31033
|
for (const vesuAdapter of vesuAdapters) {
|
|
30554
|
-
|
|
30555
|
-
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
30556
|
-
maxBorrowables.push({ amount: maxBorrowableAmount.minimum(debtCap), borrowableAsset: vesuAdapter.config.debt });
|
|
31034
|
+
maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
|
|
30557
31035
|
}
|
|
30558
31036
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
30559
31037
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
30560
31038
|
return { netMaxBorrowableAmount, maxBorrowables };
|
|
30561
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
|
+
}
|
|
30562
31075
|
// todo how much to unwind to get back healthy APY zone again
|
|
30563
31076
|
// if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
|
|
30564
31077
|
// For xSTRK, simply deposit in Vesu if looping is not viable
|
|
@@ -30582,7 +31095,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30582
31095
|
// todo undo this
|
|
30583
31096
|
async netAPY() {
|
|
30584
31097
|
const unusedBalance = await this.getUnusedBalance();
|
|
30585
|
-
const maxNewDeposits = await this.maxNewDeposits();
|
|
31098
|
+
const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
30586
31099
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30587
31100
|
if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
30588
31101
|
logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
|
|
@@ -30599,8 +31112,8 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30599
31112
|
return output;
|
|
30600
31113
|
}
|
|
30601
31114
|
}
|
|
30602
|
-
async maxNewDeposits() {
|
|
30603
|
-
const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
|
|
31115
|
+
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
31116
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
30604
31117
|
let ltv = void 0;
|
|
30605
31118
|
for (let adapter of this.getVesuAdapters()) {
|
|
30606
31119
|
const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
|
|
@@ -30703,7 +31216,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30703
31216
|
const manageCall2 = manage2Info.callConstructor({
|
|
30704
31217
|
delegation: true
|
|
30705
31218
|
});
|
|
30706
|
-
const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU
|
|
31219
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
30707
31220
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
30708
31221
|
const multiplyParams = params.isIncrease ? {
|
|
30709
31222
|
isIncrease: true,
|
|
@@ -30787,6 +31300,12 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
|
|
|
30787
31300
|
function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
30788
31301
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
30789
31302
|
}
|
|
31303
|
+
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
31304
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31305
|
+
}
|
|
31306
|
+
function getVesuLegId(baseID, debtTokenSymbol) {
|
|
31307
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31308
|
+
}
|
|
30790
31309
|
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
30791
31310
|
vaultSettings.leafAdapters = [];
|
|
30792
31311
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
@@ -30796,7 +31315,7 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30796
31315
|
collateral: lstToken,
|
|
30797
31316
|
debt: underlyingToken,
|
|
30798
31317
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
30799
|
-
id: "vesu_leg1" /* VESU_LEG1
|
|
31318
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
30800
31319
|
});
|
|
30801
31320
|
const commonAdapter = new CommonAdapter({
|
|
30802
31321
|
manager: vaultSettings.manager,
|
|
@@ -30805,25 +31324,39 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30805
31324
|
vaultAddress: vaultSettings.vaultAddress,
|
|
30806
31325
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
30807
31326
|
});
|
|
30808
|
-
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
30809
|
-
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
30810
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
30811
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter("multiply_vesu" /* MULTIPLY_VESU */).bind(vesuAdapterLST));
|
|
30812
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
30813
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
30814
31327
|
vaultSettings.adapters.push(...[{
|
|
30815
|
-
id: "
|
|
31328
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
30816
31329
|
adapter: vesuAdapterLST
|
|
30817
31330
|
}, {
|
|
30818
31331
|
id: "common_adapter" /* COMMON */,
|
|
30819
31332
|
adapter: commonAdapter
|
|
30820
31333
|
}]);
|
|
30821
|
-
|
|
30822
|
-
|
|
30823
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address,
|
|
30824
|
-
vaultSettings.leafAdapters.push(
|
|
30825
|
-
vaultSettings.leafAdapters.push(
|
|
30826
|
-
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
|
+
}
|
|
30827
31360
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30828
31361
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30829
31362
|
vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
|
|
@@ -30901,7 +31434,8 @@ var hyperxSTRK = {
|
|
|
30901
31434
|
adapters: [],
|
|
30902
31435
|
targetHealthFactor: 1.1,
|
|
30903
31436
|
minHealthFactor: 1.05,
|
|
30904
|
-
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")
|
|
30905
31439
|
};
|
|
30906
31440
|
var hyperxWBTC = {
|
|
30907
31441
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -30913,7 +31447,8 @@ var hyperxWBTC = {
|
|
|
30913
31447
|
adapters: [],
|
|
30914
31448
|
targetHealthFactor: 1.1,
|
|
30915
31449
|
minHealthFactor: 1.05,
|
|
30916
|
-
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")
|
|
30917
31452
|
};
|
|
30918
31453
|
var hyperxtBTC = {
|
|
30919
31454
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -30925,7 +31460,8 @@ var hyperxtBTC = {
|
|
|
30925
31460
|
adapters: [],
|
|
30926
31461
|
targetHealthFactor: 1.1,
|
|
30927
31462
|
minHealthFactor: 1.05,
|
|
30928
|
-
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")
|
|
30929
31465
|
};
|
|
30930
31466
|
var hyperxsBTC = {
|
|
30931
31467
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -30937,7 +31473,8 @@ var hyperxsBTC = {
|
|
|
30937
31473
|
adapters: [],
|
|
30938
31474
|
targetHealthFactor: 1.1,
|
|
30939
31475
|
minHealthFactor: 1.05,
|
|
30940
|
-
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")
|
|
30941
31478
|
};
|
|
30942
31479
|
var hyperxLBTC = {
|
|
30943
31480
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -30949,7 +31486,8 @@ var hyperxLBTC = {
|
|
|
30949
31486
|
adapters: [],
|
|
30950
31487
|
targetHealthFactor: 1.1,
|
|
30951
31488
|
minHealthFactor: 1.05,
|
|
30952
|
-
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")
|
|
30953
31491
|
};
|
|
30954
31492
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
30955
31493
|
return [
|
|
@@ -31652,6 +32190,7 @@ var Deployer = {
|
|
|
31652
32190
|
var deployer_default = Deployer;
|
|
31653
32191
|
// Annotate the CommonJS export names for ESM import in node:
|
|
31654
32192
|
0 && (module.exports = {
|
|
32193
|
+
APYType,
|
|
31655
32194
|
AUMTypes,
|
|
31656
32195
|
AVNU_EXCHANGE,
|
|
31657
32196
|
AVNU_MIDDLEWARE,
|