@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.mjs
CHANGED
|
@@ -315,6 +315,25 @@ var defaultTokens = [{
|
|
|
315
315
|
priceProxySymbol: "WBTC",
|
|
316
316
|
priceCheckAmount: 1e-4
|
|
317
317
|
// 112000 * 0.0001 = $11.2
|
|
318
|
+
}, {
|
|
319
|
+
name: "mRe7BTC",
|
|
320
|
+
symbol: "mRe7BTC",
|
|
321
|
+
logo: "https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/3a62ecee-1e58-45d3-9862-3ce90dff1900/logo",
|
|
322
|
+
address: ContractAddr.from("0x4e4fb1a9ca7e84bae609b9dc0078ad7719e49187ae7e425bb47d131710eddac"),
|
|
323
|
+
decimals: 18,
|
|
324
|
+
coingeckId: void 0,
|
|
325
|
+
displayDecimals: 6,
|
|
326
|
+
priceCheckAmount: 1e-4
|
|
327
|
+
// 112000 * 0.0001 = $11.2
|
|
328
|
+
}, {
|
|
329
|
+
name: "mRe7YIELD",
|
|
330
|
+
symbol: "mRe7YIELD",
|
|
331
|
+
logo: "https://midas.app/assets/mre7-BcOOHm7i.svg",
|
|
332
|
+
address: ContractAddr.from("0x4be8945e61dc3e19ebadd1579a6bd53b262f51ba89e6f8b0c4bc9a7e3c633fc"),
|
|
333
|
+
decimals: 18,
|
|
334
|
+
coingeckId: void 0,
|
|
335
|
+
displayDecimals: 2,
|
|
336
|
+
priceCheckAmount: 100
|
|
318
337
|
}];
|
|
319
338
|
var tokens = defaultTokens;
|
|
320
339
|
var _Global = class _Global {
|
|
@@ -2208,16 +2227,16 @@ var AvnuWrapper = class _AvnuWrapper {
|
|
|
2208
2227
|
};
|
|
2209
2228
|
return swapInfo;
|
|
2210
2229
|
}
|
|
2211
|
-
static buildZeroSwap(tokenToSell,
|
|
2230
|
+
static buildZeroSwap(tokenToSell, beneficiary, tokenToBuy = tokenToSell) {
|
|
2212
2231
|
return {
|
|
2213
2232
|
token_from_address: tokenToSell.address,
|
|
2214
2233
|
token_from_amount: uint256.bnToUint256(0),
|
|
2215
|
-
token_to_address:
|
|
2234
|
+
token_to_address: tokenToBuy.address,
|
|
2216
2235
|
token_to_amount: uint256.bnToUint256(0),
|
|
2217
2236
|
token_to_min_amount: uint256.bnToUint256(0),
|
|
2218
|
-
beneficiary
|
|
2237
|
+
beneficiary,
|
|
2219
2238
|
integrator_fee_amount_bps: 0,
|
|
2220
|
-
integrator_fee_recipient:
|
|
2239
|
+
integrator_fee_recipient: beneficiary,
|
|
2221
2240
|
routes: []
|
|
2222
2241
|
};
|
|
2223
2242
|
}
|
|
@@ -4018,21 +4037,20 @@ var Harvests = class _Harvests {
|
|
|
4018
4037
|
const rewards = await this.getHarvests(addr);
|
|
4019
4038
|
if (rewards.length == 0) return [];
|
|
4020
4039
|
const unClaimed = [];
|
|
4021
|
-
const
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
}
|
|
4029
|
-
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4030
|
-
if (bal.lessThan(reward.claim.amount)) {
|
|
4031
|
-
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4032
|
-
continue;
|
|
4033
|
-
}
|
|
4034
|
-
unClaimed.unshift(reward);
|
|
4040
|
+
const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
|
|
4041
|
+
const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
|
|
4042
|
+
const contract = new Contract4({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
|
|
4043
|
+
const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
|
|
4044
|
+
logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
|
|
4045
|
+
if (isClaimed) {
|
|
4046
|
+
return unClaimed;
|
|
4035
4047
|
}
|
|
4048
|
+
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4049
|
+
if (bal.lessThan(reward.claim.amount)) {
|
|
4050
|
+
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4051
|
+
return unClaimed;
|
|
4052
|
+
}
|
|
4053
|
+
unClaimed.unshift(reward);
|
|
4036
4054
|
return unClaimed;
|
|
4037
4055
|
}
|
|
4038
4056
|
};
|
|
@@ -15299,6 +15317,91 @@ var apolloClient = new ApolloClient({
|
|
|
15299
15317
|
});
|
|
15300
15318
|
var apollo_client_default = apolloClient;
|
|
15301
15319
|
|
|
15320
|
+
// src/utils/math-utils.ts
|
|
15321
|
+
async function binarySearch(lowWei, highWei, callback) {
|
|
15322
|
+
while (lowWei <= highWei) {
|
|
15323
|
+
const diff = highWei - lowWei;
|
|
15324
|
+
const mid = lowWei + diff / 2n;
|
|
15325
|
+
const result = await callback(mid);
|
|
15326
|
+
if (result === "found") {
|
|
15327
|
+
return mid;
|
|
15328
|
+
} else if (result == "retry") {
|
|
15329
|
+
} else if (result === "go_low") {
|
|
15330
|
+
highWei = mid - BigInt(1);
|
|
15331
|
+
} else {
|
|
15332
|
+
lowWei = mid + BigInt(1);
|
|
15333
|
+
}
|
|
15334
|
+
}
|
|
15335
|
+
return null;
|
|
15336
|
+
}
|
|
15337
|
+
async function findMaxInputWithSlippage(options) {
|
|
15338
|
+
const {
|
|
15339
|
+
apiGetOutput,
|
|
15340
|
+
maxInput,
|
|
15341
|
+
maxSlippagePercent,
|
|
15342
|
+
tolerance,
|
|
15343
|
+
minInput = 0,
|
|
15344
|
+
referenceAmountMultiplier = 1e-3,
|
|
15345
|
+
referenceRate = 0
|
|
15346
|
+
} = options;
|
|
15347
|
+
let apiCalls = 0;
|
|
15348
|
+
if (!referenceRate && !referenceAmountMultiplier) {
|
|
15349
|
+
throw new Error("One of referenceRate or referenceAmountMultiplier must be provided");
|
|
15350
|
+
}
|
|
15351
|
+
let _referenceRate = referenceRate;
|
|
15352
|
+
if (!_referenceRate) {
|
|
15353
|
+
const smallAmount = maxInput * referenceAmountMultiplier;
|
|
15354
|
+
const referenceOutput = await apiGetOutput(smallAmount);
|
|
15355
|
+
apiCalls++;
|
|
15356
|
+
_referenceRate = referenceOutput / smallAmount;
|
|
15357
|
+
}
|
|
15358
|
+
async function checkSlippage(inputAmount) {
|
|
15359
|
+
const actualOutput = await apiGetOutput(inputAmount);
|
|
15360
|
+
apiCalls++;
|
|
15361
|
+
const expectedOutput = inputAmount * referenceRate;
|
|
15362
|
+
const slippage = (expectedOutput - actualOutput) / expectedOutput;
|
|
15363
|
+
logger.verbose(`findMaxInputWithSlippage::checkSlippage inputAmount: ${inputAmount}, actualOutput: ${actualOutput}, slippage: ${slippage}, maxSlippagePercent: ${maxSlippagePercent}`);
|
|
15364
|
+
return {
|
|
15365
|
+
acceptable: slippage <= maxSlippagePercent,
|
|
15366
|
+
slippage,
|
|
15367
|
+
output: actualOutput
|
|
15368
|
+
};
|
|
15369
|
+
}
|
|
15370
|
+
const maxCheck = await checkSlippage(maxInput);
|
|
15371
|
+
if (maxCheck.acceptable) {
|
|
15372
|
+
return {
|
|
15373
|
+
optimalInput: maxInput,
|
|
15374
|
+
actualOutput: maxCheck.output,
|
|
15375
|
+
actualSlippage: maxCheck.slippage,
|
|
15376
|
+
apiCallsUsed: apiCalls
|
|
15377
|
+
};
|
|
15378
|
+
}
|
|
15379
|
+
let left = minInput;
|
|
15380
|
+
let right = maxInput;
|
|
15381
|
+
let bestInput = minInput;
|
|
15382
|
+
let bestOutput = 0;
|
|
15383
|
+
let bestSlippage = 0;
|
|
15384
|
+
const convergenceThreshold = tolerance * maxInput;
|
|
15385
|
+
while (right - left > convergenceThreshold) {
|
|
15386
|
+
const mid = (left + right) / 2;
|
|
15387
|
+
const midCheck = await checkSlippage(mid);
|
|
15388
|
+
if (midCheck.acceptable) {
|
|
15389
|
+
bestInput = mid;
|
|
15390
|
+
bestOutput = midCheck.output;
|
|
15391
|
+
bestSlippage = midCheck.slippage;
|
|
15392
|
+
left = mid;
|
|
15393
|
+
} else {
|
|
15394
|
+
right = mid;
|
|
15395
|
+
}
|
|
15396
|
+
}
|
|
15397
|
+
return {
|
|
15398
|
+
optimalInput: bestInput,
|
|
15399
|
+
actualOutput: bestOutput,
|
|
15400
|
+
actualSlippage: bestSlippage,
|
|
15401
|
+
apiCallsUsed: apiCalls
|
|
15402
|
+
};
|
|
15403
|
+
}
|
|
15404
|
+
|
|
15302
15405
|
// src/strategies/ekubo-cl-vault.tsx
|
|
15303
15406
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
15304
15407
|
var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
@@ -15585,7 +15688,6 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
15585
15688
|
for (let i = len - 1; i >= 0; --i) {
|
|
15586
15689
|
let record = await this.contract.call("get_rewards_info", [i]);
|
|
15587
15690
|
logger.verbose(`${_EkuboCLVault.name}: getHarvestRewardShares: ${i}`);
|
|
15588
|
-
console.log(record);
|
|
15589
15691
|
const block = Number(record.block_number);
|
|
15590
15692
|
if (block < fromBlock) {
|
|
15591
15693
|
return shares;
|
|
@@ -15785,16 +15887,10 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
15785
15887
|
const sqrtRatio = _EkuboCLVault.div2Power128(
|
|
15786
15888
|
BigInt(priceInfo.sqrt_ratio.toString())
|
|
15787
15889
|
);
|
|
15788
|
-
console.log(
|
|
15789
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, sqrtRatio: ${sqrtRatio}, ${priceInfo.sqrt_ratio.toString()}`
|
|
15790
|
-
);
|
|
15791
15890
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
15792
15891
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
15793
15892
|
const price = sqrtRatio * sqrtRatio * 10 ** token0Info.decimals / 10 ** token1Info.decimals;
|
|
15794
15893
|
const tick = priceInfo.tick;
|
|
15795
|
-
console.log(
|
|
15796
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, price: ${price}, tick: ${tick.mag}, ${tick.sign}`
|
|
15797
|
-
);
|
|
15798
15894
|
return {
|
|
15799
15895
|
price,
|
|
15800
15896
|
tick: Number(tick.mag) * (tick.sign ? -1 : 1),
|
|
@@ -16421,62 +16517,193 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16421
16517
|
logger.verbose(
|
|
16422
16518
|
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
16423
16519
|
);
|
|
16424
|
-
const
|
|
16425
|
-
|
|
16520
|
+
const isRewardTokenMatch = claim.token.eq(poolKey.token0) || claim.token.eq(poolKey.token1);
|
|
16521
|
+
if (isRewardTokenMatch) {
|
|
16522
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMatchHarvest({
|
|
16523
|
+
acc,
|
|
16524
|
+
claim,
|
|
16525
|
+
isToken1,
|
|
16526
|
+
token0Info,
|
|
16527
|
+
token1Info,
|
|
16528
|
+
postFeeAmount,
|
|
16529
|
+
poolKey,
|
|
16530
|
+
bounds,
|
|
16531
|
+
maxIterations,
|
|
16532
|
+
priceRatioPrecision
|
|
16533
|
+
});
|
|
16534
|
+
calls.push(..._callsFinal);
|
|
16535
|
+
} else {
|
|
16536
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMismatchHarvest({
|
|
16537
|
+
claim,
|
|
16538
|
+
token0Info,
|
|
16539
|
+
token1Info,
|
|
16540
|
+
postFeeAmount,
|
|
16541
|
+
poolKey,
|
|
16542
|
+
bounds,
|
|
16543
|
+
maxIterations,
|
|
16544
|
+
priceRatioPrecision,
|
|
16545
|
+
acc
|
|
16546
|
+
});
|
|
16547
|
+
calls.push(..._callsFinal);
|
|
16548
|
+
}
|
|
16549
|
+
}
|
|
16550
|
+
return calls;
|
|
16551
|
+
}
|
|
16552
|
+
/**
|
|
16553
|
+
* @description This funciton requires atleast one of the pool tokens to be reward token
|
|
16554
|
+
* i.e. STRK.
|
|
16555
|
+
* @param params
|
|
16556
|
+
*/
|
|
16557
|
+
async _handleRewardAndVaultTokenMatchHarvest(params) {
|
|
16558
|
+
const { acc, claim, isToken1, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
16559
|
+
const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
|
|
16560
|
+
const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
|
|
16561
|
+
logger.verbose(
|
|
16562
|
+
`${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
|
|
16563
|
+
);
|
|
16564
|
+
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
16565
|
+
poolKey,
|
|
16566
|
+
token0Amt,
|
|
16567
|
+
token1Amt,
|
|
16568
|
+
bounds,
|
|
16569
|
+
maxIterations,
|
|
16570
|
+
priceRatioPrecision
|
|
16571
|
+
);
|
|
16572
|
+
swapInfo.token_to_address = token0Info.address.address;
|
|
16573
|
+
logger.verbose(
|
|
16574
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
16575
|
+
);
|
|
16576
|
+
logger.verbose(
|
|
16577
|
+
`${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
16578
|
+
);
|
|
16579
|
+
const harvestEstimateCall = async (swapInfo1) => {
|
|
16580
|
+
const swap1Amount = Web3Number.fromWei(
|
|
16581
|
+
uint2564.uint256ToBN(swapInfo1.token_from_amount).toString(),
|
|
16582
|
+
18
|
|
16583
|
+
// cause its always STRK?
|
|
16584
|
+
).minimum(
|
|
16585
|
+
postFeeAmount.toFixed(18)
|
|
16586
|
+
// cause always strk
|
|
16587
|
+
);
|
|
16588
|
+
swapInfo.token_from_amount = uint2564.bnToUint256(swap1Amount.toWei());
|
|
16589
|
+
swapInfo.token_to_min_amount = uint2564.bnToUint256(
|
|
16590
|
+
swap1Amount.multipliedBy(0).toWei()
|
|
16591
|
+
// placeholder
|
|
16592
|
+
);
|
|
16426
16593
|
logger.verbose(
|
|
16427
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16594
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
16428
16595
|
);
|
|
16429
|
-
const
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
token1Amt,
|
|
16433
|
-
bounds,
|
|
16434
|
-
maxIterations,
|
|
16435
|
-
priceRatioPrecision
|
|
16596
|
+
const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
|
|
16597
|
+
logger.verbose(
|
|
16598
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
16436
16599
|
);
|
|
16437
|
-
|
|
16600
|
+
const swapInfo2 = {
|
|
16601
|
+
...swapInfo,
|
|
16602
|
+
token_from_amount: uint2564.bnToUint256(remainingAmount.toWei())
|
|
16603
|
+
};
|
|
16604
|
+
swapInfo2.token_to_address = token1Info.address.address;
|
|
16438
16605
|
logger.verbose(
|
|
16439
|
-
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16606
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16607
|
+
swapInfo
|
|
16608
|
+
)}`
|
|
16440
16609
|
);
|
|
16441
16610
|
logger.verbose(
|
|
16442
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16611
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
16612
|
+
swapInfo2
|
|
16613
|
+
)}`
|
|
16443
16614
|
);
|
|
16444
|
-
const
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
16471
|
-
|
|
16472
|
-
|
|
16473
|
-
|
|
16474
|
-
|
|
16475
|
-
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
|
|
16479
|
-
|
|
16615
|
+
const calldata = [
|
|
16616
|
+
claim.rewardsContract.address,
|
|
16617
|
+
{
|
|
16618
|
+
id: claim.claim.id,
|
|
16619
|
+
amount: claim.claim.amount.toWei(),
|
|
16620
|
+
claimee: claim.claim.claimee.address
|
|
16621
|
+
},
|
|
16622
|
+
claim.proof.map((p) => num5.getDecimalString(p)),
|
|
16623
|
+
swapInfo,
|
|
16624
|
+
swapInfo2
|
|
16625
|
+
];
|
|
16626
|
+
logger.verbose(
|
|
16627
|
+
`${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
16628
|
+
calldata
|
|
16629
|
+
)}`
|
|
16630
|
+
);
|
|
16631
|
+
return [this.contract.populate("harvest", calldata)];
|
|
16632
|
+
};
|
|
16633
|
+
const _callsFinal = await this.rebalanceIter(
|
|
16634
|
+
swapInfo,
|
|
16635
|
+
acc,
|
|
16636
|
+
harvestEstimateCall,
|
|
16637
|
+
claim.token.eq(poolKey.token0),
|
|
16638
|
+
0,
|
|
16639
|
+
0n,
|
|
16640
|
+
BigInt(postFeeAmount.toWei())
|
|
16641
|
+
// upper limit is the post fee amount
|
|
16642
|
+
);
|
|
16643
|
+
logger.verbose(
|
|
16644
|
+
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
16645
|
+
_callsFinal
|
|
16646
|
+
)}`
|
|
16647
|
+
);
|
|
16648
|
+
return _callsFinal;
|
|
16649
|
+
}
|
|
16650
|
+
/**
|
|
16651
|
+
* @description This function handles harvesting of reward token that is not the same as any of the vault token
|
|
16652
|
+
* i.e. STRK is not part of vault tokens like BTC/ETH
|
|
16653
|
+
* @param params
|
|
16654
|
+
* @returns
|
|
16655
|
+
*/
|
|
16656
|
+
async _handleRewardAndVaultTokenMismatchHarvest(params) {
|
|
16657
|
+
const { acc, claim, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
16658
|
+
let token0Amt = postFeeAmount;
|
|
16659
|
+
const beneficiary = this.address.address;
|
|
16660
|
+
let harvestCall = null;
|
|
16661
|
+
harvestCall = await this.harvestMismatchEstimateCallFn({
|
|
16662
|
+
postFeeAmount,
|
|
16663
|
+
claim,
|
|
16664
|
+
token0Info,
|
|
16665
|
+
token1Info,
|
|
16666
|
+
acc
|
|
16667
|
+
});
|
|
16668
|
+
if (!harvestCall) {
|
|
16669
|
+
throw new Error("Harvest call not found");
|
|
16670
|
+
}
|
|
16671
|
+
return [harvestCall];
|
|
16672
|
+
}
|
|
16673
|
+
// given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
|
|
16674
|
+
// amount for binary search
|
|
16675
|
+
async harvestMismatchEstimateCallFn(params) {
|
|
16676
|
+
const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
|
|
16677
|
+
let harvestCall = null;
|
|
16678
|
+
const binarySearchCallbackFn = async (mid) => {
|
|
16679
|
+
const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
|
|
16680
|
+
const avnuWrapper = new AvnuWrapper();
|
|
16681
|
+
const beneficiary = this.address.address;
|
|
16682
|
+
const quote1 = await avnuWrapper.getQuotes(
|
|
16683
|
+
claim.token.address,
|
|
16684
|
+
token0Info.address.address,
|
|
16685
|
+
mid.toString(),
|
|
16686
|
+
beneficiary
|
|
16687
|
+
);
|
|
16688
|
+
const swapInfo1 = await avnuWrapper.getSwapInfo(
|
|
16689
|
+
quote1,
|
|
16690
|
+
beneficiary,
|
|
16691
|
+
0,
|
|
16692
|
+
beneficiary
|
|
16693
|
+
);
|
|
16694
|
+
const quote2 = await avnuWrapper.getQuotes(
|
|
16695
|
+
claim.token.address,
|
|
16696
|
+
token1Info.address.address,
|
|
16697
|
+
rewardPart2.toString(),
|
|
16698
|
+
beneficiary
|
|
16699
|
+
);
|
|
16700
|
+
const swapInfo2 = await avnuWrapper.getSwapInfo(
|
|
16701
|
+
quote2,
|
|
16702
|
+
beneficiary,
|
|
16703
|
+
0,
|
|
16704
|
+
beneficiary
|
|
16705
|
+
);
|
|
16706
|
+
try {
|
|
16480
16707
|
const calldata = [
|
|
16481
16708
|
claim.rewardsContract.address,
|
|
16482
16709
|
{
|
|
@@ -16485,34 +16712,23 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16485
16712
|
claimee: claim.claim.claimee.address
|
|
16486
16713
|
},
|
|
16487
16714
|
claim.proof.map((p) => num5.getDecimalString(p)),
|
|
16488
|
-
|
|
16715
|
+
swapInfo1,
|
|
16489
16716
|
swapInfo2
|
|
16490
16717
|
];
|
|
16491
|
-
|
|
16492
|
-
|
|
16493
|
-
|
|
16494
|
-
|
|
16495
|
-
)
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
BigInt(postFeeAmount.toWei())
|
|
16506
|
-
// upper limit is the post fee amount
|
|
16507
|
-
);
|
|
16508
|
-
logger.verbose(
|
|
16509
|
-
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
16510
|
-
_callsFinal
|
|
16511
|
-
)}`
|
|
16512
|
-
);
|
|
16513
|
-
calls.push(..._callsFinal);
|
|
16514
|
-
}
|
|
16515
|
-
return calls;
|
|
16718
|
+
harvestCall = this.contract.populate("harvest", calldata);
|
|
16719
|
+
const gas = await acc.estimateInvokeFee(harvestCall);
|
|
16720
|
+
return "found";
|
|
16721
|
+
} catch (err) {
|
|
16722
|
+
if (err.message.includes("invalid token0 amount")) {
|
|
16723
|
+
return "go_low";
|
|
16724
|
+
} else if (err.message.includes("invalid token1 amount")) {
|
|
16725
|
+
return "go_high";
|
|
16726
|
+
}
|
|
16727
|
+
return "retry";
|
|
16728
|
+
}
|
|
16729
|
+
};
|
|
16730
|
+
await binarySearch(0n, BigInt(postFeeAmount.toWei()), binarySearchCallbackFn);
|
|
16731
|
+
return harvestCall;
|
|
16516
16732
|
}
|
|
16517
16733
|
async getInvestmentFlows() {
|
|
16518
16734
|
const netYield = await this.netAPY();
|
|
@@ -19044,7 +19260,58 @@ function toBigInt(value) {
|
|
|
19044
19260
|
}
|
|
19045
19261
|
|
|
19046
19262
|
// src/strategies/universal-adapters/baseAdapter.ts
|
|
19263
|
+
var APYType = /* @__PURE__ */ ((APYType2) => {
|
|
19264
|
+
APYType2["BASE"] = "base";
|
|
19265
|
+
APYType2["REWARD"] = "reward";
|
|
19266
|
+
APYType2["LST"] = "lst";
|
|
19267
|
+
return APYType2;
|
|
19268
|
+
})(APYType || {});
|
|
19047
19269
|
var BaseAdapter = class extends CacheClass {
|
|
19270
|
+
// readonly config: BaseAdapterConfig;
|
|
19271
|
+
// constructor(config: BaseAdapterConfig) {
|
|
19272
|
+
// super();
|
|
19273
|
+
// this.config = config;
|
|
19274
|
+
// }
|
|
19275
|
+
constructor() {
|
|
19276
|
+
super();
|
|
19277
|
+
}
|
|
19278
|
+
// /**
|
|
19279
|
+
// * Loop through all supported positions and return amount, usd value, remarks and apy for each
|
|
19280
|
+
// */
|
|
19281
|
+
// async getPositions(): Promise<PositionInfo[]> {
|
|
19282
|
+
// const results: PositionInfo[] = [];
|
|
19283
|
+
// for (const supported of this.config.supportedPositions) {
|
|
19284
|
+
// const amount = await this.getPosition(supported);
|
|
19285
|
+
// const usdValue = await this.getUSDValue(supported.asset, amount);
|
|
19286
|
+
// const apy = await this.getAPY(supported);
|
|
19287
|
+
// results.push({ amount, usdValue, apy });
|
|
19288
|
+
// }
|
|
19289
|
+
// return results;
|
|
19290
|
+
// }
|
|
19291
|
+
// /**
|
|
19292
|
+
// * Implemented by child adapters to compute APY for a given supported position
|
|
19293
|
+
// */
|
|
19294
|
+
// protected abstract getAPY(supportedPosition: SupportedPosition): Promise<PositionAPY>;
|
|
19295
|
+
// /**
|
|
19296
|
+
// * Implemented by child adapters to fetch amount for a given supported position
|
|
19297
|
+
// */
|
|
19298
|
+
// protected abstract getPosition(supportedPosition: SupportedPosition): Promise<Web3Number>;
|
|
19299
|
+
// /**
|
|
19300
|
+
// * Implemented by child adapters to calculate maximum deposit positions
|
|
19301
|
+
// * @param amount Optional amount in baseToken to deposit
|
|
19302
|
+
// */
|
|
19303
|
+
// protected abstract maxDeposit(amount?: Web3Number): Promise<PositionInfo[]>;
|
|
19304
|
+
// /**
|
|
19305
|
+
// * Implemented by child adapters to calculate maximum withdraw positions
|
|
19306
|
+
// */
|
|
19307
|
+
// protected abstract maxWithdraw(): Promise<PositionInfo[]>;
|
|
19308
|
+
// /**
|
|
19309
|
+
// * Uses pricer to convert an amount of an asset to USD value
|
|
19310
|
+
// */
|
|
19311
|
+
// protected async getUSDValue(asset: TokenInfo, amount: Web3Number): Promise<number> {
|
|
19312
|
+
// const priceInfo = await this.config.pricer.getPrice(asset.symbol);
|
|
19313
|
+
// return amount.toNumber() * priceInfo.price;
|
|
19314
|
+
// }
|
|
19048
19315
|
constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
|
|
19049
19316
|
const { id, target, method, packedArguments } = params;
|
|
19050
19317
|
return {
|
|
@@ -19062,6 +19329,94 @@ var BaseAdapter = class extends CacheClass {
|
|
|
19062
19329
|
]
|
|
19063
19330
|
};
|
|
19064
19331
|
}
|
|
19332
|
+
// /**
|
|
19333
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for deposit leaf construction
|
|
19334
|
+
// */
|
|
19335
|
+
// protected abstract _getDepositLeaf(): {
|
|
19336
|
+
// target: ContractAddr,
|
|
19337
|
+
// method: string,
|
|
19338
|
+
// packedArguments: bigint[],
|
|
19339
|
+
// sanitizer: ContractAddr,
|
|
19340
|
+
// id: string
|
|
19341
|
+
// }[];
|
|
19342
|
+
// /**
|
|
19343
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for withdraw leaf construction
|
|
19344
|
+
// */
|
|
19345
|
+
// protected abstract _getWithdrawLeaf(): {
|
|
19346
|
+
// target: ContractAddr,
|
|
19347
|
+
// method: string,
|
|
19348
|
+
// packedArguments: bigint[],
|
|
19349
|
+
// sanitizer: ContractAddr,
|
|
19350
|
+
// id: string
|
|
19351
|
+
// }[];
|
|
19352
|
+
// /**
|
|
19353
|
+
// * Returns deposit leaf adapter using configured proof id
|
|
19354
|
+
// */
|
|
19355
|
+
// getDepositLeaf(): AdapterLeafType<T1> {
|
|
19356
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
19357
|
+
// const leaves = leafConfigs.map(config => {
|
|
19358
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
19359
|
+
// const leaf = this.constructSimpleLeafData({
|
|
19360
|
+
// id: id,
|
|
19361
|
+
// target,
|
|
19362
|
+
// method,
|
|
19363
|
+
// packedArguments
|
|
19364
|
+
// }, sanitizer);
|
|
19365
|
+
// return leaf;
|
|
19366
|
+
// });
|
|
19367
|
+
// return { leaves, callConstructor: this.getDepositCall.bind(this) as unknown as GenerateCallFn<T1> };
|
|
19368
|
+
// }
|
|
19369
|
+
// /**
|
|
19370
|
+
// * Returns withdraw leaf adapter using configured proof id
|
|
19371
|
+
// */
|
|
19372
|
+
// getWithdrawLeaf(): AdapterLeafType<T2> {
|
|
19373
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
19374
|
+
// const leaves = leafConfigs.map(config => {
|
|
19375
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
19376
|
+
// const leaf = this.constructSimpleLeafData({
|
|
19377
|
+
// id: id,
|
|
19378
|
+
// target,
|
|
19379
|
+
// method,
|
|
19380
|
+
// packedArguments
|
|
19381
|
+
// }, sanitizer ?? SIMPLE_SANITIZER);
|
|
19382
|
+
// return leaf;
|
|
19383
|
+
// });
|
|
19384
|
+
// return { leaves, callConstructor: this.getWithdrawCall.bind(this) as unknown as GenerateCallFn<T2> };
|
|
19385
|
+
// }
|
|
19386
|
+
// /**
|
|
19387
|
+
// * Default deposit callConstructor: expects params as calldata (bigint[])
|
|
19388
|
+
// */
|
|
19389
|
+
// protected getDepositCall<T1 = bigint[]>(params: T1): ManageCall[] {
|
|
19390
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
19391
|
+
// return leafConfigs.map(config => {
|
|
19392
|
+
// const { target, method, sanitizer } = config;
|
|
19393
|
+
// return {
|
|
19394
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
19395
|
+
// call: {
|
|
19396
|
+
// contractAddress: target,
|
|
19397
|
+
// selector: hash.getSelectorFromName(method),
|
|
19398
|
+
// calldata: params as unknown as bigint[]
|
|
19399
|
+
// }
|
|
19400
|
+
// };
|
|
19401
|
+
// });
|
|
19402
|
+
// }
|
|
19403
|
+
// /**
|
|
19404
|
+
// * Default withdraw callConstructor: expects params as calldata (bigint[])
|
|
19405
|
+
// */
|
|
19406
|
+
// protected getWithdrawCall<T2 = bigint[]>(params: T2): ManageCall[] {
|
|
19407
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
19408
|
+
// return leafConfigs.map(config => {
|
|
19409
|
+
// const { target, method, sanitizer } = config;
|
|
19410
|
+
// return {
|
|
19411
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
19412
|
+
// call: {
|
|
19413
|
+
// contractAddress: target,
|
|
19414
|
+
// selector: hash.getSelectorFromName(method),
|
|
19415
|
+
// calldata: params as unknown as bigint[]
|
|
19416
|
+
// }
|
|
19417
|
+
// };
|
|
19418
|
+
// });
|
|
19419
|
+
// }
|
|
19065
19420
|
};
|
|
19066
19421
|
|
|
19067
19422
|
// src/strategies/universal-adapters/common-adapter.ts
|
|
@@ -26664,7 +27019,20 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26664
27019
|
}
|
|
26665
27020
|
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
26666
27021
|
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
|
|
26667
|
-
|
|
27022
|
+
if (!isV2) {
|
|
27023
|
+
throw new Error("getDebtCap is not supported for v1");
|
|
27024
|
+
}
|
|
27025
|
+
const currentDebt = await this.getCurrentDebtUtilisationAmount(config);
|
|
27026
|
+
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap currentDebt: ${currentDebt.toString()}`);
|
|
27027
|
+
return Web3Number.fromWei(output.debt_cap.toString(), this.config.debt.decimals).minus(currentDebt);
|
|
27028
|
+
}
|
|
27029
|
+
async getCurrentDebtUtilisationAmount(config) {
|
|
27030
|
+
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
27031
|
+
if (!isV2) {
|
|
27032
|
+
throw new Error("getCurrentDebtUtilisationAmount is not supported for v1");
|
|
27033
|
+
}
|
|
27034
|
+
const output = await contract.call("pairs", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27035
|
+
return new Web3Number((Number(output.total_nominal_debt) / 1e18).toFixed(9), this.config.debt.decimals);
|
|
26668
27036
|
}
|
|
26669
27037
|
async getMaxBorrowableByInterestRate(config, asset, maxBorrowAPY) {
|
|
26670
27038
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
@@ -26697,16 +27065,17 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26697
27065
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
26698
27066
|
const timeDelta = assetConfig.last_updated;
|
|
26699
27067
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
26700
|
-
const
|
|
27068
|
+
const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals);
|
|
27069
|
+
const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
|
|
26701
27070
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
26702
27071
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
26703
27072
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
26704
27073
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
26705
|
-
|
|
27074
|
+
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
26706
27075
|
return maxDebtToHave.minus(currentDebt);
|
|
26707
27076
|
}
|
|
26708
|
-
async getLTVConfig(config) {
|
|
26709
|
-
const CACHE_KEY =
|
|
27077
|
+
async getLTVConfig(config, blockNumber = "latest") {
|
|
27078
|
+
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
26710
27079
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26711
27080
|
if (cacheData) {
|
|
26712
27081
|
return cacheData;
|
|
@@ -26714,10 +27083,10 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26714
27083
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
26715
27084
|
let ltv = 0;
|
|
26716
27085
|
if (isV2) {
|
|
26717
|
-
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27086
|
+
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
26718
27087
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26719
27088
|
} else {
|
|
26720
|
-
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27089
|
+
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
26721
27090
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26722
27091
|
}
|
|
26723
27092
|
if (ltv == 0) {
|
|
@@ -26726,11 +27095,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26726
27095
|
this.setCache(CACHE_KEY, ltv, 3e5);
|
|
26727
27096
|
return this.getCache(CACHE_KEY);
|
|
26728
27097
|
}
|
|
26729
|
-
async getPositions(config) {
|
|
27098
|
+
async getPositions(config, blockNumber = "latest") {
|
|
26730
27099
|
if (!this.pricer) {
|
|
26731
27100
|
throw new Error("Pricer is not initialized");
|
|
26732
27101
|
}
|
|
26733
|
-
const CACHE_KEY =
|
|
27102
|
+
const CACHE_KEY = `positions_${blockNumber}`;
|
|
26734
27103
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26735
27104
|
if (cacheData) {
|
|
26736
27105
|
return cacheData;
|
|
@@ -26742,7 +27111,8 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26742
27111
|
this.config.collateral.address.address,
|
|
26743
27112
|
this.config.debt.address.address,
|
|
26744
27113
|
this.config.vaultAllocator.address
|
|
26745
|
-
]);
|
|
27114
|
+
], { blockIdentifier: blockNumber });
|
|
27115
|
+
console.log(output);
|
|
26746
27116
|
const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
|
|
26747
27117
|
const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
|
|
26748
27118
|
logger.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
|
|
@@ -26762,11 +27132,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26762
27132
|
this.setCache(CACHE_KEY, value, 6e4);
|
|
26763
27133
|
return value;
|
|
26764
27134
|
}
|
|
26765
|
-
async getCollateralization(config) {
|
|
27135
|
+
async getCollateralization(config, blockNumber = "latest") {
|
|
26766
27136
|
if (!this.pricer) {
|
|
26767
27137
|
throw new Error("Pricer is not initialized");
|
|
26768
27138
|
}
|
|
26769
|
-
const CACHE_KEY =
|
|
27139
|
+
const CACHE_KEY = `collateralization_${blockNumber}`;
|
|
26770
27140
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26771
27141
|
if (cacheData) {
|
|
26772
27142
|
return cacheData;
|
|
@@ -26778,7 +27148,7 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26778
27148
|
this.config.collateral.address.address,
|
|
26779
27149
|
this.config.debt.address.address,
|
|
26780
27150
|
this.config.vaultAllocator.address
|
|
26781
|
-
]);
|
|
27151
|
+
], { blockIdentifier: blockNumber });
|
|
26782
27152
|
const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
|
|
26783
27153
|
const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
|
|
26784
27154
|
const value = [{
|
|
@@ -26815,9 +27185,9 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26815
27185
|
ltv
|
|
26816
27186
|
};
|
|
26817
27187
|
}
|
|
26818
|
-
async getHealthFactor() {
|
|
26819
|
-
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
26820
|
-
const collateralisation = await this.getCollateralization(this.networkConfig);
|
|
27188
|
+
async getHealthFactor(blockNumber = "latest") {
|
|
27189
|
+
const ltv = await this.getLTVConfig(this.networkConfig, blockNumber);
|
|
27190
|
+
const collateralisation = await this.getCollateralization(this.networkConfig, blockNumber);
|
|
26821
27191
|
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
26822
27192
|
}
|
|
26823
27193
|
static async getVesuPools(retry = 0) {
|
|
@@ -29479,11 +29849,11 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29479
29849
|
vesuAdapter2.networkConfig = this.config;
|
|
29480
29850
|
return [vesuAdapter1, vesuAdapter2];
|
|
29481
29851
|
}
|
|
29482
|
-
async getVesuPositions() {
|
|
29852
|
+
async getVesuPositions(blockNumber = "latest") {
|
|
29483
29853
|
const adapters = this.getVesuAdapters();
|
|
29484
29854
|
const positions = [];
|
|
29485
29855
|
for (const adapter of adapters) {
|
|
29486
|
-
positions.push(...await adapter.getPositions(this.config));
|
|
29856
|
+
positions.push(...await adapter.getPositions(this.config, blockNumber));
|
|
29487
29857
|
}
|
|
29488
29858
|
return positions;
|
|
29489
29859
|
}
|
|
@@ -29552,8 +29922,8 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29552
29922
|
async getLSTAPR(address) {
|
|
29553
29923
|
return 0;
|
|
29554
29924
|
}
|
|
29555
|
-
async getVesuHealthFactors() {
|
|
29556
|
-
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
|
|
29925
|
+
async getVesuHealthFactors(blockNumber = "latest") {
|
|
29926
|
+
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor(blockNumber)));
|
|
29557
29927
|
}
|
|
29558
29928
|
async computeRebalanceConditionAndReturnCalls() {
|
|
29559
29929
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -30149,6 +30519,42 @@ var UniversalStrategies = [
|
|
|
30149
30519
|
|
|
30150
30520
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30151
30521
|
import { Contract as Contract10, uint256 as uint2569 } from "starknet";
|
|
30522
|
+
|
|
30523
|
+
// src/utils/health-factor-math.ts
|
|
30524
|
+
var HealthFactorMath = class {
|
|
30525
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
30526
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
30527
|
+
const denominator = collateralPrice * maxLTV;
|
|
30528
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
30529
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
30530
|
+
return netCollateral;
|
|
30531
|
+
}
|
|
30532
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
30533
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
30534
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
30535
|
+
return netCollateral.minus(collateralFromDebt);
|
|
30536
|
+
}
|
|
30537
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
30538
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30539
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
30540
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
30541
|
+
return healthFactor.toNumber();
|
|
30542
|
+
}
|
|
30543
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
30544
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30545
|
+
const denominator = targetHF - maxLTV;
|
|
30546
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
30547
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
30548
|
+
}
|
|
30549
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
30550
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30551
|
+
const denominator = targetHF * debtPrice;
|
|
30552
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
30553
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
30554
|
+
}
|
|
30555
|
+
};
|
|
30556
|
+
|
|
30557
|
+
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30152
30558
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
30153
30559
|
var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
|
|
30154
30560
|
constructor(config, pricer, metadata) {
|
|
@@ -30163,15 +30569,14 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30163
30569
|
}
|
|
30164
30570
|
}
|
|
30165
30571
|
asset() {
|
|
30166
|
-
|
|
30167
|
-
return vesuAdapter1.config.collateral;
|
|
30572
|
+
return this.getVesuSameTokenAdapter().config.collateral;
|
|
30168
30573
|
}
|
|
30169
30574
|
getTag() {
|
|
30170
30575
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
30171
30576
|
}
|
|
30172
30577
|
// Vesu adapter with LST and base token match
|
|
30173
30578
|
getVesuSameTokenAdapter() {
|
|
30174
|
-
const baseAdapter = this.getAdapter("
|
|
30579
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
30175
30580
|
baseAdapter.networkConfig = this.config;
|
|
30176
30581
|
baseAdapter.pricer = this.pricer;
|
|
30177
30582
|
return baseAdapter;
|
|
@@ -30219,20 +30624,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30219
30624
|
return price;
|
|
30220
30625
|
}
|
|
30221
30626
|
async getAvnuSwapMultiplyCall(params) {
|
|
30222
|
-
|
|
30223
|
-
|
|
30224
|
-
|
|
30225
|
-
|
|
30226
|
-
|
|
30627
|
+
assert(params.isDeposit, "Only deposit is supported in getAvnuSwapMultiplyCall");
|
|
30628
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
|
|
30629
|
+
const allVesuAdapters = this.getVesuAdapters();
|
|
30630
|
+
let remainingAmount = params.leg1DepositAmount;
|
|
30631
|
+
const lstExRate = await this.getLSTExchangeRate();
|
|
30632
|
+
const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
|
|
30633
|
+
const lstPrice = baseAssetPrice.price * lstExRate;
|
|
30634
|
+
for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
|
|
30635
|
+
const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
|
|
30636
|
+
const vesuAdapter = allVesuAdapters.find((adapter) => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
|
|
30637
|
+
if (!vesuAdapter) {
|
|
30638
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
|
|
30639
|
+
}
|
|
30640
|
+
const maxLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30641
|
+
const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
|
|
30642
|
+
const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
|
|
30643
|
+
maxBorrowable.amount,
|
|
30644
|
+
debtPrice.price,
|
|
30645
|
+
this.metadata.additionalInfo.targetHealthFactor,
|
|
30646
|
+
maxLTV,
|
|
30647
|
+
lstPrice,
|
|
30648
|
+
this.asset()
|
|
30649
|
+
);
|
|
30650
|
+
const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
|
|
30651
|
+
logger.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
|
|
30652
|
+
const call = await this._getAvnuDepositSwapLegCall({
|
|
30653
|
+
isDeposit: params.isDeposit,
|
|
30654
|
+
// adjust decimals of debt asset
|
|
30655
|
+
leg1DepositAmount: amountToDeposit,
|
|
30656
|
+
minHF: 1.1,
|
|
30657
|
+
// undo
|
|
30658
|
+
vesuAdapter
|
|
30659
|
+
});
|
|
30660
|
+
remainingAmount = remainingAmount.minus(amountToDeposit);
|
|
30661
|
+
return { call, vesuAdapter };
|
|
30662
|
+
}
|
|
30663
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
|
|
30227
30664
|
}
|
|
30228
30665
|
async _getAvnuDepositSwapLegCall(params) {
|
|
30666
|
+
const { vesuAdapter } = params;
|
|
30229
30667
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
|
|
30230
30668
|
assert(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
|
|
30231
|
-
const
|
|
30232
|
-
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
30669
|
+
const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30233
30670
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
30234
|
-
const existingPositions = await
|
|
30235
|
-
const collateralisation = await
|
|
30671
|
+
const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
30672
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30236
30673
|
const existingCollateralInfo = existingPositions[0];
|
|
30237
30674
|
const existingDebtInfo = existingPositions[1];
|
|
30238
30675
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
@@ -30240,11 +30677,40 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30240
30677
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30241
30678
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30242
30679
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30680
|
+
const debtTokenInfo = vesuAdapter.config.debt;
|
|
30681
|
+
let newDepositAmount = params.leg1DepositAmount;
|
|
30243
30682
|
const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
|
|
30244
30683
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
|
|
30245
|
-
const totalDebtAmount =
|
|
30246
|
-
|
|
30247
|
-
|
|
30684
|
+
const totalDebtAmount = new Web3Number(
|
|
30685
|
+
totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
|
|
30686
|
+
debtTokenInfo.decimals
|
|
30687
|
+
);
|
|
30688
|
+
let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
|
|
30689
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
|
|
30690
|
+
const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
|
|
30691
|
+
if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
|
|
30692
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
|
|
30693
|
+
return void 0;
|
|
30694
|
+
} else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
|
|
30695
|
+
debtAmount = maxBorrowable.amount.minimum(debtAmount);
|
|
30696
|
+
const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
|
|
30697
|
+
const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
|
|
30698
|
+
debtAmount.plus(existingDebtInfo.amount),
|
|
30699
|
+
debtPrice,
|
|
30700
|
+
params.minHF,
|
|
30701
|
+
legLTV,
|
|
30702
|
+
collateralPrice,
|
|
30703
|
+
this.asset()
|
|
30704
|
+
);
|
|
30705
|
+
newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
|
|
30706
|
+
if (newDepositAmount.lt(0)) {
|
|
30707
|
+
throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
|
|
30708
|
+
}
|
|
30709
|
+
if (newDebtUSDValue.toNumber() < 100) {
|
|
30710
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
|
|
30711
|
+
return void 0;
|
|
30712
|
+
}
|
|
30713
|
+
}
|
|
30248
30714
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
30249
30715
|
if (debtAmount.lt(0)) {
|
|
30250
30716
|
const lstDEXPrice = await this.getLSTDexPrice();
|
|
@@ -30256,32 +30722,34 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30256
30722
|
assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
30257
30723
|
return calls[0];
|
|
30258
30724
|
}
|
|
30725
|
+
console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
|
|
30259
30726
|
const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
|
|
30260
30727
|
const manage0Info = this.getProofs(STEP0);
|
|
30261
30728
|
const manageCall0 = manage0Info.callConstructor({
|
|
30262
|
-
amount:
|
|
30729
|
+
amount: newDepositAmount
|
|
30263
30730
|
});
|
|
30264
|
-
const STEP1 = "vesu_leg1" /* VESU_LEG1
|
|
30731
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30265
30732
|
const manage1Info = this.getProofs(STEP1);
|
|
30266
30733
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30267
|
-
collateralAmount:
|
|
30734
|
+
collateralAmount: newDepositAmount,
|
|
30268
30735
|
isAddCollateral: params.isDeposit,
|
|
30269
30736
|
debtAmount,
|
|
30270
30737
|
isBorrow: params.isDeposit
|
|
30271
30738
|
}));
|
|
30739
|
+
console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
30272
30740
|
const proofIds = [STEP0, STEP1];
|
|
30273
30741
|
const manageCalls = [manageCall0, manageCall1];
|
|
30274
30742
|
if (debtAmount.gt(0)) {
|
|
30275
|
-
const STEP2 = "
|
|
30743
|
+
const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30276
30744
|
const manage2Info = this.getProofs(STEP2);
|
|
30277
30745
|
const manageCall2 = manage2Info.callConstructor({
|
|
30278
30746
|
amount: debtAmount
|
|
30279
30747
|
});
|
|
30280
|
-
const
|
|
30748
|
+
const debtTokenInfo2 = vesuAdapter.config.debt;
|
|
30281
30749
|
const lstTokenInfo = this.asset();
|
|
30282
30750
|
const avnuModule = new AvnuWrapper();
|
|
30283
30751
|
const quote = await avnuModule.getQuotes(
|
|
30284
|
-
|
|
30752
|
+
debtTokenInfo2.address.address,
|
|
30285
30753
|
lstTokenInfo.address.address,
|
|
30286
30754
|
debtAmount.toWei(),
|
|
30287
30755
|
this.metadata.additionalInfo.vaultAllocator.address
|
|
@@ -30297,7 +30765,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30297
30765
|
minAmountWei
|
|
30298
30766
|
);
|
|
30299
30767
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
|
|
30300
|
-
const STEP3 = "
|
|
30768
|
+
const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30301
30769
|
const manage3Info = this.getProofs(STEP3);
|
|
30302
30770
|
const manageCall3 = manage3Info.callConstructor({
|
|
30303
30771
|
props: swapInfo
|
|
@@ -30315,7 +30783,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30315
30783
|
const manageCall4 = manage4Info.callConstructor({
|
|
30316
30784
|
amount: minAmount
|
|
30317
30785
|
});
|
|
30318
|
-
const STEP5 = "vesu_leg1" /* VESU_LEG1
|
|
30786
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30319
30787
|
const manage5Info = this.getProofs(STEP5);
|
|
30320
30788
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30321
30789
|
collateralAmount: minAmount,
|
|
@@ -30332,28 +30800,41 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30332
30800
|
}
|
|
30333
30801
|
// todo unwind or not deposit when the yield is bad.
|
|
30334
30802
|
async getLSTMultiplierRebalanceCall() {
|
|
30335
|
-
|
|
30336
|
-
|
|
30803
|
+
let shouldRebalance = false;
|
|
30804
|
+
const calls = [];
|
|
30805
|
+
const allVesuAdapters = this.getVesuAdapters().filter((vesuAdapter) => vesuAdapter.config.debt.symbol === "LBTC");
|
|
30806
|
+
for (const vesuAdapter of allVesuAdapters) {
|
|
30807
|
+
const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
|
|
30808
|
+
if (call.shouldRebalance && call.manageCall) {
|
|
30809
|
+
shouldRebalance = true;
|
|
30810
|
+
calls.push({ vesuAdapter, manageCall: call.manageCall });
|
|
30811
|
+
}
|
|
30812
|
+
}
|
|
30813
|
+
return { shouldRebalance, manageCalls: calls };
|
|
30814
|
+
}
|
|
30815
|
+
async _getLSTMultiplierRebalanceCall(vesuAdapter) {
|
|
30816
|
+
const positions = await vesuAdapter.getPositions(this.config);
|
|
30817
|
+
assert(positions.length == 2, "Rebalance call is only supported for 2 positions");
|
|
30337
30818
|
const existingCollateralInfo = positions[0];
|
|
30338
30819
|
const existingDebtInfo = positions[1];
|
|
30339
|
-
const unusedBalance =
|
|
30340
|
-
const
|
|
30341
|
-
const
|
|
30342
|
-
|
|
30343
|
-
const collateralisation = await vesuAdapter1.getCollateralization(this.config);
|
|
30344
|
-
logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
30820
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
30821
|
+
const healthFactor = await vesuAdapter.getHealthFactor();
|
|
30822
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30823
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
30345
30824
|
existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
30346
30825
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30347
30826
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30348
30827
|
logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30828
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
|
|
30349
30829
|
const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
30350
30830
|
const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
30351
|
-
if (isHFTooLow || isHFTooHigh) {
|
|
30831
|
+
if (isHFTooLow || isHFTooHigh || 1) {
|
|
30352
30832
|
const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
30353
30833
|
isDeposit: true,
|
|
30354
30834
|
leg1DepositAmount: unusedBalance.amount,
|
|
30355
|
-
minHF: 1.02
|
|
30835
|
+
minHF: 1.02,
|
|
30356
30836
|
// todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
30837
|
+
vesuAdapter
|
|
30357
30838
|
});
|
|
30358
30839
|
return { shouldRebalance: true, manageCall };
|
|
30359
30840
|
} else {
|
|
@@ -30386,7 +30867,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30386
30867
|
async _getMinOutputAmountLSTBuy(amountInUnderlying) {
|
|
30387
30868
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
30388
30869
|
const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
|
|
30389
|
-
return minOutputAmount;
|
|
30870
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
30390
30871
|
}
|
|
30391
30872
|
async _getMinOutputAmountLSTSell(amountInLST) {
|
|
30392
30873
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
@@ -30443,21 +30924,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30443
30924
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
30444
30925
|
return vesuAdapter1.config.debt;
|
|
30445
30926
|
}
|
|
30446
|
-
async getMaxBorrowableAmount() {
|
|
30927
|
+
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
30447
30928
|
const vesuAdapters = this.getVesuAdapters();
|
|
30448
30929
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
30449
30930
|
const maxBorrowables = [];
|
|
30450
|
-
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30451
|
-
const maxInterestRate = lstAPY * 0.8;
|
|
30452
30931
|
for (const vesuAdapter of vesuAdapters) {
|
|
30453
|
-
|
|
30454
|
-
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
30455
|
-
maxBorrowables.push({ amount: maxBorrowableAmount.minimum(debtCap), borrowableAsset: vesuAdapter.config.debt });
|
|
30932
|
+
maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
|
|
30456
30933
|
}
|
|
30457
30934
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
30458
30935
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
30459
30936
|
return { netMaxBorrowableAmount, maxBorrowables };
|
|
30460
30937
|
}
|
|
30938
|
+
// recursively, using binary search computes max swappable.
|
|
30939
|
+
// @dev assumes 1 token of from == 1 token of to
|
|
30940
|
+
async getMaxSwappableWithMaxSlippage(fromToken, toToken, maxSlippage, maxAmount) {
|
|
30941
|
+
const output = await findMaxInputWithSlippage({
|
|
30942
|
+
apiGetOutput: async (inputAmount) => {
|
|
30943
|
+
const ekuboQuoter = new EkuboQuoter(this.config);
|
|
30944
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
30945
|
+
const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
|
|
30946
|
+
return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
|
|
30947
|
+
},
|
|
30948
|
+
maxInput: maxAmount.toNumber(),
|
|
30949
|
+
maxSlippagePercent: maxSlippage,
|
|
30950
|
+
tolerance: 1e-3,
|
|
30951
|
+
referenceRate: 1
|
|
30952
|
+
});
|
|
30953
|
+
return new Web3Number(output.optimalInput, fromToken.decimals);
|
|
30954
|
+
}
|
|
30955
|
+
async getMaxBorrowableAmountByVesuAdapter(vesuAdapter, isAPYComputation) {
|
|
30956
|
+
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30957
|
+
const maxInterestRate = lstAPY * 0.8;
|
|
30958
|
+
const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
|
|
30959
|
+
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
30960
|
+
const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
|
|
30961
|
+
if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
|
|
30962
|
+
return { amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
30963
|
+
}
|
|
30964
|
+
try {
|
|
30965
|
+
const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 2e-4, maxBorrowable);
|
|
30966
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
30967
|
+
} catch (error) {
|
|
30968
|
+
logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
|
|
30969
|
+
const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
|
|
30970
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
30971
|
+
}
|
|
30972
|
+
}
|
|
30461
30973
|
// todo how much to unwind to get back healthy APY zone again
|
|
30462
30974
|
// if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
|
|
30463
30975
|
// For xSTRK, simply deposit in Vesu if looping is not viable
|
|
@@ -30481,7 +30993,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30481
30993
|
// todo undo this
|
|
30482
30994
|
async netAPY() {
|
|
30483
30995
|
const unusedBalance = await this.getUnusedBalance();
|
|
30484
|
-
const maxNewDeposits = await this.maxNewDeposits();
|
|
30996
|
+
const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
30485
30997
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30486
30998
|
if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
30487
30999
|
logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
|
|
@@ -30498,8 +31010,8 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30498
31010
|
return output;
|
|
30499
31011
|
}
|
|
30500
31012
|
}
|
|
30501
|
-
async maxNewDeposits() {
|
|
30502
|
-
const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
|
|
31013
|
+
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
31014
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
30503
31015
|
let ltv = void 0;
|
|
30504
31016
|
for (let adapter of this.getVesuAdapters()) {
|
|
30505
31017
|
const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
|
|
@@ -30602,7 +31114,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30602
31114
|
const manageCall2 = manage2Info.callConstructor({
|
|
30603
31115
|
delegation: true
|
|
30604
31116
|
});
|
|
30605
|
-
const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU
|
|
31117
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
30606
31118
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
30607
31119
|
const multiplyParams = params.isIncrease ? {
|
|
30608
31120
|
isIncrease: true,
|
|
@@ -30686,6 +31198,12 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
|
|
|
30686
31198
|
function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
30687
31199
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
30688
31200
|
}
|
|
31201
|
+
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
31202
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31203
|
+
}
|
|
31204
|
+
function getVesuLegId(baseID, debtTokenSymbol) {
|
|
31205
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31206
|
+
}
|
|
30689
31207
|
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
30690
31208
|
vaultSettings.leafAdapters = [];
|
|
30691
31209
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
@@ -30695,7 +31213,7 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30695
31213
|
collateral: lstToken,
|
|
30696
31214
|
debt: underlyingToken,
|
|
30697
31215
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
30698
|
-
id: "vesu_leg1" /* VESU_LEG1
|
|
31216
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
30699
31217
|
});
|
|
30700
31218
|
const commonAdapter = new CommonAdapter({
|
|
30701
31219
|
manager: vaultSettings.manager,
|
|
@@ -30704,25 +31222,39 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30704
31222
|
vaultAddress: vaultSettings.vaultAddress,
|
|
30705
31223
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
30706
31224
|
});
|
|
30707
|
-
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
30708
|
-
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
30709
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
30710
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter("multiply_vesu" /* MULTIPLY_VESU */).bind(vesuAdapterLST));
|
|
30711
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
30712
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
30713
31225
|
vaultSettings.adapters.push(...[{
|
|
30714
|
-
id: "
|
|
31226
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
30715
31227
|
adapter: vesuAdapterLST
|
|
30716
31228
|
}, {
|
|
30717
31229
|
id: "common_adapter" /* COMMON */,
|
|
30718
31230
|
adapter: commonAdapter
|
|
30719
31231
|
}]);
|
|
30720
|
-
|
|
30721
|
-
|
|
30722
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address,
|
|
30723
|
-
vaultSettings.leafAdapters.push(
|
|
30724
|
-
vaultSettings.leafAdapters.push(
|
|
30725
|
-
vaultSettings.leafAdapters.push(
|
|
31232
|
+
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
31233
|
+
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
31234
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
31235
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
31236
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
31237
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_mul_approve_withdr" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
|
|
31238
|
+
for (let borrowableAsset of vaultSettings.borrowable_assets) {
|
|
31239
|
+
const debtAsset = borrowableAsset;
|
|
31240
|
+
const approve_debt_token_id = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, debtAsset.symbol);
|
|
31241
|
+
const swap_debt_token_id = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, debtAsset.symbol);
|
|
31242
|
+
const swap_lst_token_id = getAvnuManageIDs("avnu_mul_swap_withdr" /* AVNU_MULTIPLY_SWAP_WITHDRAW */, debtAsset.symbol);
|
|
31243
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
|
|
31244
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
|
|
31245
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
|
|
31246
|
+
const vesuAdapter = new VesuAdapter({
|
|
31247
|
+
poolId: pool1,
|
|
31248
|
+
collateral: lstToken,
|
|
31249
|
+
debt: debtAsset,
|
|
31250
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
31251
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol)
|
|
31252
|
+
});
|
|
31253
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
|
|
31254
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
|
|
31255
|
+
const multiplID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, debtAsset.symbol);
|
|
31256
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getMultiplyAdapter(multiplID).bind(vesuAdapter));
|
|
31257
|
+
}
|
|
30726
31258
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30727
31259
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30728
31260
|
vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
|
|
@@ -30800,7 +31332,8 @@ var hyperxSTRK = {
|
|
|
30800
31332
|
adapters: [],
|
|
30801
31333
|
targetHealthFactor: 1.1,
|
|
30802
31334
|
minHealthFactor: 1.05,
|
|
30803
|
-
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK")
|
|
31335
|
+
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK"),
|
|
31336
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK")
|
|
30804
31337
|
};
|
|
30805
31338
|
var hyperxWBTC = {
|
|
30806
31339
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -30812,7 +31345,8 @@ var hyperxWBTC = {
|
|
|
30812
31345
|
adapters: [],
|
|
30813
31346
|
targetHealthFactor: 1.1,
|
|
30814
31347
|
minHealthFactor: 1.05,
|
|
30815
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31348
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31349
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC")
|
|
30816
31350
|
};
|
|
30817
31351
|
var hyperxtBTC = {
|
|
30818
31352
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -30824,7 +31358,8 @@ var hyperxtBTC = {
|
|
|
30824
31358
|
adapters: [],
|
|
30825
31359
|
targetHealthFactor: 1.1,
|
|
30826
31360
|
minHealthFactor: 1.05,
|
|
30827
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31361
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31362
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC")
|
|
30828
31363
|
};
|
|
30829
31364
|
var hyperxsBTC = {
|
|
30830
31365
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -30836,7 +31371,8 @@ var hyperxsBTC = {
|
|
|
30836
31371
|
adapters: [],
|
|
30837
31372
|
targetHealthFactor: 1.1,
|
|
30838
31373
|
minHealthFactor: 1.05,
|
|
30839
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31374
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31375
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC")
|
|
30840
31376
|
};
|
|
30841
31377
|
var hyperxLBTC = {
|
|
30842
31378
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -30848,7 +31384,8 @@ var hyperxLBTC = {
|
|
|
30848
31384
|
adapters: [],
|
|
30849
31385
|
targetHealthFactor: 1.1,
|
|
30850
31386
|
minHealthFactor: 1.05,
|
|
30851
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31387
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31388
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC")
|
|
30852
31389
|
};
|
|
30853
31390
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
30854
31391
|
return [
|
|
@@ -31550,6 +32087,7 @@ var Deployer = {
|
|
|
31550
32087
|
};
|
|
31551
32088
|
var deployer_default = Deployer;
|
|
31552
32089
|
export {
|
|
32090
|
+
APYType,
|
|
31553
32091
|
AUMTypes,
|
|
31554
32092
|
AVNU_EXCHANGE,
|
|
31555
32093
|
AVNU_MIDDLEWARE,
|