@strkfarm/sdk 1.1.38 → 1.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.global.js +726 -185
- package/dist/index.browser.mjs +725 -182
- package/dist/index.d.ts +126 -13
- package/dist/index.js +726 -182
- package/dist/index.mjs +725 -182
- package/package.json +1 -1
- package/src/global.ts +18 -0
- package/src/modules/avnu.ts +5 -4
- package/src/modules/harvests.ts +16 -15
- package/src/strategies/ekubo-cl-vault.tsx +255 -79
- package/src/strategies/universal-adapters/baseAdapter.ts +184 -2
- package/src/strategies/universal-adapters/vesu-adapter.ts +34 -17
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +322 -0
- package/src/strategies/universal-lst-muliplier-strategy.tsx +231 -72
- 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 {
|
|
@@ -80443,62 +80547,193 @@ spurious results.`);
|
|
|
80443
80547
|
logger2.verbose(
|
|
80444
80548
|
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
80445
80549
|
);
|
|
80446
|
-
const
|
|
80447
|
-
|
|
80550
|
+
const isRewardTokenMatch = claim.token.eq(poolKey.token0) || claim.token.eq(poolKey.token1);
|
|
80551
|
+
if (isRewardTokenMatch) {
|
|
80552
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMatchHarvest({
|
|
80553
|
+
acc,
|
|
80554
|
+
claim,
|
|
80555
|
+
isToken1,
|
|
80556
|
+
token0Info,
|
|
80557
|
+
token1Info,
|
|
80558
|
+
postFeeAmount,
|
|
80559
|
+
poolKey,
|
|
80560
|
+
bounds,
|
|
80561
|
+
maxIterations,
|
|
80562
|
+
priceRatioPrecision
|
|
80563
|
+
});
|
|
80564
|
+
calls.push(..._callsFinal);
|
|
80565
|
+
} else {
|
|
80566
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMismatchHarvest({
|
|
80567
|
+
claim,
|
|
80568
|
+
token0Info,
|
|
80569
|
+
token1Info,
|
|
80570
|
+
postFeeAmount,
|
|
80571
|
+
poolKey,
|
|
80572
|
+
bounds,
|
|
80573
|
+
maxIterations,
|
|
80574
|
+
priceRatioPrecision,
|
|
80575
|
+
acc
|
|
80576
|
+
});
|
|
80577
|
+
calls.push(..._callsFinal);
|
|
80578
|
+
}
|
|
80579
|
+
}
|
|
80580
|
+
return calls;
|
|
80581
|
+
}
|
|
80582
|
+
/**
|
|
80583
|
+
* @description This funciton requires atleast one of the pool tokens to be reward token
|
|
80584
|
+
* i.e. STRK.
|
|
80585
|
+
* @param params
|
|
80586
|
+
*/
|
|
80587
|
+
async _handleRewardAndVaultTokenMatchHarvest(params) {
|
|
80588
|
+
const { acc, claim, isToken1, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
80589
|
+
const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
|
|
80590
|
+
const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
|
|
80591
|
+
logger2.verbose(
|
|
80592
|
+
`${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
|
|
80593
|
+
);
|
|
80594
|
+
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
80595
|
+
poolKey,
|
|
80596
|
+
token0Amt,
|
|
80597
|
+
token1Amt,
|
|
80598
|
+
bounds,
|
|
80599
|
+
maxIterations,
|
|
80600
|
+
priceRatioPrecision
|
|
80601
|
+
);
|
|
80602
|
+
swapInfo.token_to_address = token0Info.address.address;
|
|
80603
|
+
logger2.verbose(
|
|
80604
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
80605
|
+
);
|
|
80606
|
+
logger2.verbose(
|
|
80607
|
+
`${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
80608
|
+
);
|
|
80609
|
+
const harvestEstimateCall = async (swapInfo1) => {
|
|
80610
|
+
const swap1Amount = Web3Number.fromWei(
|
|
80611
|
+
uint256_exports.uint256ToBN(swapInfo1.token_from_amount).toString(),
|
|
80612
|
+
18
|
|
80613
|
+
// cause its always STRK?
|
|
80614
|
+
).minimum(
|
|
80615
|
+
postFeeAmount.toFixed(18)
|
|
80616
|
+
// cause always strk
|
|
80617
|
+
);
|
|
80618
|
+
swapInfo.token_from_amount = uint256_exports.bnToUint256(swap1Amount.toWei());
|
|
80619
|
+
swapInfo.token_to_min_amount = uint256_exports.bnToUint256(
|
|
80620
|
+
swap1Amount.multipliedBy(0).toWei()
|
|
80621
|
+
// placeholder
|
|
80622
|
+
);
|
|
80448
80623
|
logger2.verbose(
|
|
80449
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
80624
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
80450
80625
|
);
|
|
80451
|
-
const
|
|
80452
|
-
|
|
80453
|
-
|
|
80454
|
-
token1Amt,
|
|
80455
|
-
bounds,
|
|
80456
|
-
maxIterations,
|
|
80457
|
-
priceRatioPrecision
|
|
80626
|
+
const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
|
|
80627
|
+
logger2.verbose(
|
|
80628
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
80458
80629
|
);
|
|
80459
|
-
|
|
80630
|
+
const swapInfo2 = {
|
|
80631
|
+
...swapInfo,
|
|
80632
|
+
token_from_amount: uint256_exports.bnToUint256(remainingAmount.toWei())
|
|
80633
|
+
};
|
|
80634
|
+
swapInfo2.token_to_address = token1Info.address.address;
|
|
80460
80635
|
logger2.verbose(
|
|
80461
|
-
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
80636
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
80637
|
+
swapInfo
|
|
80638
|
+
)}`
|
|
80462
80639
|
);
|
|
80463
80640
|
logger2.verbose(
|
|
80464
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
80641
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
80642
|
+
swapInfo2
|
|
80643
|
+
)}`
|
|
80465
80644
|
);
|
|
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
|
-
|
|
80645
|
+
const calldata = [
|
|
80646
|
+
claim.rewardsContract.address,
|
|
80647
|
+
{
|
|
80648
|
+
id: claim.claim.id,
|
|
80649
|
+
amount: claim.claim.amount.toWei(),
|
|
80650
|
+
claimee: claim.claim.claimee.address
|
|
80651
|
+
},
|
|
80652
|
+
claim.proof.map((p) => num_exports.getDecimalString(p)),
|
|
80653
|
+
swapInfo,
|
|
80654
|
+
swapInfo2
|
|
80655
|
+
];
|
|
80656
|
+
logger2.verbose(
|
|
80657
|
+
`${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
80658
|
+
calldata
|
|
80659
|
+
)}`
|
|
80660
|
+
);
|
|
80661
|
+
return [this.contract.populate("harvest", calldata)];
|
|
80662
|
+
};
|
|
80663
|
+
const _callsFinal = await this.rebalanceIter(
|
|
80664
|
+
swapInfo,
|
|
80665
|
+
acc,
|
|
80666
|
+
harvestEstimateCall,
|
|
80667
|
+
claim.token.eq(poolKey.token0),
|
|
80668
|
+
0,
|
|
80669
|
+
0n,
|
|
80670
|
+
BigInt(postFeeAmount.toWei())
|
|
80671
|
+
// upper limit is the post fee amount
|
|
80672
|
+
);
|
|
80673
|
+
logger2.verbose(
|
|
80674
|
+
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
80675
|
+
_callsFinal
|
|
80676
|
+
)}`
|
|
80677
|
+
);
|
|
80678
|
+
return _callsFinal;
|
|
80679
|
+
}
|
|
80680
|
+
/**
|
|
80681
|
+
* @description This function handles harvesting of reward token that is not the same as any of the vault token
|
|
80682
|
+
* i.e. STRK is not part of vault tokens like BTC/ETH
|
|
80683
|
+
* @param params
|
|
80684
|
+
* @returns
|
|
80685
|
+
*/
|
|
80686
|
+
async _handleRewardAndVaultTokenMismatchHarvest(params) {
|
|
80687
|
+
const { acc, claim, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
80688
|
+
let token0Amt = postFeeAmount;
|
|
80689
|
+
const beneficiary = this.address.address;
|
|
80690
|
+
let harvestCall = null;
|
|
80691
|
+
harvestCall = await this.harvestMismatchEstimateCallFn({
|
|
80692
|
+
postFeeAmount,
|
|
80693
|
+
claim,
|
|
80694
|
+
token0Info,
|
|
80695
|
+
token1Info,
|
|
80696
|
+
acc
|
|
80697
|
+
});
|
|
80698
|
+
if (!harvestCall) {
|
|
80699
|
+
throw new Error("Harvest call not found");
|
|
80700
|
+
}
|
|
80701
|
+
return [harvestCall];
|
|
80702
|
+
}
|
|
80703
|
+
// given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
|
|
80704
|
+
// amount for binary search
|
|
80705
|
+
async harvestMismatchEstimateCallFn(params) {
|
|
80706
|
+
const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
|
|
80707
|
+
let harvestCall = null;
|
|
80708
|
+
const binarySearchCallbackFn = async (mid) => {
|
|
80709
|
+
const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
|
|
80710
|
+
const avnuWrapper = new AvnuWrapper();
|
|
80711
|
+
const beneficiary = this.address.address;
|
|
80712
|
+
const quote1 = await avnuWrapper.getQuotes(
|
|
80713
|
+
claim.token.address,
|
|
80714
|
+
token0Info.address.address,
|
|
80715
|
+
mid.toString(),
|
|
80716
|
+
beneficiary
|
|
80717
|
+
);
|
|
80718
|
+
const swapInfo1 = await avnuWrapper.getSwapInfo(
|
|
80719
|
+
quote1,
|
|
80720
|
+
beneficiary,
|
|
80721
|
+
0,
|
|
80722
|
+
beneficiary
|
|
80723
|
+
);
|
|
80724
|
+
const quote2 = await avnuWrapper.getQuotes(
|
|
80725
|
+
claim.token.address,
|
|
80726
|
+
token1Info.address.address,
|
|
80727
|
+
rewardPart2.toString(),
|
|
80728
|
+
beneficiary
|
|
80729
|
+
);
|
|
80730
|
+
const swapInfo2 = await avnuWrapper.getSwapInfo(
|
|
80731
|
+
quote2,
|
|
80732
|
+
beneficiary,
|
|
80733
|
+
0,
|
|
80734
|
+
beneficiary
|
|
80735
|
+
);
|
|
80736
|
+
try {
|
|
80502
80737
|
const calldata = [
|
|
80503
80738
|
claim.rewardsContract.address,
|
|
80504
80739
|
{
|
|
@@ -80507,34 +80742,24 @@ spurious results.`);
|
|
|
80507
80742
|
claimee: claim.claim.claimee.address
|
|
80508
80743
|
},
|
|
80509
80744
|
claim.proof.map((p) => num_exports.getDecimalString(p)),
|
|
80510
|
-
|
|
80745
|
+
swapInfo1,
|
|
80511
80746
|
swapInfo2
|
|
80512
80747
|
];
|
|
80513
|
-
|
|
80514
|
-
|
|
80515
|
-
|
|
80516
|
-
|
|
80517
|
-
);
|
|
80518
|
-
|
|
80519
|
-
|
|
80520
|
-
|
|
80521
|
-
|
|
80522
|
-
|
|
80523
|
-
|
|
80524
|
-
|
|
80525
|
-
|
|
80526
|
-
|
|
80527
|
-
|
|
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;
|
|
80748
|
+
harvestCall = this.contract.populate("harvest", calldata);
|
|
80749
|
+
const gas = await acc.estimateInvokeFee(harvestCall);
|
|
80750
|
+
return "found";
|
|
80751
|
+
} catch (err2) {
|
|
80752
|
+
console.error(err2);
|
|
80753
|
+
if (err2.message.includes("invalid token0 amount")) {
|
|
80754
|
+
return "go_low";
|
|
80755
|
+
} else if (err2.message.includes("invalid token1 amount")) {
|
|
80756
|
+
return "go_high";
|
|
80757
|
+
}
|
|
80758
|
+
return "retry";
|
|
80759
|
+
}
|
|
80760
|
+
};
|
|
80761
|
+
await binarySearch(0n, BigInt(postFeeAmount.toWei()), binarySearchCallbackFn);
|
|
80762
|
+
return harvestCall;
|
|
80538
80763
|
}
|
|
80539
80764
|
async getInvestmentFlows() {
|
|
80540
80765
|
const netYield = await this.netAPY();
|
|
@@ -83060,7 +83285,58 @@ spurious results.`);
|
|
|
83060
83285
|
}
|
|
83061
83286
|
|
|
83062
83287
|
// src/strategies/universal-adapters/baseAdapter.ts
|
|
83288
|
+
var APYType = /* @__PURE__ */ ((APYType2) => {
|
|
83289
|
+
APYType2["BASE"] = "base";
|
|
83290
|
+
APYType2["REWARD"] = "reward";
|
|
83291
|
+
APYType2["LST"] = "lst";
|
|
83292
|
+
return APYType2;
|
|
83293
|
+
})(APYType || {});
|
|
83063
83294
|
var BaseAdapter = class extends CacheClass {
|
|
83295
|
+
// readonly config: BaseAdapterConfig;
|
|
83296
|
+
// constructor(config: BaseAdapterConfig) {
|
|
83297
|
+
// super();
|
|
83298
|
+
// this.config = config;
|
|
83299
|
+
// }
|
|
83300
|
+
constructor() {
|
|
83301
|
+
super();
|
|
83302
|
+
}
|
|
83303
|
+
// /**
|
|
83304
|
+
// * Loop through all supported positions and return amount, usd value, remarks and apy for each
|
|
83305
|
+
// */
|
|
83306
|
+
// async getPositions(): Promise<PositionInfo[]> {
|
|
83307
|
+
// const results: PositionInfo[] = [];
|
|
83308
|
+
// for (const supported of this.config.supportedPositions) {
|
|
83309
|
+
// const amount = await this.getPosition(supported);
|
|
83310
|
+
// const usdValue = await this.getUSDValue(supported.asset, amount);
|
|
83311
|
+
// const apy = await this.getAPY(supported);
|
|
83312
|
+
// results.push({ amount, usdValue, apy });
|
|
83313
|
+
// }
|
|
83314
|
+
// return results;
|
|
83315
|
+
// }
|
|
83316
|
+
// /**
|
|
83317
|
+
// * Implemented by child adapters to compute APY for a given supported position
|
|
83318
|
+
// */
|
|
83319
|
+
// protected abstract getAPY(supportedPosition: SupportedPosition): Promise<PositionAPY>;
|
|
83320
|
+
// /**
|
|
83321
|
+
// * Implemented by child adapters to fetch amount for a given supported position
|
|
83322
|
+
// */
|
|
83323
|
+
// protected abstract getPosition(supportedPosition: SupportedPosition): Promise<Web3Number>;
|
|
83324
|
+
// /**
|
|
83325
|
+
// * Implemented by child adapters to calculate maximum deposit positions
|
|
83326
|
+
// * @param amount Optional amount in baseToken to deposit
|
|
83327
|
+
// */
|
|
83328
|
+
// protected abstract maxDeposit(amount?: Web3Number): Promise<PositionInfo[]>;
|
|
83329
|
+
// /**
|
|
83330
|
+
// * Implemented by child adapters to calculate maximum withdraw positions
|
|
83331
|
+
// */
|
|
83332
|
+
// protected abstract maxWithdraw(): Promise<PositionInfo[]>;
|
|
83333
|
+
// /**
|
|
83334
|
+
// * Uses pricer to convert an amount of an asset to USD value
|
|
83335
|
+
// */
|
|
83336
|
+
// protected async getUSDValue(asset: TokenInfo, amount: Web3Number): Promise<number> {
|
|
83337
|
+
// const priceInfo = await this.config.pricer.getPrice(asset.symbol);
|
|
83338
|
+
// return amount.toNumber() * priceInfo.price;
|
|
83339
|
+
// }
|
|
83064
83340
|
constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
|
|
83065
83341
|
const { id, target, method, packedArguments } = params;
|
|
83066
83342
|
return {
|
|
@@ -83078,6 +83354,94 @@ spurious results.`);
|
|
|
83078
83354
|
]
|
|
83079
83355
|
};
|
|
83080
83356
|
}
|
|
83357
|
+
// /**
|
|
83358
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for deposit leaf construction
|
|
83359
|
+
// */
|
|
83360
|
+
// protected abstract _getDepositLeaf(): {
|
|
83361
|
+
// target: ContractAddr,
|
|
83362
|
+
// method: string,
|
|
83363
|
+
// packedArguments: bigint[],
|
|
83364
|
+
// sanitizer: ContractAddr,
|
|
83365
|
+
// id: string
|
|
83366
|
+
// }[];
|
|
83367
|
+
// /**
|
|
83368
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for withdraw leaf construction
|
|
83369
|
+
// */
|
|
83370
|
+
// protected abstract _getWithdrawLeaf(): {
|
|
83371
|
+
// target: ContractAddr,
|
|
83372
|
+
// method: string,
|
|
83373
|
+
// packedArguments: bigint[],
|
|
83374
|
+
// sanitizer: ContractAddr,
|
|
83375
|
+
// id: string
|
|
83376
|
+
// }[];
|
|
83377
|
+
// /**
|
|
83378
|
+
// * Returns deposit leaf adapter using configured proof id
|
|
83379
|
+
// */
|
|
83380
|
+
// getDepositLeaf(): AdapterLeafType<T1> {
|
|
83381
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
83382
|
+
// const leaves = leafConfigs.map(config => {
|
|
83383
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
83384
|
+
// const leaf = this.constructSimpleLeafData({
|
|
83385
|
+
// id: id,
|
|
83386
|
+
// target,
|
|
83387
|
+
// method,
|
|
83388
|
+
// packedArguments
|
|
83389
|
+
// }, sanitizer);
|
|
83390
|
+
// return leaf;
|
|
83391
|
+
// });
|
|
83392
|
+
// return { leaves, callConstructor: this.getDepositCall.bind(this) as unknown as GenerateCallFn<T1> };
|
|
83393
|
+
// }
|
|
83394
|
+
// /**
|
|
83395
|
+
// * Returns withdraw leaf adapter using configured proof id
|
|
83396
|
+
// */
|
|
83397
|
+
// getWithdrawLeaf(): AdapterLeafType<T2> {
|
|
83398
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
83399
|
+
// const leaves = leafConfigs.map(config => {
|
|
83400
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
83401
|
+
// const leaf = this.constructSimpleLeafData({
|
|
83402
|
+
// id: id,
|
|
83403
|
+
// target,
|
|
83404
|
+
// method,
|
|
83405
|
+
// packedArguments
|
|
83406
|
+
// }, sanitizer ?? SIMPLE_SANITIZER);
|
|
83407
|
+
// return leaf;
|
|
83408
|
+
// });
|
|
83409
|
+
// return { leaves, callConstructor: this.getWithdrawCall.bind(this) as unknown as GenerateCallFn<T2> };
|
|
83410
|
+
// }
|
|
83411
|
+
// /**
|
|
83412
|
+
// * Default deposit callConstructor: expects params as calldata (bigint[])
|
|
83413
|
+
// */
|
|
83414
|
+
// protected getDepositCall<T1 = bigint[]>(params: T1): ManageCall[] {
|
|
83415
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
83416
|
+
// return leafConfigs.map(config => {
|
|
83417
|
+
// const { target, method, sanitizer } = config;
|
|
83418
|
+
// return {
|
|
83419
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
83420
|
+
// call: {
|
|
83421
|
+
// contractAddress: target,
|
|
83422
|
+
// selector: hash.getSelectorFromName(method),
|
|
83423
|
+
// calldata: params as unknown as bigint[]
|
|
83424
|
+
// }
|
|
83425
|
+
// };
|
|
83426
|
+
// });
|
|
83427
|
+
// }
|
|
83428
|
+
// /**
|
|
83429
|
+
// * Default withdraw callConstructor: expects params as calldata (bigint[])
|
|
83430
|
+
// */
|
|
83431
|
+
// protected getWithdrawCall<T2 = bigint[]>(params: T2): ManageCall[] {
|
|
83432
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
83433
|
+
// return leafConfigs.map(config => {
|
|
83434
|
+
// const { target, method, sanitizer } = config;
|
|
83435
|
+
// return {
|
|
83436
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
83437
|
+
// call: {
|
|
83438
|
+
// contractAddress: target,
|
|
83439
|
+
// selector: hash.getSelectorFromName(method),
|
|
83440
|
+
// calldata: params as unknown as bigint[]
|
|
83441
|
+
// }
|
|
83442
|
+
// };
|
|
83443
|
+
// });
|
|
83444
|
+
// }
|
|
83081
83445
|
};
|
|
83082
83446
|
|
|
83083
83447
|
// src/strategies/universal-adapters/common-adapter.ts
|
|
@@ -90676,7 +91040,20 @@ spurious results.`);
|
|
|
90676
91040
|
}
|
|
90677
91041
|
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
90678
91042
|
logger2.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
|
|
90679
|
-
|
|
91043
|
+
if (!isV2) {
|
|
91044
|
+
throw new Error("getDebtCap is not supported for v1");
|
|
91045
|
+
}
|
|
91046
|
+
const currentDebt = await this.getCurrentDebtUtilisationAmount(config3);
|
|
91047
|
+
logger2.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap currentDebt: ${currentDebt.toString()}`);
|
|
91048
|
+
return Web3Number.fromWei(output.debt_cap.toString(), this.config.debt.decimals).minus(currentDebt);
|
|
91049
|
+
}
|
|
91050
|
+
async getCurrentDebtUtilisationAmount(config3) {
|
|
91051
|
+
const { contract, isV2 } = await this.getVesuSingletonContract(config3, this.config.poolId);
|
|
91052
|
+
if (!isV2) {
|
|
91053
|
+
throw new Error("getCurrentDebtUtilisationAmount is not supported for v1");
|
|
91054
|
+
}
|
|
91055
|
+
const output = await contract.call("pairs", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
91056
|
+
return new Web3Number((Number(output.total_nominal_debt) / 1e18).toFixed(9), this.config.debt.decimals);
|
|
90680
91057
|
}
|
|
90681
91058
|
async getMaxBorrowableByInterestRate(config3, asset, maxBorrowAPY) {
|
|
90682
91059
|
const { contract, isV2 } = await this.getVesuSingletonContract(config3, this.config.poolId);
|
|
@@ -90709,16 +91086,17 @@ spurious results.`);
|
|
|
90709
91086
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
90710
91087
|
const timeDelta = assetConfig.last_updated;
|
|
90711
91088
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
90712
|
-
const
|
|
91089
|
+
const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals);
|
|
91090
|
+
const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
|
|
90713
91091
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
90714
91092
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
90715
91093
|
logger2.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
90716
91094
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
90717
|
-
|
|
91095
|
+
logger2.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
90718
91096
|
return maxDebtToHave.minus(currentDebt);
|
|
90719
91097
|
}
|
|
90720
|
-
async getLTVConfig(config3) {
|
|
90721
|
-
const CACHE_KEY =
|
|
91098
|
+
async getLTVConfig(config3, blockNumber = "latest") {
|
|
91099
|
+
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
90722
91100
|
const cacheData = this.getCache(CACHE_KEY);
|
|
90723
91101
|
if (cacheData) {
|
|
90724
91102
|
return cacheData;
|
|
@@ -90726,10 +91104,10 @@ spurious results.`);
|
|
|
90726
91104
|
const { contract, isV2 } = await this.getVesuSingletonContract(config3, this.config.poolId);
|
|
90727
91105
|
let ltv = 0;
|
|
90728
91106
|
if (isV2) {
|
|
90729
|
-
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
91107
|
+
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
90730
91108
|
ltv = Number(output.max_ltv) / 1e18;
|
|
90731
91109
|
} else {
|
|
90732
|
-
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
|
|
91110
|
+
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
90733
91111
|
ltv = Number(output.max_ltv) / 1e18;
|
|
90734
91112
|
}
|
|
90735
91113
|
if (ltv == 0) {
|
|
@@ -90738,11 +91116,11 @@ spurious results.`);
|
|
|
90738
91116
|
this.setCache(CACHE_KEY, ltv, 3e5);
|
|
90739
91117
|
return this.getCache(CACHE_KEY);
|
|
90740
91118
|
}
|
|
90741
|
-
async getPositions(config3) {
|
|
91119
|
+
async getPositions(config3, blockNumber = "latest") {
|
|
90742
91120
|
if (!this.pricer) {
|
|
90743
91121
|
throw new Error("Pricer is not initialized");
|
|
90744
91122
|
}
|
|
90745
|
-
const CACHE_KEY =
|
|
91123
|
+
const CACHE_KEY = `positions_${blockNumber}`;
|
|
90746
91124
|
const cacheData = this.getCache(CACHE_KEY);
|
|
90747
91125
|
if (cacheData) {
|
|
90748
91126
|
return cacheData;
|
|
@@ -90754,7 +91132,8 @@ spurious results.`);
|
|
|
90754
91132
|
this.config.collateral.address.address,
|
|
90755
91133
|
this.config.debt.address.address,
|
|
90756
91134
|
this.config.vaultAllocator.address
|
|
90757
|
-
]);
|
|
91135
|
+
], { blockIdentifier: blockNumber });
|
|
91136
|
+
console.log(output);
|
|
90758
91137
|
const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
|
|
90759
91138
|
const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
|
|
90760
91139
|
logger2.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
|
|
@@ -90774,11 +91153,11 @@ spurious results.`);
|
|
|
90774
91153
|
this.setCache(CACHE_KEY, value, 6e4);
|
|
90775
91154
|
return value;
|
|
90776
91155
|
}
|
|
90777
|
-
async getCollateralization(config3) {
|
|
91156
|
+
async getCollateralization(config3, blockNumber = "latest") {
|
|
90778
91157
|
if (!this.pricer) {
|
|
90779
91158
|
throw new Error("Pricer is not initialized");
|
|
90780
91159
|
}
|
|
90781
|
-
const CACHE_KEY =
|
|
91160
|
+
const CACHE_KEY = `collateralization_${blockNumber}`;
|
|
90782
91161
|
const cacheData = this.getCache(CACHE_KEY);
|
|
90783
91162
|
if (cacheData) {
|
|
90784
91163
|
return cacheData;
|
|
@@ -90790,7 +91169,7 @@ spurious results.`);
|
|
|
90790
91169
|
this.config.collateral.address.address,
|
|
90791
91170
|
this.config.debt.address.address,
|
|
90792
91171
|
this.config.vaultAllocator.address
|
|
90793
|
-
]);
|
|
91172
|
+
], { blockIdentifier: blockNumber });
|
|
90794
91173
|
const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
|
|
90795
91174
|
const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
|
|
90796
91175
|
const value = [{
|
|
@@ -90827,9 +91206,9 @@ spurious results.`);
|
|
|
90827
91206
|
ltv
|
|
90828
91207
|
};
|
|
90829
91208
|
}
|
|
90830
|
-
async getHealthFactor() {
|
|
90831
|
-
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
90832
|
-
const collateralisation = await this.getCollateralization(this.networkConfig);
|
|
91209
|
+
async getHealthFactor(blockNumber = "latest") {
|
|
91210
|
+
const ltv = await this.getLTVConfig(this.networkConfig, blockNumber);
|
|
91211
|
+
const collateralisation = await this.getCollateralization(this.networkConfig, blockNumber);
|
|
90833
91212
|
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
90834
91213
|
}
|
|
90835
91214
|
static async getVesuPools(retry = 0) {
|
|
@@ -93488,11 +93867,11 @@ spurious results.`);
|
|
|
93488
93867
|
vesuAdapter2.networkConfig = this.config;
|
|
93489
93868
|
return [vesuAdapter1, vesuAdapter2];
|
|
93490
93869
|
}
|
|
93491
|
-
async getVesuPositions() {
|
|
93870
|
+
async getVesuPositions(blockNumber = "latest") {
|
|
93492
93871
|
const adapters = this.getVesuAdapters();
|
|
93493
93872
|
const positions = [];
|
|
93494
93873
|
for (const adapter of adapters) {
|
|
93495
|
-
positions.push(...await adapter.getPositions(this.config));
|
|
93874
|
+
positions.push(...await adapter.getPositions(this.config, blockNumber));
|
|
93496
93875
|
}
|
|
93497
93876
|
return positions;
|
|
93498
93877
|
}
|
|
@@ -93561,8 +93940,8 @@ spurious results.`);
|
|
|
93561
93940
|
async getLSTAPR(address) {
|
|
93562
93941
|
return 0;
|
|
93563
93942
|
}
|
|
93564
|
-
async getVesuHealthFactors() {
|
|
93565
|
-
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
|
|
93943
|
+
async getVesuHealthFactors(blockNumber = "latest") {
|
|
93944
|
+
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor(blockNumber)));
|
|
93566
93945
|
}
|
|
93567
93946
|
async computeRebalanceConditionAndReturnCalls() {
|
|
93568
93947
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -94156,6 +94535,40 @@ spurious results.`);
|
|
|
94156
94535
|
}
|
|
94157
94536
|
];
|
|
94158
94537
|
|
|
94538
|
+
// src/utils/health-factor-math.ts
|
|
94539
|
+
var HealthFactorMath = class {
|
|
94540
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
94541
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
94542
|
+
const denominator = collateralPrice * maxLTV;
|
|
94543
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
94544
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
94545
|
+
return netCollateral;
|
|
94546
|
+
}
|
|
94547
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
94548
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
94549
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
94550
|
+
return netCollateral.minus(collateralFromDebt);
|
|
94551
|
+
}
|
|
94552
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
94553
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
94554
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
94555
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
94556
|
+
return healthFactor.toNumber();
|
|
94557
|
+
}
|
|
94558
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
94559
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
94560
|
+
const denominator = targetHF - maxLTV;
|
|
94561
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
94562
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
94563
|
+
}
|
|
94564
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
94565
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
94566
|
+
const denominator = targetHF * debtPrice;
|
|
94567
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
94568
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
94569
|
+
}
|
|
94570
|
+
};
|
|
94571
|
+
|
|
94159
94572
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
94160
94573
|
var import_jsx_runtime5 = __toESM(require_jsx_runtime());
|
|
94161
94574
|
var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
|
|
@@ -94171,15 +94584,14 @@ spurious results.`);
|
|
|
94171
94584
|
}
|
|
94172
94585
|
}
|
|
94173
94586
|
asset() {
|
|
94174
|
-
|
|
94175
|
-
return vesuAdapter1.config.collateral;
|
|
94587
|
+
return this.getVesuSameTokenAdapter().config.collateral;
|
|
94176
94588
|
}
|
|
94177
94589
|
getTag() {
|
|
94178
94590
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
94179
94591
|
}
|
|
94180
94592
|
// Vesu adapter with LST and base token match
|
|
94181
94593
|
getVesuSameTokenAdapter() {
|
|
94182
|
-
const baseAdapter = this.getAdapter("
|
|
94594
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
94183
94595
|
baseAdapter.networkConfig = this.config;
|
|
94184
94596
|
baseAdapter.pricer = this.pricer;
|
|
94185
94597
|
return baseAdapter;
|
|
@@ -94227,20 +94639,52 @@ spurious results.`);
|
|
|
94227
94639
|
return price;
|
|
94228
94640
|
}
|
|
94229
94641
|
async getAvnuSwapMultiplyCall(params) {
|
|
94230
|
-
|
|
94231
|
-
|
|
94232
|
-
|
|
94233
|
-
|
|
94234
|
-
|
|
94642
|
+
assert3(params.isDeposit, "Only deposit is supported in getAvnuSwapMultiplyCall");
|
|
94643
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
|
|
94644
|
+
const allVesuAdapters = this.getVesuAdapters();
|
|
94645
|
+
let remainingAmount = params.leg1DepositAmount;
|
|
94646
|
+
const lstExRate = await this.getLSTExchangeRate();
|
|
94647
|
+
const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
|
|
94648
|
+
const lstPrice = baseAssetPrice.price * lstExRate;
|
|
94649
|
+
for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
|
|
94650
|
+
const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
|
|
94651
|
+
const vesuAdapter = allVesuAdapters.find((adapter) => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
|
|
94652
|
+
if (!vesuAdapter) {
|
|
94653
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
|
|
94654
|
+
}
|
|
94655
|
+
const maxLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
94656
|
+
const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
|
|
94657
|
+
const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
|
|
94658
|
+
maxBorrowable.amount,
|
|
94659
|
+
debtPrice.price,
|
|
94660
|
+
this.metadata.additionalInfo.targetHealthFactor,
|
|
94661
|
+
maxLTV,
|
|
94662
|
+
lstPrice,
|
|
94663
|
+
this.asset()
|
|
94664
|
+
);
|
|
94665
|
+
const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
|
|
94666
|
+
logger2.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
|
|
94667
|
+
const call = await this._getAvnuDepositSwapLegCall({
|
|
94668
|
+
isDeposit: params.isDeposit,
|
|
94669
|
+
// adjust decimals of debt asset
|
|
94670
|
+
leg1DepositAmount: amountToDeposit,
|
|
94671
|
+
minHF: 1.1,
|
|
94672
|
+
// undo
|
|
94673
|
+
vesuAdapter
|
|
94674
|
+
});
|
|
94675
|
+
remainingAmount = remainingAmount.minus(amountToDeposit);
|
|
94676
|
+
return { call, vesuAdapter };
|
|
94677
|
+
}
|
|
94678
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
|
|
94235
94679
|
}
|
|
94236
94680
|
async _getAvnuDepositSwapLegCall(params) {
|
|
94681
|
+
const { vesuAdapter } = params;
|
|
94237
94682
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
|
|
94238
94683
|
assert3(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
|
|
94239
|
-
const
|
|
94240
|
-
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
94684
|
+
const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
94241
94685
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
94242
|
-
const existingPositions = await
|
|
94243
|
-
const collateralisation = await
|
|
94686
|
+
const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
94687
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
94244
94688
|
const existingCollateralInfo = existingPositions[0];
|
|
94245
94689
|
const existingDebtInfo = existingPositions[1];
|
|
94246
94690
|
logger2.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
@@ -94248,11 +94692,40 @@ spurious results.`);
|
|
|
94248
94692
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
94249
94693
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
94250
94694
|
logger2.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
94695
|
+
const debtTokenInfo = vesuAdapter.config.debt;
|
|
94696
|
+
let newDepositAmount = params.leg1DepositAmount;
|
|
94251
94697
|
const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
|
|
94252
94698
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
|
|
94253
|
-
const totalDebtAmount =
|
|
94254
|
-
|
|
94255
|
-
|
|
94699
|
+
const totalDebtAmount = new Web3Number(
|
|
94700
|
+
totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
|
|
94701
|
+
debtTokenInfo.decimals
|
|
94702
|
+
);
|
|
94703
|
+
let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
|
|
94704
|
+
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
|
|
94705
|
+
const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
|
|
94706
|
+
if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
|
|
94707
|
+
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
|
|
94708
|
+
return void 0;
|
|
94709
|
+
} else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
|
|
94710
|
+
debtAmount = maxBorrowable.amount.minimum(debtAmount);
|
|
94711
|
+
const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
|
|
94712
|
+
const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
|
|
94713
|
+
debtAmount.plus(existingDebtInfo.amount),
|
|
94714
|
+
debtPrice,
|
|
94715
|
+
params.minHF,
|
|
94716
|
+
legLTV,
|
|
94717
|
+
collateralPrice,
|
|
94718
|
+
this.asset()
|
|
94719
|
+
);
|
|
94720
|
+
newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
|
|
94721
|
+
if (newDepositAmount.lt(0)) {
|
|
94722
|
+
throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
|
|
94723
|
+
}
|
|
94724
|
+
if (newDebtUSDValue.toNumber() < 100) {
|
|
94725
|
+
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
|
|
94726
|
+
return void 0;
|
|
94727
|
+
}
|
|
94728
|
+
}
|
|
94256
94729
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
94257
94730
|
if (debtAmount.lt(0)) {
|
|
94258
94731
|
const lstDEXPrice = await this.getLSTDexPrice();
|
|
@@ -94264,32 +94737,34 @@ spurious results.`);
|
|
|
94264
94737
|
assert3(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
94265
94738
|
return calls[0];
|
|
94266
94739
|
}
|
|
94740
|
+
console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
|
|
94267
94741
|
const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
|
|
94268
94742
|
const manage0Info = this.getProofs(STEP0);
|
|
94269
94743
|
const manageCall0 = manage0Info.callConstructor({
|
|
94270
|
-
amount:
|
|
94744
|
+
amount: newDepositAmount
|
|
94271
94745
|
});
|
|
94272
|
-
const STEP1 = "vesu_leg1" /* VESU_LEG1
|
|
94746
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
94273
94747
|
const manage1Info = this.getProofs(STEP1);
|
|
94274
94748
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
94275
|
-
collateralAmount:
|
|
94749
|
+
collateralAmount: newDepositAmount,
|
|
94276
94750
|
isAddCollateral: params.isDeposit,
|
|
94277
94751
|
debtAmount,
|
|
94278
94752
|
isBorrow: params.isDeposit
|
|
94279
94753
|
}));
|
|
94754
|
+
console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
94280
94755
|
const proofIds = [STEP0, STEP1];
|
|
94281
94756
|
const manageCalls = [manageCall0, manageCall1];
|
|
94282
94757
|
if (debtAmount.gt(0)) {
|
|
94283
|
-
const STEP2 = "
|
|
94758
|
+
const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
94284
94759
|
const manage2Info = this.getProofs(STEP2);
|
|
94285
94760
|
const manageCall2 = manage2Info.callConstructor({
|
|
94286
94761
|
amount: debtAmount
|
|
94287
94762
|
});
|
|
94288
|
-
const
|
|
94763
|
+
const debtTokenInfo2 = vesuAdapter.config.debt;
|
|
94289
94764
|
const lstTokenInfo = this.asset();
|
|
94290
94765
|
const avnuModule = new AvnuWrapper();
|
|
94291
94766
|
const quote = await avnuModule.getQuotes(
|
|
94292
|
-
|
|
94767
|
+
debtTokenInfo2.address.address,
|
|
94293
94768
|
lstTokenInfo.address.address,
|
|
94294
94769
|
debtAmount.toWei(),
|
|
94295
94770
|
this.metadata.additionalInfo.vaultAllocator.address
|
|
@@ -94305,7 +94780,7 @@ spurious results.`);
|
|
|
94305
94780
|
minAmountWei
|
|
94306
94781
|
);
|
|
94307
94782
|
logger2.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
|
|
94308
|
-
const STEP3 = "
|
|
94783
|
+
const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
94309
94784
|
const manage3Info = this.getProofs(STEP3);
|
|
94310
94785
|
const manageCall3 = manage3Info.callConstructor({
|
|
94311
94786
|
props: swapInfo
|
|
@@ -94323,7 +94798,7 @@ spurious results.`);
|
|
|
94323
94798
|
const manageCall4 = manage4Info.callConstructor({
|
|
94324
94799
|
amount: minAmount
|
|
94325
94800
|
});
|
|
94326
|
-
const STEP5 = "vesu_leg1" /* VESU_LEG1
|
|
94801
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
94327
94802
|
const manage5Info = this.getProofs(STEP5);
|
|
94328
94803
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
94329
94804
|
collateralAmount: minAmount,
|
|
@@ -94340,28 +94815,41 @@ spurious results.`);
|
|
|
94340
94815
|
}
|
|
94341
94816
|
// todo unwind or not deposit when the yield is bad.
|
|
94342
94817
|
async getLSTMultiplierRebalanceCall() {
|
|
94343
|
-
|
|
94344
|
-
|
|
94818
|
+
let shouldRebalance = false;
|
|
94819
|
+
const calls = [];
|
|
94820
|
+
const allVesuAdapters = this.getVesuAdapters().filter((vesuAdapter) => vesuAdapter.config.debt.symbol === "LBTC");
|
|
94821
|
+
for (const vesuAdapter of allVesuAdapters) {
|
|
94822
|
+
const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
|
|
94823
|
+
if (call.shouldRebalance && call.manageCall) {
|
|
94824
|
+
shouldRebalance = true;
|
|
94825
|
+
calls.push({ vesuAdapter, manageCall: call.manageCall });
|
|
94826
|
+
}
|
|
94827
|
+
}
|
|
94828
|
+
return { shouldRebalance, manageCalls: calls };
|
|
94829
|
+
}
|
|
94830
|
+
async _getLSTMultiplierRebalanceCall(vesuAdapter) {
|
|
94831
|
+
const positions = await vesuAdapter.getPositions(this.config);
|
|
94832
|
+
assert3(positions.length == 2, "Rebalance call is only supported for 2 positions");
|
|
94345
94833
|
const existingCollateralInfo = positions[0];
|
|
94346
94834
|
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)},
|
|
94835
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
94836
|
+
const healthFactor = await vesuAdapter.getHealthFactor();
|
|
94837
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
94838
|
+
logger2.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
94353
94839
|
existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
94354
94840
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
94355
94841
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
94356
94842
|
logger2.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
94843
|
+
logger2.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
|
|
94357
94844
|
const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
94358
94845
|
const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
94359
|
-
if (isHFTooLow || isHFTooHigh) {
|
|
94846
|
+
if (isHFTooLow || isHFTooHigh || 1) {
|
|
94360
94847
|
const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
94361
94848
|
isDeposit: true,
|
|
94362
94849
|
leg1DepositAmount: unusedBalance.amount,
|
|
94363
|
-
minHF: 1.02
|
|
94850
|
+
minHF: 1.02,
|
|
94364
94851
|
// todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
94852
|
+
vesuAdapter
|
|
94365
94853
|
});
|
|
94366
94854
|
return { shouldRebalance: true, manageCall };
|
|
94367
94855
|
} else {
|
|
@@ -94394,7 +94882,7 @@ spurious results.`);
|
|
|
94394
94882
|
async _getMinOutputAmountLSTBuy(amountInUnderlying) {
|
|
94395
94883
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
94396
94884
|
const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
|
|
94397
|
-
return minOutputAmount;
|
|
94885
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
94398
94886
|
}
|
|
94399
94887
|
async _getMinOutputAmountLSTSell(amountInLST) {
|
|
94400
94888
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
@@ -94451,21 +94939,52 @@ spurious results.`);
|
|
|
94451
94939
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
94452
94940
|
return vesuAdapter1.config.debt;
|
|
94453
94941
|
}
|
|
94454
|
-
async getMaxBorrowableAmount() {
|
|
94942
|
+
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
94455
94943
|
const vesuAdapters = this.getVesuAdapters();
|
|
94456
94944
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
94457
94945
|
const maxBorrowables = [];
|
|
94458
|
-
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
94459
|
-
const maxInterestRate = lstAPY * 0.8;
|
|
94460
94946
|
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 });
|
|
94947
|
+
maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
|
|
94464
94948
|
}
|
|
94465
94949
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
94466
94950
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
94467
94951
|
return { netMaxBorrowableAmount, maxBorrowables };
|
|
94468
94952
|
}
|
|
94953
|
+
// recursively, using binary search computes max swappable.
|
|
94954
|
+
// @dev assumes 1 token of from == 1 token of to
|
|
94955
|
+
async getMaxSwappableWithMaxSlippage(fromToken, toToken, maxSlippage, maxAmount) {
|
|
94956
|
+
const output = await findMaxInputWithSlippage({
|
|
94957
|
+
apiGetOutput: async (inputAmount) => {
|
|
94958
|
+
const ekuboQuoter = new EkuboQuoter(this.config);
|
|
94959
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
94960
|
+
const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
|
|
94961
|
+
return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
|
|
94962
|
+
},
|
|
94963
|
+
maxInput: maxAmount.toNumber(),
|
|
94964
|
+
maxSlippagePercent: maxSlippage,
|
|
94965
|
+
tolerance: 1e-3,
|
|
94966
|
+
referenceRate: 1
|
|
94967
|
+
});
|
|
94968
|
+
return new Web3Number(output.optimalInput, fromToken.decimals);
|
|
94969
|
+
}
|
|
94970
|
+
async getMaxBorrowableAmountByVesuAdapter(vesuAdapter, isAPYComputation) {
|
|
94971
|
+
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
94972
|
+
const maxInterestRate = lstAPY * 0.8;
|
|
94973
|
+
const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
|
|
94974
|
+
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
94975
|
+
const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
|
|
94976
|
+
if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
|
|
94977
|
+
return { amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
94978
|
+
}
|
|
94979
|
+
try {
|
|
94980
|
+
const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 2e-4, maxBorrowable);
|
|
94981
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
94982
|
+
} catch (error2) {
|
|
94983
|
+
logger2.warn(`${this.getTag()}: Failed to get max swappable: ${error2}`);
|
|
94984
|
+
const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
|
|
94985
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
94986
|
+
}
|
|
94987
|
+
}
|
|
94469
94988
|
// todo how much to unwind to get back healthy APY zone again
|
|
94470
94989
|
// if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
|
|
94471
94990
|
// For xSTRK, simply deposit in Vesu if looping is not viable
|
|
@@ -94489,7 +95008,7 @@ spurious results.`);
|
|
|
94489
95008
|
// todo undo this
|
|
94490
95009
|
async netAPY() {
|
|
94491
95010
|
const unusedBalance = await this.getUnusedBalance();
|
|
94492
|
-
const maxNewDeposits = await this.maxNewDeposits();
|
|
95011
|
+
const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
94493
95012
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
94494
95013
|
if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
94495
95014
|
logger2.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
|
|
@@ -94506,8 +95025,8 @@ spurious results.`);
|
|
|
94506
95025
|
return output;
|
|
94507
95026
|
}
|
|
94508
95027
|
}
|
|
94509
|
-
async maxNewDeposits() {
|
|
94510
|
-
const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
|
|
95028
|
+
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
95029
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
94511
95030
|
let ltv = void 0;
|
|
94512
95031
|
for (let adapter of this.getVesuAdapters()) {
|
|
94513
95032
|
const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
|
|
@@ -94610,7 +95129,7 @@ spurious results.`);
|
|
|
94610
95129
|
const manageCall2 = manage2Info.callConstructor({
|
|
94611
95130
|
delegation: true
|
|
94612
95131
|
});
|
|
94613
|
-
const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU
|
|
95132
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
94614
95133
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
94615
95134
|
const multiplyParams = params.isIncrease ? {
|
|
94616
95135
|
isIncrease: true,
|
|
@@ -94676,6 +95195,7 @@ spurious results.`);
|
|
|
94676
95195
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }, children: [
|
|
94677
95196
|
"This vault uses Vesu for lending and borrowing. The oracle used by this pool is a ",
|
|
94678
95197
|
highlightTextWithLinks("conversion rate oracle", [{ highlight: "conversion rate oracle", link: "https://docs.pragma.build/starknet/development#conversion-rate" }]),
|
|
95198
|
+
" ",
|
|
94679
95199
|
"which is resilient to liquidity issues and price volatility, hence reducing the risk of liquidation. However, overtime, if left un-monitored, debt can increase enough to trigger a liquidation. But no worries, our continuous monitoring systems look for situations with reduced health factor and balance collateral/debt to bring it back to safe levels. With Troves, you can have a peaceful sleep."
|
|
94680
95200
|
] }),
|
|
94681
95201
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
|
|
@@ -94686,17 +95206,19 @@ spurious results.`);
|
|
|
94686
95206
|
] }) }),
|
|
94687
95207
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
|
|
94688
95208
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "Debt limits:" }),
|
|
94689
|
-
" Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited LSTs remain in the vault, generating a shared net return for all depositors."
|
|
94690
|
-
] }) }),
|
|
94691
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
|
|
94692
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: "APY assumptions:" }),
|
|
94693
|
-
" APY shown is the max possible value given current LST and borrowing rates. True APY will be subject to the actual leverage, based on above point. More insights on exact APY will be added soon."
|
|
95209
|
+
" Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited LSTs remain in the vault, generating a shared net return for all depositors. There is no additional fee taken by Troves on LST APY, its only on added gain."
|
|
94694
95210
|
] }) })
|
|
94695
95211
|
] });
|
|
94696
95212
|
}
|
|
94697
95213
|
function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
94698
95214
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
94699
95215
|
}
|
|
95216
|
+
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
95217
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
95218
|
+
}
|
|
95219
|
+
function getVesuLegId(baseID, debtTokenSymbol) {
|
|
95220
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
95221
|
+
}
|
|
94700
95222
|
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
94701
95223
|
vaultSettings.leafAdapters = [];
|
|
94702
95224
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
@@ -94706,7 +95228,7 @@ spurious results.`);
|
|
|
94706
95228
|
collateral: lstToken,
|
|
94707
95229
|
debt: underlyingToken,
|
|
94708
95230
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
94709
|
-
id: "vesu_leg1" /* VESU_LEG1
|
|
95231
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
94710
95232
|
});
|
|
94711
95233
|
const commonAdapter = new CommonAdapter({
|
|
94712
95234
|
manager: vaultSettings.manager,
|
|
@@ -94715,25 +95237,39 @@ spurious results.`);
|
|
|
94715
95237
|
vaultAddress: vaultSettings.vaultAddress,
|
|
94716
95238
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
94717
95239
|
});
|
|
94718
|
-
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
94719
|
-
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
94720
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
94721
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter("multiply_vesu" /* MULTIPLY_VESU */).bind(vesuAdapterLST));
|
|
94722
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
94723
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
94724
95240
|
vaultSettings.adapters.push(...[{
|
|
94725
|
-
id: "
|
|
95241
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
94726
95242
|
adapter: vesuAdapterLST
|
|
94727
95243
|
}, {
|
|
94728
95244
|
id: "common_adapter" /* COMMON */,
|
|
94729
95245
|
adapter: commonAdapter
|
|
94730
95246
|
}]);
|
|
94731
|
-
|
|
94732
|
-
|
|
94733
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address,
|
|
94734
|
-
vaultSettings.leafAdapters.push(
|
|
94735
|
-
vaultSettings.leafAdapters.push(
|
|
94736
|
-
vaultSettings.leafAdapters.push(
|
|
95247
|
+
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
95248
|
+
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
95249
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
95250
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
95251
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
95252
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_mul_approve_withdr" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
|
|
95253
|
+
for (let borrowableAsset of vaultSettings.borrowable_assets) {
|
|
95254
|
+
const debtAsset = borrowableAsset;
|
|
95255
|
+
const approve_debt_token_id = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, debtAsset.symbol);
|
|
95256
|
+
const swap_debt_token_id = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, debtAsset.symbol);
|
|
95257
|
+
const swap_lst_token_id = getAvnuManageIDs("avnu_mul_swap_withdr" /* AVNU_MULTIPLY_SWAP_WITHDRAW */, debtAsset.symbol);
|
|
95258
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
|
|
95259
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
|
|
95260
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
|
|
95261
|
+
const vesuAdapter = new VesuAdapter({
|
|
95262
|
+
poolId: pool1,
|
|
95263
|
+
collateral: lstToken,
|
|
95264
|
+
debt: debtAsset,
|
|
95265
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
95266
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol)
|
|
95267
|
+
});
|
|
95268
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
|
|
95269
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
|
|
95270
|
+
const multiplID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, debtAsset.symbol);
|
|
95271
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getMultiplyAdapter(multiplID).bind(vesuAdapter));
|
|
95272
|
+
}
|
|
94737
95273
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
94738
95274
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
94739
95275
|
vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
|
|
@@ -94811,7 +95347,8 @@ spurious results.`);
|
|
|
94811
95347
|
adapters: [],
|
|
94812
95348
|
targetHealthFactor: 1.1,
|
|
94813
95349
|
minHealthFactor: 1.05,
|
|
94814
|
-
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK")
|
|
95350
|
+
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK"),
|
|
95351
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK")
|
|
94815
95352
|
};
|
|
94816
95353
|
var hyperxWBTC = {
|
|
94817
95354
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -94823,7 +95360,8 @@ spurious results.`);
|
|
|
94823
95360
|
adapters: [],
|
|
94824
95361
|
targetHealthFactor: 1.1,
|
|
94825
95362
|
minHealthFactor: 1.05,
|
|
94826
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95363
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95364
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC")
|
|
94827
95365
|
};
|
|
94828
95366
|
var hyperxtBTC = {
|
|
94829
95367
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -94835,7 +95373,8 @@ spurious results.`);
|
|
|
94835
95373
|
adapters: [],
|
|
94836
95374
|
targetHealthFactor: 1.1,
|
|
94837
95375
|
minHealthFactor: 1.05,
|
|
94838
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95376
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95377
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC")
|
|
94839
95378
|
};
|
|
94840
95379
|
var hyperxsBTC = {
|
|
94841
95380
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -94847,7 +95386,8 @@ spurious results.`);
|
|
|
94847
95386
|
adapters: [],
|
|
94848
95387
|
targetHealthFactor: 1.1,
|
|
94849
95388
|
minHealthFactor: 1.05,
|
|
94850
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95389
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95390
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC")
|
|
94851
95391
|
};
|
|
94852
95392
|
var hyperxLBTC = {
|
|
94853
95393
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -94859,7 +95399,8 @@ spurious results.`);
|
|
|
94859
95399
|
adapters: [],
|
|
94860
95400
|
targetHealthFactor: 1.1,
|
|
94861
95401
|
minHealthFactor: 1.05,
|
|
94862
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
95402
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
95403
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC")
|
|
94863
95404
|
};
|
|
94864
95405
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
94865
95406
|
return [
|
|
@@ -94891,7 +95432,7 @@ spurious results.`);
|
|
|
94891
95432
|
faqs: getFAQs2(lstSymbol, underlyingSymbol),
|
|
94892
95433
|
investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
|
|
94893
95434
|
isPreview,
|
|
94894
|
-
apyMethodology: "Current annualized APY in terms of base asset of the LST"
|
|
95435
|
+
apyMethodology: "Current annualized APY in terms of base asset of the LST. There is no additional fee taken by Troves on LST APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown."
|
|
94895
95436
|
};
|
|
94896
95437
|
}
|
|
94897
95438
|
var HyperLSTStrategies = [
|