@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
|
@@ -20191,7 +20191,7 @@ ${r2}}` : "}", l2;
|
|
|
20191
20191
|
toHexString: () => toHexString2,
|
|
20192
20192
|
toStorageKey: () => toStorageKey2
|
|
20193
20193
|
});
|
|
20194
|
-
var
|
|
20194
|
+
var import_utils64 = require_utils2();
|
|
20195
20195
|
function isHex3(hex) {
|
|
20196
20196
|
return /^0x[0-9a-f]*$/i.test(hex);
|
|
20197
20197
|
}
|
|
@@ -20264,7 +20264,7 @@ ${r2}}` : "}", l2;
|
|
|
20264
20264
|
if (adaptedValue.length % 2 !== 0) {
|
|
20265
20265
|
adaptedValue = `0${adaptedValue}`;
|
|
20266
20266
|
}
|
|
20267
|
-
return (0,
|
|
20267
|
+
return (0, import_utils64.hexToBytes)(adaptedValue);
|
|
20268
20268
|
}
|
|
20269
20269
|
function addPercent2(number2, percent) {
|
|
20270
20270
|
const bigIntNum = BigInt(number2);
|
|
@@ -28640,6 +28640,7 @@ ${r2}}` : "}", l2;
|
|
|
28640
28640
|
// src/index.browser.ts
|
|
28641
28641
|
var index_browser_exports = {};
|
|
28642
28642
|
__export(index_browser_exports, {
|
|
28643
|
+
APYType: () => APYType,
|
|
28643
28644
|
AUMTypes: () => AUMTypes,
|
|
28644
28645
|
AVNU_EXCHANGE: () => AVNU_EXCHANGE,
|
|
28645
28646
|
AVNU_MIDDLEWARE: () => AVNU_MIDDLEWARE,
|
|
@@ -49193,6 +49194,25 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
49193
49194
|
priceProxySymbol: "WBTC",
|
|
49194
49195
|
priceCheckAmount: 1e-4
|
|
49195
49196
|
// 112000 * 0.0001 = $11.2
|
|
49197
|
+
}, {
|
|
49198
|
+
name: "mRe7BTC",
|
|
49199
|
+
symbol: "mRe7BTC",
|
|
49200
|
+
logo: "https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/3a62ecee-1e58-45d3-9862-3ce90dff1900/logo",
|
|
49201
|
+
address: ContractAddr.from("0x4e4fb1a9ca7e84bae609b9dc0078ad7719e49187ae7e425bb47d131710eddac"),
|
|
49202
|
+
decimals: 18,
|
|
49203
|
+
coingeckId: void 0,
|
|
49204
|
+
displayDecimals: 6,
|
|
49205
|
+
priceCheckAmount: 1e-4
|
|
49206
|
+
// 112000 * 0.0001 = $11.2
|
|
49207
|
+
}, {
|
|
49208
|
+
name: "mRe7YIELD",
|
|
49209
|
+
symbol: "mRe7YIELD",
|
|
49210
|
+
logo: "https://midas.app/assets/mre7-BcOOHm7i.svg",
|
|
49211
|
+
address: ContractAddr.from("0x4be8945e61dc3e19ebadd1579a6bd53b262f51ba89e6f8b0c4bc9a7e3c633fc"),
|
|
49212
|
+
decimals: 18,
|
|
49213
|
+
coingeckId: void 0,
|
|
49214
|
+
displayDecimals: 2,
|
|
49215
|
+
priceCheckAmount: 100
|
|
49196
49216
|
}];
|
|
49197
49217
|
var tokens = defaultTokens;
|
|
49198
49218
|
var _Global = class _Global {
|
|
@@ -53767,16 +53787,16 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
53767
53787
|
};
|
|
53768
53788
|
return swapInfo;
|
|
53769
53789
|
}
|
|
53770
|
-
static buildZeroSwap(tokenToSell,
|
|
53790
|
+
static buildZeroSwap(tokenToSell, beneficiary, tokenToBuy = tokenToSell) {
|
|
53771
53791
|
return {
|
|
53772
53792
|
token_from_address: tokenToSell.address,
|
|
53773
53793
|
token_from_amount: uint256_exports.bnToUint256(0),
|
|
53774
|
-
token_to_address:
|
|
53794
|
+
token_to_address: tokenToBuy.address,
|
|
53775
53795
|
token_to_amount: uint256_exports.bnToUint256(0),
|
|
53776
53796
|
token_to_min_amount: uint256_exports.bnToUint256(0),
|
|
53777
|
-
beneficiary
|
|
53797
|
+
beneficiary,
|
|
53778
53798
|
integrator_fee_amount_bps: 0,
|
|
53779
|
-
integrator_fee_recipient:
|
|
53799
|
+
integrator_fee_recipient: beneficiary,
|
|
53780
53800
|
routes: []
|
|
53781
53801
|
};
|
|
53782
53802
|
}
|
|
@@ -55717,21 +55737,20 @@ ${JSON.stringify(data, null, 2)}`;
|
|
|
55717
55737
|
const rewards = await this.getHarvests(addr);
|
|
55718
55738
|
if (rewards.length == 0) return [];
|
|
55719
55739
|
const unClaimed = [];
|
|
55720
|
-
const
|
|
55721
|
-
|
|
55722
|
-
|
|
55723
|
-
|
|
55724
|
-
|
|
55725
|
-
|
|
55726
|
-
|
|
55727
|
-
|
|
55728
|
-
|
|
55729
|
-
|
|
55730
|
-
|
|
55731
|
-
|
|
55732
|
-
|
|
55733
|
-
|
|
55734
|
-
}
|
|
55740
|
+
const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
|
|
55741
|
+
const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
|
|
55742
|
+
const contract = new Contract({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
|
|
55743
|
+
const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
|
|
55744
|
+
logger2.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
|
|
55745
|
+
if (isClaimed) {
|
|
55746
|
+
return unClaimed;
|
|
55747
|
+
}
|
|
55748
|
+
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
55749
|
+
if (bal.lessThan(reward.claim.amount)) {
|
|
55750
|
+
logger2.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
55751
|
+
return unClaimed;
|
|
55752
|
+
}
|
|
55753
|
+
unClaimed.unshift(reward);
|
|
55735
55754
|
return unClaimed;
|
|
55736
55755
|
}
|
|
55737
55756
|
};
|
|
@@ -79321,6 +79340,91 @@ spurious results.`);
|
|
|
79321
79340
|
});
|
|
79322
79341
|
var apollo_client_default = apolloClient;
|
|
79323
79342
|
|
|
79343
|
+
// src/utils/math-utils.ts
|
|
79344
|
+
async function binarySearch(lowWei, highWei, callback) {
|
|
79345
|
+
while (lowWei <= highWei) {
|
|
79346
|
+
const diff = highWei - lowWei;
|
|
79347
|
+
const mid = lowWei + diff / 2n;
|
|
79348
|
+
const result2 = await callback(mid);
|
|
79349
|
+
if (result2 === "found") {
|
|
79350
|
+
return mid;
|
|
79351
|
+
} else if (result2 == "retry") {
|
|
79352
|
+
} else if (result2 === "go_low") {
|
|
79353
|
+
highWei = mid - BigInt(1);
|
|
79354
|
+
} else {
|
|
79355
|
+
lowWei = mid + BigInt(1);
|
|
79356
|
+
}
|
|
79357
|
+
}
|
|
79358
|
+
return null;
|
|
79359
|
+
}
|
|
79360
|
+
async function findMaxInputWithSlippage(options) {
|
|
79361
|
+
const {
|
|
79362
|
+
apiGetOutput,
|
|
79363
|
+
maxInput,
|
|
79364
|
+
maxSlippagePercent,
|
|
79365
|
+
tolerance,
|
|
79366
|
+
minInput = 0,
|
|
79367
|
+
referenceAmountMultiplier = 1e-3,
|
|
79368
|
+
referenceRate = 0
|
|
79369
|
+
} = options;
|
|
79370
|
+
let apiCalls = 0;
|
|
79371
|
+
if (!referenceRate && !referenceAmountMultiplier) {
|
|
79372
|
+
throw new Error("One of referenceRate or referenceAmountMultiplier must be provided");
|
|
79373
|
+
}
|
|
79374
|
+
let _referenceRate = referenceRate;
|
|
79375
|
+
if (!_referenceRate) {
|
|
79376
|
+
const smallAmount = maxInput * referenceAmountMultiplier;
|
|
79377
|
+
const referenceOutput = await apiGetOutput(smallAmount);
|
|
79378
|
+
apiCalls++;
|
|
79379
|
+
_referenceRate = referenceOutput / smallAmount;
|
|
79380
|
+
}
|
|
79381
|
+
async function checkSlippage(inputAmount) {
|
|
79382
|
+
const actualOutput = await apiGetOutput(inputAmount);
|
|
79383
|
+
apiCalls++;
|
|
79384
|
+
const expectedOutput = inputAmount * referenceRate;
|
|
79385
|
+
const slippage = (expectedOutput - actualOutput) / expectedOutput;
|
|
79386
|
+
logger2.verbose(`findMaxInputWithSlippage::checkSlippage inputAmount: ${inputAmount}, actualOutput: ${actualOutput}, slippage: ${slippage}, maxSlippagePercent: ${maxSlippagePercent}`);
|
|
79387
|
+
return {
|
|
79388
|
+
acceptable: slippage <= maxSlippagePercent,
|
|
79389
|
+
slippage,
|
|
79390
|
+
output: actualOutput
|
|
79391
|
+
};
|
|
79392
|
+
}
|
|
79393
|
+
const maxCheck = await checkSlippage(maxInput);
|
|
79394
|
+
if (maxCheck.acceptable) {
|
|
79395
|
+
return {
|
|
79396
|
+
optimalInput: maxInput,
|
|
79397
|
+
actualOutput: maxCheck.output,
|
|
79398
|
+
actualSlippage: maxCheck.slippage,
|
|
79399
|
+
apiCallsUsed: apiCalls
|
|
79400
|
+
};
|
|
79401
|
+
}
|
|
79402
|
+
let left = minInput;
|
|
79403
|
+
let right = maxInput;
|
|
79404
|
+
let bestInput = minInput;
|
|
79405
|
+
let bestOutput = 0;
|
|
79406
|
+
let bestSlippage = 0;
|
|
79407
|
+
const convergenceThreshold = tolerance * maxInput;
|
|
79408
|
+
while (right - left > convergenceThreshold) {
|
|
79409
|
+
const mid = (left + right) / 2;
|
|
79410
|
+
const midCheck = await checkSlippage(mid);
|
|
79411
|
+
if (midCheck.acceptable) {
|
|
79412
|
+
bestInput = mid;
|
|
79413
|
+
bestOutput = midCheck.output;
|
|
79414
|
+
bestSlippage = midCheck.slippage;
|
|
79415
|
+
left = mid;
|
|
79416
|
+
} else {
|
|
79417
|
+
right = mid;
|
|
79418
|
+
}
|
|
79419
|
+
}
|
|
79420
|
+
return {
|
|
79421
|
+
optimalInput: bestInput,
|
|
79422
|
+
actualOutput: bestOutput,
|
|
79423
|
+
actualSlippage: bestSlippage,
|
|
79424
|
+
apiCallsUsed: apiCalls
|
|
79425
|
+
};
|
|
79426
|
+
}
|
|
79427
|
+
|
|
79324
79428
|
// src/strategies/ekubo-cl-vault.tsx
|
|
79325
79429
|
var import_jsx_runtime3 = __toESM(require_jsx_runtime());
|
|
79326
79430
|
var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
@@ -79607,7 +79711,6 @@ spurious results.`);
|
|
|
79607
79711
|
for (let i = len - 1; i >= 0; --i) {
|
|
79608
79712
|
let record = await this.contract.call("get_rewards_info", [i]);
|
|
79609
79713
|
logger2.verbose(`${_EkuboCLVault.name}: getHarvestRewardShares: ${i}`);
|
|
79610
|
-
console.log(record);
|
|
79611
79714
|
const block2 = Number(record.block_number);
|
|
79612
79715
|
if (block2 < fromBlock) {
|
|
79613
79716
|
return shares;
|
|
@@ -79807,16 +79910,10 @@ spurious results.`);
|
|
|
79807
79910
|
const sqrtRatio = _EkuboCLVault.div2Power128(
|
|
79808
79911
|
BigInt(priceInfo.sqrt_ratio.toString())
|
|
79809
79912
|
);
|
|
79810
|
-
console.log(
|
|
79811
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, sqrtRatio: ${sqrtRatio}, ${priceInfo.sqrt_ratio.toString()}`
|
|
79812
|
-
);
|
|
79813
79913
|
const token0Info = await Global.getTokenInfoFromAddr(poolKey.token0);
|
|
79814
79914
|
const token1Info = await Global.getTokenInfoFromAddr(poolKey.token1);
|
|
79815
79915
|
const price = sqrtRatio * sqrtRatio * 10 ** token0Info.decimals / 10 ** token1Info.decimals;
|
|
79816
79916
|
const tick = priceInfo.tick;
|
|
79817
|
-
console.log(
|
|
79818
|
-
`EkuboCLVault: getCurrentPrice: blockIdentifier: ${blockIdentifier}, price: ${price}, tick: ${tick.mag}, ${tick.sign}`
|
|
79819
|
-
);
|
|
79820
79917
|
return {
|
|
79821
79918
|
price,
|
|
79822
79919
|
tick: Number(tick.mag) * (tick.sign ? -1 : 1),
|
|
@@ -80443,62 +80540,193 @@ spurious results.`);
|
|
|
80443
80540
|
logger2.verbose(
|
|
80444
80541
|
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
80445
80542
|
);
|
|
80446
|
-
const
|
|
80447
|
-
|
|
80543
|
+
const isRewardTokenMatch = claim.token.eq(poolKey.token0) || claim.token.eq(poolKey.token1);
|
|
80544
|
+
if (isRewardTokenMatch) {
|
|
80545
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMatchHarvest({
|
|
80546
|
+
acc,
|
|
80547
|
+
claim,
|
|
80548
|
+
isToken1,
|
|
80549
|
+
token0Info,
|
|
80550
|
+
token1Info,
|
|
80551
|
+
postFeeAmount,
|
|
80552
|
+
poolKey,
|
|
80553
|
+
bounds,
|
|
80554
|
+
maxIterations,
|
|
80555
|
+
priceRatioPrecision
|
|
80556
|
+
});
|
|
80557
|
+
calls.push(..._callsFinal);
|
|
80558
|
+
} else {
|
|
80559
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMismatchHarvest({
|
|
80560
|
+
claim,
|
|
80561
|
+
token0Info,
|
|
80562
|
+
token1Info,
|
|
80563
|
+
postFeeAmount,
|
|
80564
|
+
poolKey,
|
|
80565
|
+
bounds,
|
|
80566
|
+
maxIterations,
|
|
80567
|
+
priceRatioPrecision,
|
|
80568
|
+
acc
|
|
80569
|
+
});
|
|
80570
|
+
calls.push(..._callsFinal);
|
|
80571
|
+
}
|
|
80572
|
+
}
|
|
80573
|
+
return calls;
|
|
80574
|
+
}
|
|
80575
|
+
/**
|
|
80576
|
+
* @description This funciton requires atleast one of the pool tokens to be reward token
|
|
80577
|
+
* i.e. STRK.
|
|
80578
|
+
* @param params
|
|
80579
|
+
*/
|
|
80580
|
+
async _handleRewardAndVaultTokenMatchHarvest(params) {
|
|
80581
|
+
const { acc, claim, isToken1, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
80582
|
+
const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
|
|
80583
|
+
const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
|
|
80584
|
+
logger2.verbose(
|
|
80585
|
+
`${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
|
|
80586
|
+
);
|
|
80587
|
+
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
80588
|
+
poolKey,
|
|
80589
|
+
token0Amt,
|
|
80590
|
+
token1Amt,
|
|
80591
|
+
bounds,
|
|
80592
|
+
maxIterations,
|
|
80593
|
+
priceRatioPrecision
|
|
80594
|
+
);
|
|
80595
|
+
swapInfo.token_to_address = token0Info.address.address;
|
|
80596
|
+
logger2.verbose(
|
|
80597
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
80598
|
+
);
|
|
80599
|
+
logger2.verbose(
|
|
80600
|
+
`${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
80601
|
+
);
|
|
80602
|
+
const harvestEstimateCall = async (swapInfo1) => {
|
|
80603
|
+
const swap1Amount = Web3Number.fromWei(
|
|
80604
|
+
uint256_exports.uint256ToBN(swapInfo1.token_from_amount).toString(),
|
|
80605
|
+
18
|
|
80606
|
+
// cause its always STRK?
|
|
80607
|
+
).minimum(
|
|
80608
|
+
postFeeAmount.toFixed(18)
|
|
80609
|
+
// cause always strk
|
|
80610
|
+
);
|
|
80611
|
+
swapInfo.token_from_amount = uint256_exports.bnToUint256(swap1Amount.toWei());
|
|
80612
|
+
swapInfo.token_to_min_amount = uint256_exports.bnToUint256(
|
|
80613
|
+
swap1Amount.multipliedBy(0).toWei()
|
|
80614
|
+
// placeholder
|
|
80615
|
+
);
|
|
80448
80616
|
logger2.verbose(
|
|
80449
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
80617
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
80450
80618
|
);
|
|
80451
|
-
const
|
|
80452
|
-
|
|
80453
|
-
|
|
80454
|
-
token1Amt,
|
|
80455
|
-
bounds,
|
|
80456
|
-
maxIterations,
|
|
80457
|
-
priceRatioPrecision
|
|
80619
|
+
const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
|
|
80620
|
+
logger2.verbose(
|
|
80621
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
80458
80622
|
);
|
|
80459
|
-
|
|
80623
|
+
const swapInfo2 = {
|
|
80624
|
+
...swapInfo,
|
|
80625
|
+
token_from_amount: uint256_exports.bnToUint256(remainingAmount.toWei())
|
|
80626
|
+
};
|
|
80627
|
+
swapInfo2.token_to_address = token1Info.address.address;
|
|
80460
80628
|
logger2.verbose(
|
|
80461
|
-
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
80629
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
80630
|
+
swapInfo
|
|
80631
|
+
)}`
|
|
80462
80632
|
);
|
|
80463
80633
|
logger2.verbose(
|
|
80464
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
80634
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
80635
|
+
swapInfo2
|
|
80636
|
+
)}`
|
|
80465
80637
|
);
|
|
80466
|
-
const
|
|
80467
|
-
|
|
80468
|
-
|
|
80469
|
-
|
|
80470
|
-
|
|
80471
|
-
|
|
80472
|
-
|
|
80473
|
-
|
|
80474
|
-
|
|
80475
|
-
|
|
80476
|
-
|
|
80477
|
-
|
|
80478
|
-
|
|
80479
|
-
|
|
80480
|
-
|
|
80481
|
-
|
|
80482
|
-
|
|
80483
|
-
|
|
80484
|
-
|
|
80485
|
-
|
|
80486
|
-
|
|
80487
|
-
|
|
80488
|
-
|
|
80489
|
-
|
|
80490
|
-
|
|
80491
|
-
|
|
80492
|
-
|
|
80493
|
-
|
|
80494
|
-
|
|
80495
|
-
|
|
80496
|
-
|
|
80497
|
-
|
|
80498
|
-
|
|
80499
|
-
|
|
80500
|
-
|
|
80501
|
-
|
|
80638
|
+
const calldata = [
|
|
80639
|
+
claim.rewardsContract.address,
|
|
80640
|
+
{
|
|
80641
|
+
id: claim.claim.id,
|
|
80642
|
+
amount: claim.claim.amount.toWei(),
|
|
80643
|
+
claimee: claim.claim.claimee.address
|
|
80644
|
+
},
|
|
80645
|
+
claim.proof.map((p) => num_exports.getDecimalString(p)),
|
|
80646
|
+
swapInfo,
|
|
80647
|
+
swapInfo2
|
|
80648
|
+
];
|
|
80649
|
+
logger2.verbose(
|
|
80650
|
+
`${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
80651
|
+
calldata
|
|
80652
|
+
)}`
|
|
80653
|
+
);
|
|
80654
|
+
return [this.contract.populate("harvest", calldata)];
|
|
80655
|
+
};
|
|
80656
|
+
const _callsFinal = await this.rebalanceIter(
|
|
80657
|
+
swapInfo,
|
|
80658
|
+
acc,
|
|
80659
|
+
harvestEstimateCall,
|
|
80660
|
+
claim.token.eq(poolKey.token0),
|
|
80661
|
+
0,
|
|
80662
|
+
0n,
|
|
80663
|
+
BigInt(postFeeAmount.toWei())
|
|
80664
|
+
// upper limit is the post fee amount
|
|
80665
|
+
);
|
|
80666
|
+
logger2.verbose(
|
|
80667
|
+
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
80668
|
+
_callsFinal
|
|
80669
|
+
)}`
|
|
80670
|
+
);
|
|
80671
|
+
return _callsFinal;
|
|
80672
|
+
}
|
|
80673
|
+
/**
|
|
80674
|
+
* @description This function handles harvesting of reward token that is not the same as any of the vault token
|
|
80675
|
+
* i.e. STRK is not part of vault tokens like BTC/ETH
|
|
80676
|
+
* @param params
|
|
80677
|
+
* @returns
|
|
80678
|
+
*/
|
|
80679
|
+
async _handleRewardAndVaultTokenMismatchHarvest(params) {
|
|
80680
|
+
const { acc, claim, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
80681
|
+
let token0Amt = postFeeAmount;
|
|
80682
|
+
const beneficiary = this.address.address;
|
|
80683
|
+
let harvestCall = null;
|
|
80684
|
+
harvestCall = await this.harvestMismatchEstimateCallFn({
|
|
80685
|
+
postFeeAmount,
|
|
80686
|
+
claim,
|
|
80687
|
+
token0Info,
|
|
80688
|
+
token1Info,
|
|
80689
|
+
acc
|
|
80690
|
+
});
|
|
80691
|
+
if (!harvestCall) {
|
|
80692
|
+
throw new Error("Harvest call not found");
|
|
80693
|
+
}
|
|
80694
|
+
return [harvestCall];
|
|
80695
|
+
}
|
|
80696
|
+
// given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
|
|
80697
|
+
// amount for binary search
|
|
80698
|
+
async harvestMismatchEstimateCallFn(params) {
|
|
80699
|
+
const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
|
|
80700
|
+
let harvestCall = null;
|
|
80701
|
+
const binarySearchCallbackFn = async (mid) => {
|
|
80702
|
+
const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
|
|
80703
|
+
const avnuWrapper = new AvnuWrapper();
|
|
80704
|
+
const beneficiary = this.address.address;
|
|
80705
|
+
const quote1 = await avnuWrapper.getQuotes(
|
|
80706
|
+
claim.token.address,
|
|
80707
|
+
token0Info.address.address,
|
|
80708
|
+
mid.toString(),
|
|
80709
|
+
beneficiary
|
|
80710
|
+
);
|
|
80711
|
+
const swapInfo1 = await avnuWrapper.getSwapInfo(
|
|
80712
|
+
quote1,
|
|
80713
|
+
beneficiary,
|
|
80714
|
+
0,
|
|
80715
|
+
beneficiary
|
|
80716
|
+
);
|
|
80717
|
+
const quote2 = await avnuWrapper.getQuotes(
|
|
80718
|
+
claim.token.address,
|
|
80719
|
+
token1Info.address.address,
|
|
80720
|
+
rewardPart2.toString(),
|
|
80721
|
+
beneficiary
|
|
80722
|
+
);
|
|
80723
|
+
const swapInfo2 = await avnuWrapper.getSwapInfo(
|
|
80724
|
+
quote2,
|
|
80725
|
+
beneficiary,
|
|
80726
|
+
0,
|
|
80727
|
+
beneficiary
|
|
80728
|
+
);
|
|
80729
|
+
try {
|
|
80502
80730
|
const calldata = [
|
|
80503
80731
|
claim.rewardsContract.address,
|
|
80504
80732
|
{
|
|
@@ -80507,34 +80735,23 @@ spurious results.`);
|
|
|
80507
80735
|
claimee: claim.claim.claimee.address
|
|
80508
80736
|
},
|
|
80509
80737
|
claim.proof.map((p) => num_exports.getDecimalString(p)),
|
|
80510
|
-
|
|
80738
|
+
swapInfo1,
|
|
80511
80739
|
swapInfo2
|
|
80512
80740
|
];
|
|
80513
|
-
|
|
80514
|
-
|
|
80515
|
-
|
|
80516
|
-
|
|
80517
|
-
)
|
|
80518
|
-
|
|
80519
|
-
|
|
80520
|
-
|
|
80521
|
-
|
|
80522
|
-
|
|
80523
|
-
|
|
80524
|
-
|
|
80525
|
-
|
|
80526
|
-
|
|
80527
|
-
BigInt(postFeeAmount.toWei())
|
|
80528
|
-
// upper limit is the post fee amount
|
|
80529
|
-
);
|
|
80530
|
-
logger2.verbose(
|
|
80531
|
-
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
80532
|
-
_callsFinal
|
|
80533
|
-
)}`
|
|
80534
|
-
);
|
|
80535
|
-
calls.push(..._callsFinal);
|
|
80536
|
-
}
|
|
80537
|
-
return calls;
|
|
80741
|
+
harvestCall = this.contract.populate("harvest", calldata);
|
|
80742
|
+
const gas = await acc.estimateInvokeFee(harvestCall);
|
|
80743
|
+
return "found";
|
|
80744
|
+
} catch (err2) {
|
|
80745
|
+
if (err2.message.includes("invalid token0 amount")) {
|
|
80746
|
+
return "go_low";
|
|
80747
|
+
} else if (err2.message.includes("invalid token1 amount")) {
|
|
80748
|
+
return "go_high";
|
|
80749
|
+
}
|
|
80750
|
+
return "retry";
|
|
80751
|
+
}
|
|
80752
|
+
};
|
|
80753
|
+
await binarySearch(0n, BigInt(postFeeAmount.toWei()), binarySearchCallbackFn);
|
|
80754
|
+
return harvestCall;
|
|
80538
80755
|
}
|
|
80539
80756
|
async getInvestmentFlows() {
|
|
80540
80757
|
const netYield = await this.netAPY();
|
|
@@ -83060,7 +83277,58 @@ spurious results.`);
|
|
|
83060
83277
|
}
|
|
83061
83278
|
|
|
83062
83279
|
// src/strategies/universal-adapters/baseAdapter.ts
|
|
83280
|
+
var APYType = /* @__PURE__ */ ((APYType2) => {
|
|
83281
|
+
APYType2["BASE"] = "base";
|
|
83282
|
+
APYType2["REWARD"] = "reward";
|
|
83283
|
+
APYType2["LST"] = "lst";
|
|
83284
|
+
return APYType2;
|
|
83285
|
+
})(APYType || {});
|
|
83063
83286
|
var BaseAdapter = class extends CacheClass {
|
|
83287
|
+
// readonly config: BaseAdapterConfig;
|
|
83288
|
+
// constructor(config: BaseAdapterConfig) {
|
|
83289
|
+
// super();
|
|
83290
|
+
// this.config = config;
|
|
83291
|
+
// }
|
|
83292
|
+
constructor() {
|
|
83293
|
+
super();
|
|
83294
|
+
}
|
|
83295
|
+
// /**
|
|
83296
|
+
// * Loop through all supported positions and return amount, usd value, remarks and apy for each
|
|
83297
|
+
// */
|
|
83298
|
+
// async getPositions(): Promise<PositionInfo[]> {
|
|
83299
|
+
// const results: PositionInfo[] = [];
|
|
83300
|
+
// for (const supported of this.config.supportedPositions) {
|
|
83301
|
+
// const amount = await this.getPosition(supported);
|
|
83302
|
+
// const usdValue = await this.getUSDValue(supported.asset, amount);
|
|
83303
|
+
// const apy = await this.getAPY(supported);
|
|
83304
|
+
// results.push({ amount, usdValue, apy });
|
|
83305
|
+
// }
|
|
83306
|
+
// return results;
|
|
83307
|
+
// }
|
|
83308
|
+
// /**
|
|
83309
|
+
// * Implemented by child adapters to compute APY for a given supported position
|
|
83310
|
+
// */
|
|
83311
|
+
// protected abstract getAPY(supportedPosition: SupportedPosition): Promise<PositionAPY>;
|
|
83312
|
+
// /**
|
|
83313
|
+
// * Implemented by child adapters to fetch amount for a given supported position
|
|
83314
|
+
// */
|
|
83315
|
+
// protected abstract getPosition(supportedPosition: SupportedPosition): Promise<Web3Number>;
|
|
83316
|
+
// /**
|
|
83317
|
+
// * Implemented by child adapters to calculate maximum deposit positions
|
|
83318
|
+
// * @param amount Optional amount in baseToken to deposit
|
|
83319
|
+
// */
|
|
83320
|
+
// protected abstract maxDeposit(amount?: Web3Number): Promise<PositionInfo[]>;
|
|
83321
|
+
// /**
|
|
83322
|
+
// * Implemented by child adapters to calculate maximum withdraw positions
|
|
83323
|
+
// */
|
|
83324
|
+
// protected abstract maxWithdraw(): Promise<PositionInfo[]>;
|
|
83325
|
+
// /**
|
|
83326
|
+
// * Uses pricer to convert an amount of an asset to USD value
|
|
83327
|
+
// */
|
|
83328
|
+
// protected async getUSDValue(asset: TokenInfo, amount: Web3Number): Promise<number> {
|
|
83329
|
+
// const priceInfo = await this.config.pricer.getPrice(asset.symbol);
|
|
83330
|
+
// return amount.toNumber() * priceInfo.price;
|
|
83331
|
+
// }
|
|
83064
83332
|
constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
|
|
83065
83333
|
const { id, target, method, packedArguments } = params;
|
|
83066
83334
|
return {
|
|
@@ -83078,6 +83346,94 @@ spurious results.`);
|
|
|
83078
83346
|
]
|
|
83079
83347
|
};
|
|
83080
83348
|
}
|
|
83349
|
+
// /**
|
|
83350
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for deposit leaf construction
|
|
83351
|
+
// */
|
|
83352
|
+
// protected abstract _getDepositLeaf(): {
|
|
83353
|
+
// target: ContractAddr,
|
|
83354
|
+
// method: string,
|
|
83355
|
+
// packedArguments: bigint[],
|
|
83356
|
+
// sanitizer: ContractAddr,
|
|
83357
|
+
// id: string
|
|
83358
|
+
// }[];
|
|
83359
|
+
// /**
|
|
83360
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for withdraw leaf construction
|
|
83361
|
+
// */
|
|
83362
|
+
// protected abstract _getWithdrawLeaf(): {
|
|
83363
|
+
// target: ContractAddr,
|
|
83364
|
+
// method: string,
|
|
83365
|
+
// packedArguments: bigint[],
|
|
83366
|
+
// sanitizer: ContractAddr,
|
|
83367
|
+
// id: string
|
|
83368
|
+
// }[];
|
|
83369
|
+
// /**
|
|
83370
|
+
// * Returns deposit leaf adapter using configured proof id
|
|
83371
|
+
// */
|
|
83372
|
+
// getDepositLeaf(): AdapterLeafType<T1> {
|
|
83373
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
83374
|
+
// const leaves = leafConfigs.map(config => {
|
|
83375
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
83376
|
+
// const leaf = this.constructSimpleLeafData({
|
|
83377
|
+
// id: id,
|
|
83378
|
+
// target,
|
|
83379
|
+
// method,
|
|
83380
|
+
// packedArguments
|
|
83381
|
+
// }, sanitizer);
|
|
83382
|
+
// return leaf;
|
|
83383
|
+
// });
|
|
83384
|
+
// return { leaves, callConstructor: this.getDepositCall.bind(this) as unknown as GenerateCallFn<T1> };
|
|
83385
|
+
// }
|
|
83386
|
+
// /**
|
|
83387
|
+
// * Returns withdraw leaf adapter using configured proof id
|
|
83388
|
+
// */
|
|
83389
|
+
// getWithdrawLeaf(): AdapterLeafType<T2> {
|
|
83390
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
83391
|
+
// const leaves = leafConfigs.map(config => {
|
|
83392
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
83393
|
+
// const leaf = this.constructSimpleLeafData({
|
|
83394
|
+
// id: id,
|
|
83395
|
+
// target,
|
|
83396
|
+
// method,
|
|
83397
|
+
// packedArguments
|
|
83398
|
+
// }, sanitizer ?? SIMPLE_SANITIZER);
|
|
83399
|
+
// return leaf;
|
|
83400
|
+
// });
|
|
83401
|
+
// return { leaves, callConstructor: this.getWithdrawCall.bind(this) as unknown as GenerateCallFn<T2> };
|
|
83402
|
+
// }
|
|
83403
|
+
// /**
|
|
83404
|
+
// * Default deposit callConstructor: expects params as calldata (bigint[])
|
|
83405
|
+
// */
|
|
83406
|
+
// protected getDepositCall<T1 = bigint[]>(params: T1): ManageCall[] {
|
|
83407
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
83408
|
+
// return leafConfigs.map(config => {
|
|
83409
|
+
// const { target, method, sanitizer } = config;
|
|
83410
|
+
// return {
|
|
83411
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
83412
|
+
// call: {
|
|
83413
|
+
// contractAddress: target,
|
|
83414
|
+
// selector: hash.getSelectorFromName(method),
|
|
83415
|
+
// calldata: params as unknown as bigint[]
|
|
83416
|
+
// }
|
|
83417
|
+
// };
|
|
83418
|
+
// });
|
|
83419
|
+
// }
|
|
83420
|
+
// /**
|
|
83421
|
+
// * Default withdraw callConstructor: expects params as calldata (bigint[])
|
|
83422
|
+
// */
|
|
83423
|
+
// protected getWithdrawCall<T2 = bigint[]>(params: T2): ManageCall[] {
|
|
83424
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
83425
|
+
// return leafConfigs.map(config => {
|
|
83426
|
+
// const { target, method, sanitizer } = config;
|
|
83427
|
+
// return {
|
|
83428
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
83429
|
+
// call: {
|
|
83430
|
+
// contractAddress: target,
|
|
83431
|
+
// selector: hash.getSelectorFromName(method),
|
|
83432
|
+
// calldata: params as unknown as bigint[]
|
|
83433
|
+
// }
|
|
83434
|
+
// };
|
|
83435
|
+
// });
|
|
83436
|
+
// }
|
|
83081
83437
|
};
|
|
83082
83438
|
|
|
83083
83439
|
// src/strategies/universal-adapters/common-adapter.ts
|
|
@@ -90676,7 +91032,20 @@ spurious results.`);
|
|
|
90676
91032
|
}
|
|
90677
91033
|
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
90678
91034
|
logger2.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
|
|
90679
|
-
|
|
91035
|
+
if (!isV2) {
|
|
91036
|
+
throw new Error("getDebtCap is not supported for v1");
|
|
91037
|
+
}
|
|
91038
|
+
const currentDebt = await this.getCurrentDebtUtilisationAmount(config3);
|
|
91039
|
+
logger2.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap currentDebt: ${currentDebt.toString()}`);
|
|
91040
|
+
return Web3Number.fromWei(output.debt_cap.toString(), this.config.debt.decimals).minus(currentDebt);
|
|
91041
|
+
}
|
|
91042
|
+
async getCurrentDebtUtilisationAmount(config3) {
|
|
91043
|
+
const { contract, isV2 } = await this.getVesuSingletonContract(config3, this.config.poolId);
|
|
91044
|
+
if (!isV2) {
|
|
91045
|
+
throw new Error("getCurrentDebtUtilisationAmount is not supported for v1");
|
|
91046
|
+
}
|
|
91047
|
+
const output = await contract.call("pairs", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
91048
|
+
return new Web3Number((Number(output.total_nominal_debt) / 1e18).toFixed(9), this.config.debt.decimals);
|
|
90680
91049
|
}
|
|
90681
91050
|
async getMaxBorrowableByInterestRate(config3, asset, maxBorrowAPY) {
|
|
90682
91051
|
const { contract, isV2 } = await this.getVesuSingletonContract(config3, this.config.poolId);
|
|
@@ -90709,16 +91078,17 @@ spurious results.`);
|
|
|
90709
91078
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
90710
91079
|
const timeDelta = assetConfig.last_updated;
|
|
90711
91080
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
90712
|
-
const
|
|
91081
|
+
const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals);
|
|
91082
|
+
const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
|
|
90713
91083
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
90714
91084
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
90715
91085
|
logger2.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
90716
91086
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
90717
|
-
|
|
91087
|
+
logger2.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
90718
91088
|
return maxDebtToHave.minus(currentDebt);
|
|
90719
91089
|
}
|
|
90720
|
-
async getLTVConfig(config3) {
|
|
90721
|
-
const CACHE_KEY =
|
|
91090
|
+
async getLTVConfig(config3, blockNumber = "latest") {
|
|
91091
|
+
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
90722
91092
|
const cacheData = this.getCache(CACHE_KEY);
|
|
90723
91093
|
if (cacheData) {
|
|
90724
91094
|
return cacheData;
|
|
@@ -90726,10 +91096,10 @@ spurious results.`);
|
|
|
90726
91096
|
const { contract, isV2 } = await this.getVesuSingletonContract(config3, this.config.poolId);
|
|
90727
91097
|
let ltv = 0;
|
|
90728
91098
|
if (isV2) {
|
|
90729
|
-
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
91099
|
+
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
90730
91100
|
ltv = Number(output.max_ltv) / 1e18;
|
|
90731
91101
|
} else {
|
|
90732
|
-
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
|
|
91102
|
+
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
90733
91103
|
ltv = Number(output.max_ltv) / 1e18;
|
|
90734
91104
|
}
|
|
90735
91105
|
if (ltv == 0) {
|
|
@@ -90738,11 +91108,11 @@ spurious results.`);
|
|
|
90738
91108
|
this.setCache(CACHE_KEY, ltv, 3e5);
|
|
90739
91109
|
return this.getCache(CACHE_KEY);
|
|
90740
91110
|
}
|
|
90741
|
-
async getPositions(config3) {
|
|
91111
|
+
async getPositions(config3, blockNumber = "latest") {
|
|
90742
91112
|
if (!this.pricer) {
|
|
90743
91113
|
throw new Error("Pricer is not initialized");
|
|
90744
91114
|
}
|
|
90745
|
-
const CACHE_KEY =
|
|
91115
|
+
const CACHE_KEY = `positions_${blockNumber}`;
|
|
90746
91116
|
const cacheData = this.getCache(CACHE_KEY);
|
|
90747
91117
|
if (cacheData) {
|
|
90748
91118
|
return cacheData;
|
|
@@ -90754,7 +91124,8 @@ spurious results.`);
|
|
|
90754
91124
|
this.config.collateral.address.address,
|
|
90755
91125
|
this.config.debt.address.address,
|
|
90756
91126
|
this.config.vaultAllocator.address
|
|
90757
|
-
]);
|
|
91127
|
+
], { blockIdentifier: blockNumber });
|
|
91128
|
+
console.log(output);
|
|
90758
91129
|
const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
|
|
90759
91130
|
const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
|
|
90760
91131
|
logger2.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
|
|
@@ -90774,11 +91145,11 @@ spurious results.`);
|
|
|
90774
91145
|
this.setCache(CACHE_KEY, value, 6e4);
|
|
90775
91146
|
return value;
|
|
90776
91147
|
}
|
|
90777
|
-
async getCollateralization(config3) {
|
|
91148
|
+
async getCollateralization(config3, blockNumber = "latest") {
|
|
90778
91149
|
if (!this.pricer) {
|
|
90779
91150
|
throw new Error("Pricer is not initialized");
|
|
90780
91151
|
}
|
|
90781
|
-
const CACHE_KEY =
|
|
91152
|
+
const CACHE_KEY = `collateralization_${blockNumber}`;
|
|
90782
91153
|
const cacheData = this.getCache(CACHE_KEY);
|
|
90783
91154
|
if (cacheData) {
|
|
90784
91155
|
return cacheData;
|
|
@@ -90790,7 +91161,7 @@ spurious results.`);
|
|
|
90790
91161
|
this.config.collateral.address.address,
|
|
90791
91162
|
this.config.debt.address.address,
|
|
90792
91163
|
this.config.vaultAllocator.address
|
|
90793
|
-
]);
|
|
91164
|
+
], { blockIdentifier: blockNumber });
|
|
90794
91165
|
const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
|
|
90795
91166
|
const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
|
|
90796
91167
|
const value = [{
|
|
@@ -90827,9 +91198,9 @@ spurious results.`);
|
|
|
90827
91198
|
ltv
|
|
90828
91199
|
};
|
|
90829
91200
|
}
|
|
90830
|
-
async getHealthFactor() {
|
|
90831
|
-
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
90832
|
-
const collateralisation = await this.getCollateralization(this.networkConfig);
|
|
91201
|
+
async getHealthFactor(blockNumber = "latest") {
|
|
91202
|
+
const ltv = await this.getLTVConfig(this.networkConfig, blockNumber);
|
|
91203
|
+
const collateralisation = await this.getCollateralization(this.networkConfig, blockNumber);
|
|
90833
91204
|
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
90834
91205
|
}
|
|
90835
91206
|
static async getVesuPools(retry = 0) {
|
|
@@ -93488,11 +93859,11 @@ spurious results.`);
|
|
|
93488
93859
|
vesuAdapter2.networkConfig = this.config;
|
|
93489
93860
|
return [vesuAdapter1, vesuAdapter2];
|
|
93490
93861
|
}
|
|
93491
|
-
async getVesuPositions() {
|
|
93862
|
+
async getVesuPositions(blockNumber = "latest") {
|
|
93492
93863
|
const adapters = this.getVesuAdapters();
|
|
93493
93864
|
const positions = [];
|
|
93494
93865
|
for (const adapter of adapters) {
|
|
93495
|
-
positions.push(...await adapter.getPositions(this.config));
|
|
93866
|
+
positions.push(...await adapter.getPositions(this.config, blockNumber));
|
|
93496
93867
|
}
|
|
93497
93868
|
return positions;
|
|
93498
93869
|
}
|
|
@@ -93561,8 +93932,8 @@ spurious results.`);
|
|
|
93561
93932
|
async getLSTAPR(address) {
|
|
93562
93933
|
return 0;
|
|
93563
93934
|
}
|
|
93564
|
-
async getVesuHealthFactors() {
|
|
93565
|
-
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
|
|
93935
|
+
async getVesuHealthFactors(blockNumber = "latest") {
|
|
93936
|
+
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor(blockNumber)));
|
|
93566
93937
|
}
|
|
93567
93938
|
async computeRebalanceConditionAndReturnCalls() {
|
|
93568
93939
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -94156,6 +94527,40 @@ spurious results.`);
|
|
|
94156
94527
|
}
|
|
94157
94528
|
];
|
|
94158
94529
|
|
|
94530
|
+
// src/utils/health-factor-math.ts
|
|
94531
|
+
var HealthFactorMath = class {
|
|
94532
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
94533
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
94534
|
+
const denominator = collateralPrice * maxLTV;
|
|
94535
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
94536
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
94537
|
+
return netCollateral;
|
|
94538
|
+
}
|
|
94539
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
94540
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
94541
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
94542
|
+
return netCollateral.minus(collateralFromDebt);
|
|
94543
|
+
}
|
|
94544
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
94545
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
94546
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
94547
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
94548
|
+
return healthFactor.toNumber();
|
|
94549
|
+
}
|
|
94550
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
94551
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
94552
|
+
const denominator = targetHF - maxLTV;
|
|
94553
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
94554
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
94555
|
+
}
|
|
94556
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
94557
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
94558
|
+
const denominator = targetHF * debtPrice;
|
|
94559
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
94560
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
94561
|
+
}
|
|
94562
|
+
};
|
|
94563
|
+
|
|
94159
94564
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
94160
94565
|
var import_jsx_runtime5 = __toESM(require_jsx_runtime());
|
|
94161
94566
|
var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
|
|
@@ -94171,15 +94576,14 @@ spurious results.`);
|
|
|
94171
94576
|
}
|
|
94172
94577
|
}
|
|
94173
94578
|
asset() {
|
|
94174
|
-
|
|
94175
|
-
return vesuAdapter1.config.collateral;
|
|
94579
|
+
return this.getVesuSameTokenAdapter().config.collateral;
|
|
94176
94580
|
}
|
|
94177
94581
|
getTag() {
|
|
94178
94582
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
94179
94583
|
}
|
|
94180
94584
|
// Vesu adapter with LST and base token match
|
|
94181
94585
|
getVesuSameTokenAdapter() {
|
|
94182
|
-
const baseAdapter = this.getAdapter("
|
|
94586
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
94183
94587
|
baseAdapter.networkConfig = this.config;
|
|
94184
94588
|
baseAdapter.pricer = this.pricer;
|
|
94185
94589
|
return baseAdapter;
|
|
@@ -94227,20 +94631,52 @@ spurious results.`);
|
|
|
94227
94631
|
return price;
|
|
94228
94632
|
}
|
|
94229
94633
|
async getAvnuSwapMultiplyCall(params) {
|
|
94230
|
-
|
|
94231
|
-
|
|
94232
|
-
|
|
94233
|
-
|
|
94234
|
-
|
|
94634
|
+
assert3(params.isDeposit, "Only deposit is supported in getAvnuSwapMultiplyCall");
|
|
94635
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
|
|
94636
|
+
const allVesuAdapters = this.getVesuAdapters();
|
|
94637
|
+
let remainingAmount = params.leg1DepositAmount;
|
|
94638
|
+
const lstExRate = await this.getLSTExchangeRate();
|
|
94639
|
+
const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
|
|
94640
|
+
const lstPrice = baseAssetPrice.price * lstExRate;
|
|
94641
|
+
for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
|
|
94642
|
+
const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
|
|
94643
|
+
const vesuAdapter = allVesuAdapters.find((adapter) => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
|
|
94644
|
+
if (!vesuAdapter) {
|
|
94645
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
|
|
94646
|
+
}
|
|
94647
|
+
const maxLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
94648
|
+
const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
|
|
94649
|
+
const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
|
|
94650
|
+
maxBorrowable.amount,
|
|
94651
|
+
debtPrice.price,
|
|
94652
|
+
this.metadata.additionalInfo.targetHealthFactor,
|
|
94653
|
+
maxLTV,
|
|
94654
|
+
lstPrice,
|
|
94655
|
+
this.asset()
|
|
94656
|
+
);
|
|
94657
|
+
const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
|
|
94658
|
+
logger2.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
|
|
94659
|
+
const call = await this._getAvnuDepositSwapLegCall({
|
|
94660
|
+
isDeposit: params.isDeposit,
|
|
94661
|
+
// adjust decimals of debt asset
|
|
94662
|
+
leg1DepositAmount: amountToDeposit,
|
|
94663
|
+
minHF: 1.1,
|
|
94664
|
+
// undo
|
|
94665
|
+
vesuAdapter
|
|
94666
|
+
});
|
|
94667
|
+
remainingAmount = remainingAmount.minus(amountToDeposit);
|
|
94668
|
+
return { call, vesuAdapter };
|
|
94669
|
+
}
|
|
94670
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
|
|
94235
94671
|
}
|
|
94236
94672
|
async _getAvnuDepositSwapLegCall(params) {
|
|
94673
|
+
const { vesuAdapter } = params;
|
|
94237
94674
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
|
|
94238
94675
|
assert3(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
|
|
94239
|
-
const
|
|
94240
|
-
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
94676
|
+
const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
94241
94677
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
94242
|
-
const existingPositions = await
|
|
94243
|
-
const collateralisation = await
|
|
94678
|
+
const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
94679
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
94244
94680
|
const existingCollateralInfo = existingPositions[0];
|
|
94245
94681
|
const existingDebtInfo = existingPositions[1];
|
|
94246
94682
|
logger2.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
@@ -94248,11 +94684,40 @@ spurious results.`);
|
|
|
94248
94684
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
94249
94685
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
94250
94686
|
logger2.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
94687
|
+
const debtTokenInfo = vesuAdapter.config.debt;
|
|
94688
|
+
let newDepositAmount = params.leg1DepositAmount;
|
|
94251
94689
|
const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
|
|
94252
94690
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
|
|
94253
|
-
const totalDebtAmount =
|
|
94254
|
-
|
|
94255
|
-
|
|
94691
|
+
const totalDebtAmount = new Web3Number(
|
|
94692
|
+
totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
|
|
94693
|
+
debtTokenInfo.decimals
|
|
94694
|
+
);
|
|
94695
|
+
let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
|
|
94696
|
+
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
|
|
94697
|
+
const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
|
|
94698
|
+
if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
|
|
94699
|
+
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
|
|
94700
|
+
return void 0;
|
|
94701
|
+
} else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
|
|
94702
|
+
debtAmount = maxBorrowable.amount.minimum(debtAmount);
|
|
94703
|
+
const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
|
|
94704
|
+
const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
|
|
94705
|
+
debtAmount.plus(existingDebtInfo.amount),
|
|
94706
|
+
debtPrice,
|
|
94707
|
+
params.minHF,
|
|
94708
|
+
legLTV,
|
|
94709
|
+
collateralPrice,
|
|
94710
|
+
this.asset()
|
|
94711
|
+
);
|
|
94712
|
+
newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
|
|
94713
|
+
if (newDepositAmount.lt(0)) {
|
|
94714
|
+
throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
|
|
94715
|
+
}
|
|
94716
|
+
if (newDebtUSDValue.toNumber() < 100) {
|
|
94717
|
+
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
|
|
94718
|
+
return void 0;
|
|
94719
|
+
}
|
|
94720
|
+
}
|
|
94256
94721
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
94257
94722
|
if (debtAmount.lt(0)) {
|
|
94258
94723
|
const lstDEXPrice = await this.getLSTDexPrice();
|
|
@@ -94264,32 +94729,34 @@ spurious results.`);
|
|
|
94264
94729
|
assert3(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
94265
94730
|
return calls[0];
|
|
94266
94731
|
}
|
|
94732
|
+
console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
|
|
94267
94733
|
const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
|
|
94268
94734
|
const manage0Info = this.getProofs(STEP0);
|
|
94269
94735
|
const manageCall0 = manage0Info.callConstructor({
|
|
94270
|
-
amount:
|
|
94736
|
+
amount: newDepositAmount
|
|
94271
94737
|
});
|
|
94272
|
-
const STEP1 = "vesu_leg1" /* VESU_LEG1
|
|
94738
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
94273
94739
|
const manage1Info = this.getProofs(STEP1);
|
|
94274
94740
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
94275
|
-
collateralAmount:
|
|
94741
|
+
collateralAmount: newDepositAmount,
|
|
94276
94742
|
isAddCollateral: params.isDeposit,
|
|
94277
94743
|
debtAmount,
|
|
94278
94744
|
isBorrow: params.isDeposit
|
|
94279
94745
|
}));
|
|
94746
|
+
console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
94280
94747
|
const proofIds = [STEP0, STEP1];
|
|
94281
94748
|
const manageCalls = [manageCall0, manageCall1];
|
|
94282
94749
|
if (debtAmount.gt(0)) {
|
|
94283
|
-
const STEP2 = "
|
|
94750
|
+
const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
94284
94751
|
const manage2Info = this.getProofs(STEP2);
|
|
94285
94752
|
const manageCall2 = manage2Info.callConstructor({
|
|
94286
94753
|
amount: debtAmount
|
|
94287
94754
|
});
|
|
94288
|
-
const
|
|
94755
|
+
const debtTokenInfo2 = vesuAdapter.config.debt;
|
|
94289
94756
|
const lstTokenInfo = this.asset();
|
|
94290
94757
|
const avnuModule = new AvnuWrapper();
|
|
94291
94758
|
const quote = await avnuModule.getQuotes(
|
|
94292
|
-
|
|
94759
|
+
debtTokenInfo2.address.address,
|
|
94293
94760
|
lstTokenInfo.address.address,
|
|
94294
94761
|
debtAmount.toWei(),
|
|
94295
94762
|
this.metadata.additionalInfo.vaultAllocator.address
|
|
@@ -94305,7 +94772,7 @@ spurious results.`);
|
|
|
94305
94772
|
minAmountWei
|
|
94306
94773
|
);
|
|
94307
94774
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
|
|
94308
|
-
const STEP3 = "
|
|
94775
|
+
const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
94309
94776
|
const manage3Info = this.getProofs(STEP3);
|
|
94310
94777
|
const manageCall3 = manage3Info.callConstructor({
|
|
94311
94778
|
props: swapInfo
|
|
@@ -94323,7 +94790,7 @@ spurious results.`);
|
|
|
94323
94790
|
const manageCall4 = manage4Info.callConstructor({
|
|
94324
94791
|
amount: minAmount
|
|
94325
94792
|
});
|
|
94326
|
-
const STEP5 = "vesu_leg1" /* VESU_LEG1
|
|
94793
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
94327
94794
|
const manage5Info = this.getProofs(STEP5);
|
|
94328
94795
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
94329
94796
|
collateralAmount: minAmount,
|
|
@@ -94340,28 +94807,41 @@ spurious results.`);
|
|
|
94340
94807
|
}
|
|
94341
94808
|
// todo unwind or not deposit when the yield is bad.
|
|
94342
94809
|
async getLSTMultiplierRebalanceCall() {
|
|
94343
|
-
|
|
94344
|
-
|
|
94810
|
+
let shouldRebalance = false;
|
|
94811
|
+
const calls = [];
|
|
94812
|
+
const allVesuAdapters = this.getVesuAdapters().filter((vesuAdapter) => vesuAdapter.config.debt.symbol === "LBTC");
|
|
94813
|
+
for (const vesuAdapter of allVesuAdapters) {
|
|
94814
|
+
const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
|
|
94815
|
+
if (call.shouldRebalance && call.manageCall) {
|
|
94816
|
+
shouldRebalance = true;
|
|
94817
|
+
calls.push({ vesuAdapter, manageCall: call.manageCall });
|
|
94818
|
+
}
|
|
94819
|
+
}
|
|
94820
|
+
return { shouldRebalance, manageCalls: calls };
|
|
94821
|
+
}
|
|
94822
|
+
async _getLSTMultiplierRebalanceCall(vesuAdapter) {
|
|
94823
|
+
const positions = await vesuAdapter.getPositions(this.config);
|
|
94824
|
+
assert3(positions.length == 2, "Rebalance call is only supported for 2 positions");
|
|
94345
94825
|
const existingCollateralInfo = positions[0];
|
|
94346
94826
|
const existingDebtInfo = positions[1];
|
|
94347
|
-
const unusedBalance =
|
|
94348
|
-
const
|
|
94349
|
-
const
|
|
94350
|
-
|
|
94351
|
-
const collateralisation = await vesuAdapter1.getCollateralization(this.config);
|
|
94352
|
-
logger2.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
94827
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
94828
|
+
const healthFactor = await vesuAdapter.getHealthFactor();
|
|
94829
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
94830
|
+
logger2.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
94353
94831
|
existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
94354
94832
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
94355
94833
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
94356
94834
|
logger2.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
94835
|
+
logger2.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
|
|
94357
94836
|
const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
94358
94837
|
const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
94359
|
-
if (isHFTooLow || isHFTooHigh) {
|
|
94838
|
+
if (isHFTooLow || isHFTooHigh || 1) {
|
|
94360
94839
|
const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
94361
94840
|
isDeposit: true,
|
|
94362
94841
|
leg1DepositAmount: unusedBalance.amount,
|
|
94363
|
-
minHF: 1.02
|
|
94842
|
+
minHF: 1.02,
|
|
94364
94843
|
// todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
94844
|
+
vesuAdapter
|
|
94365
94845
|
});
|
|
94366
94846
|
return { shouldRebalance: true, manageCall };
|
|
94367
94847
|
} else {
|
|
@@ -94394,7 +94874,7 @@ spurious results.`);
|
|
|
94394
94874
|
async _getMinOutputAmountLSTBuy(amountInUnderlying) {
|
|
94395
94875
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
94396
94876
|
const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
|
|
94397
|
-
return minOutputAmount;
|
|
94877
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
94398
94878
|
}
|
|
94399
94879
|
async _getMinOutputAmountLSTSell(amountInLST) {
|
|
94400
94880
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
@@ -94451,21 +94931,52 @@ spurious results.`);
|
|
|
94451
94931
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
94452
94932
|
return vesuAdapter1.config.debt;
|
|
94453
94933
|
}
|
|
94454
|
-
async getMaxBorrowableAmount() {
|
|
94934
|
+
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
94455
94935
|
const vesuAdapters = this.getVesuAdapters();
|
|
94456
94936
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
94457
94937
|
const maxBorrowables = [];
|
|
94458
|
-
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
94459
|
-
const maxInterestRate = lstAPY * 0.8;
|
|
94460
94938
|
for (const vesuAdapter of vesuAdapters) {
|
|
94461
|
-
|
|
94462
|
-
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
94463
|
-
maxBorrowables.push({ amount: maxBorrowableAmount.minimum(debtCap), borrowableAsset: vesuAdapter.config.debt });
|
|
94939
|
+
maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
|
|
94464
94940
|
}
|
|
94465
94941
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
94466
94942
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
94467
94943
|
return { netMaxBorrowableAmount, maxBorrowables };
|
|
94468
94944
|
}
|
|
94945
|
+
// recursively, using binary search computes max swappable.
|
|
94946
|
+
// @dev assumes 1 token of from == 1 token of to
|
|
94947
|
+
async getMaxSwappableWithMaxSlippage(fromToken, toToken, maxSlippage, maxAmount) {
|
|
94948
|
+
const output = await findMaxInputWithSlippage({
|
|
94949
|
+
apiGetOutput: async (inputAmount) => {
|
|
94950
|
+
const ekuboQuoter = new EkuboQuoter(this.config);
|
|
94951
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
94952
|
+
const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
|
|
94953
|
+
return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
|
|
94954
|
+
},
|
|
94955
|
+
maxInput: maxAmount.toNumber(),
|
|
94956
|
+
maxSlippagePercent: maxSlippage,
|
|
94957
|
+
tolerance: 1e-3,
|
|
94958
|
+
referenceRate: 1
|
|
94959
|
+
});
|
|
94960
|
+
return new Web3Number(output.optimalInput, fromToken.decimals);
|
|
94961
|
+
}
|
|
94962
|
+
async getMaxBorrowableAmountByVesuAdapter(vesuAdapter, isAPYComputation) {
|
|
94963
|
+
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
94964
|
+
const maxInterestRate = lstAPY * 0.8;
|
|
94965
|
+
const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
|
|
94966
|
+
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
94967
|
+
const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
|
|
94968
|
+
if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
|
|
94969
|
+
return { amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
94970
|
+
}
|
|
94971
|
+
try {
|
|
94972
|
+
const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 2e-4, maxBorrowable);
|
|
94973
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
94974
|
+
} catch (error2) {
|
|
94975
|
+
logger2.warn(`${this.getTag()}: Failed to get max swappable: ${error2}`);
|
|
94976
|
+
const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
|
|
94977
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
94978
|
+
}
|
|
94979
|
+
}
|
|
94469
94980
|
// todo how much to unwind to get back healthy APY zone again
|
|
94470
94981
|
// if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
|
|
94471
94982
|
// For xSTRK, simply deposit in Vesu if looping is not viable
|
|
@@ -94489,7 +95000,7 @@ spurious results.`);
|
|
|
94489
95000
|
// todo undo this
|
|
94490
95001
|
async netAPY() {
|
|
94491
95002
|
const unusedBalance = await this.getUnusedBalance();
|
|
94492
|
-
const maxNewDeposits = await this.maxNewDeposits();
|
|
95003
|
+
const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
94493
95004
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
94494
95005
|
if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
94495
95006
|
logger2.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
|
|
@@ -94506,8 +95017,8 @@ spurious results.`);
|
|
|
94506
95017
|
return output;
|
|
94507
95018
|
}
|
|
94508
95019
|
}
|
|
94509
|
-
async maxNewDeposits() {
|
|
94510
|
-
const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
|
|
95020
|
+
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
95021
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
94511
95022
|
let ltv = void 0;
|
|
94512
95023
|
for (let adapter of this.getVesuAdapters()) {
|
|
94513
95024
|
const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
|
|
@@ -94610,7 +95121,7 @@ spurious results.`);
|
|
|
94610
95121
|
const manageCall2 = manage2Info.callConstructor({
|
|
94611
95122
|
delegation: true
|
|
94612
95123
|
});
|
|
94613
|
-
const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU
|
|
95124
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
94614
95125
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
94615
95126
|
const multiplyParams = params.isIncrease ? {
|
|
94616
95127
|
isIncrease: true,
|
|
@@ -94694,6 +95205,12 @@ spurious results.`);
|
|
|
94694
95205
|
function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
94695
95206
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
94696
95207
|
}
|
|
95208
|
+
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
95209
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
95210
|
+
}
|
|
95211
|
+
function getVesuLegId(baseID, debtTokenSymbol) {
|
|
95212
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
95213
|
+
}
|
|
94697
95214
|
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
94698
95215
|
vaultSettings.leafAdapters = [];
|
|
94699
95216
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
@@ -94703,7 +95220,7 @@ spurious results.`);
|
|
|
94703
95220
|
collateral: lstToken,
|
|
94704
95221
|
debt: underlyingToken,
|
|
94705
95222
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
94706
|
-
id: "vesu_leg1" /* VESU_LEG1
|
|
95223
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
94707
95224
|
});
|
|
94708
95225
|
const commonAdapter = new CommonAdapter({
|
|
94709
95226
|
manager: vaultSettings.manager,
|
|
@@ -94712,25 +95229,39 @@ spurious results.`);
|
|
|
94712
95229
|
vaultAddress: vaultSettings.vaultAddress,
|
|
94713
95230
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
94714
95231
|
});
|
|
94715
|
-
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
94716
|
-
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
94717
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
94718
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter("multiply_vesu" /* MULTIPLY_VESU */).bind(vesuAdapterLST));
|
|
94719
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
94720
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
94721
95232
|
vaultSettings.adapters.push(...[{
|
|
94722
|
-
id: "
|
|
95233
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
94723
95234
|
adapter: vesuAdapterLST
|
|
94724
95235
|
}, {
|
|
94725
95236
|
id: "common_adapter" /* COMMON */,
|
|
94726
95237
|
adapter: commonAdapter
|
|
94727
95238
|
}]);
|
|
94728
|
-
|
|
94729
|
-
|
|
94730
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address,
|
|
94731
|
-
vaultSettings.leafAdapters.push(
|
|
94732
|
-
vaultSettings.leafAdapters.push(
|
|
94733
|
-
vaultSettings.leafAdapters.push(
|
|
95239
|
+
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
95240
|
+
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
95241
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
95242
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
95243
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
95244
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_mul_approve_withdr" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
|
|
95245
|
+
for (let borrowableAsset of vaultSettings.borrowable_assets) {
|
|
95246
|
+
const debtAsset = borrowableAsset;
|
|
95247
|
+
const approve_debt_token_id = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, debtAsset.symbol);
|
|
95248
|
+
const swap_debt_token_id = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, debtAsset.symbol);
|
|
95249
|
+
const swap_lst_token_id = getAvnuManageIDs("avnu_mul_swap_withdr" /* AVNU_MULTIPLY_SWAP_WITHDRAW */, debtAsset.symbol);
|
|
95250
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
|
|
95251
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
|
|
95252
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
|
|
95253
|
+
const vesuAdapter = new VesuAdapter({
|
|
95254
|
+
poolId: pool1,
|
|
95255
|
+
collateral: lstToken,
|
|
95256
|
+
debt: debtAsset,
|
|
95257
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
95258
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol)
|
|
95259
|
+
});
|
|
95260
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
|
|
95261
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
|
|
95262
|
+
const multiplID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, debtAsset.symbol);
|
|
95263
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getMultiplyAdapter(multiplID).bind(vesuAdapter));
|
|
95264
|
+
}
|
|
94734
95265
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
94735
95266
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
94736
95267
|
vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
|
|
@@ -94808,7 +95339,8 @@ spurious results.`);
|
|
|
94808
95339
|
adapters: [],
|
|
94809
95340
|
targetHealthFactor: 1.1,
|
|
94810
95341
|
minHealthFactor: 1.05,
|
|
94811
|
-
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK")
|
|
95342
|
+
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK"),
|
|
95343
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK")
|
|
94812
95344
|
};
|
|
94813
95345
|
var hyperxWBTC = {
|
|
94814
95346
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -94820,7 +95352,8 @@ spurious results.`);
|
|
|
94820
95352
|
adapters: [],
|
|
94821
95353
|
targetHealthFactor: 1.1,
|
|
94822
95354
|
minHealthFactor: 1.05,
|
|
94823
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95355
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95356
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC")
|
|
94824
95357
|
};
|
|
94825
95358
|
var hyperxtBTC = {
|
|
94826
95359
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -94832,7 +95365,8 @@ spurious results.`);
|
|
|
94832
95365
|
adapters: [],
|
|
94833
95366
|
targetHealthFactor: 1.1,
|
|
94834
95367
|
minHealthFactor: 1.05,
|
|
94835
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95368
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95369
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC")
|
|
94836
95370
|
};
|
|
94837
95371
|
var hyperxsBTC = {
|
|
94838
95372
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -94844,7 +95378,8 @@ spurious results.`);
|
|
|
94844
95378
|
adapters: [],
|
|
94845
95379
|
targetHealthFactor: 1.1,
|
|
94846
95380
|
minHealthFactor: 1.05,
|
|
94847
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95381
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95382
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC")
|
|
94848
95383
|
};
|
|
94849
95384
|
var hyperxLBTC = {
|
|
94850
95385
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -94856,7 +95391,8 @@ spurious results.`);
|
|
|
94856
95391
|
adapters: [],
|
|
94857
95392
|
targetHealthFactor: 1.1,
|
|
94858
95393
|
minHealthFactor: 1.05,
|
|
94859
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95394
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95395
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC")
|
|
94860
95396
|
};
|
|
94861
95397
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
94862
95398
|
return [
|