@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
package/dist/index.mjs
CHANGED
|
@@ -315,6 +315,25 @@ var defaultTokens = [{
|
|
|
315
315
|
priceProxySymbol: "WBTC",
|
|
316
316
|
priceCheckAmount: 1e-4
|
|
317
317
|
// 112000 * 0.0001 = $11.2
|
|
318
|
+
}, {
|
|
319
|
+
name: "mRe7BTC",
|
|
320
|
+
symbol: "mRe7BTC",
|
|
321
|
+
logo: "https://imagedelivery.net/0xPAQaDtnQhBs8IzYRIlNg/3a62ecee-1e58-45d3-9862-3ce90dff1900/logo",
|
|
322
|
+
address: ContractAddr.from("0x4e4fb1a9ca7e84bae609b9dc0078ad7719e49187ae7e425bb47d131710eddac"),
|
|
323
|
+
decimals: 18,
|
|
324
|
+
coingeckId: void 0,
|
|
325
|
+
displayDecimals: 6,
|
|
326
|
+
priceCheckAmount: 1e-4
|
|
327
|
+
// 112000 * 0.0001 = $11.2
|
|
328
|
+
}, {
|
|
329
|
+
name: "mRe7YIELD",
|
|
330
|
+
symbol: "mRe7YIELD",
|
|
331
|
+
logo: "https://midas.app/assets/mre7-BcOOHm7i.svg",
|
|
332
|
+
address: ContractAddr.from("0x4be8945e61dc3e19ebadd1579a6bd53b262f51ba89e6f8b0c4bc9a7e3c633fc"),
|
|
333
|
+
decimals: 18,
|
|
334
|
+
coingeckId: void 0,
|
|
335
|
+
displayDecimals: 2,
|
|
336
|
+
priceCheckAmount: 100
|
|
318
337
|
}];
|
|
319
338
|
var tokens = defaultTokens;
|
|
320
339
|
var _Global = class _Global {
|
|
@@ -2208,16 +2227,16 @@ var AvnuWrapper = class _AvnuWrapper {
|
|
|
2208
2227
|
};
|
|
2209
2228
|
return swapInfo;
|
|
2210
2229
|
}
|
|
2211
|
-
static buildZeroSwap(tokenToSell,
|
|
2230
|
+
static buildZeroSwap(tokenToSell, beneficiary, tokenToBuy = tokenToSell) {
|
|
2212
2231
|
return {
|
|
2213
2232
|
token_from_address: tokenToSell.address,
|
|
2214
2233
|
token_from_amount: uint256.bnToUint256(0),
|
|
2215
|
-
token_to_address:
|
|
2234
|
+
token_to_address: tokenToBuy.address,
|
|
2216
2235
|
token_to_amount: uint256.bnToUint256(0),
|
|
2217
2236
|
token_to_min_amount: uint256.bnToUint256(0),
|
|
2218
|
-
beneficiary
|
|
2237
|
+
beneficiary,
|
|
2219
2238
|
integrator_fee_amount_bps: 0,
|
|
2220
|
-
integrator_fee_recipient:
|
|
2239
|
+
integrator_fee_recipient: beneficiary,
|
|
2221
2240
|
routes: []
|
|
2222
2241
|
};
|
|
2223
2242
|
}
|
|
@@ -4018,21 +4037,20 @@ var Harvests = class _Harvests {
|
|
|
4018
4037
|
const rewards = await this.getHarvests(addr);
|
|
4019
4038
|
if (rewards.length == 0) return [];
|
|
4020
4039
|
const unClaimed = [];
|
|
4021
|
-
const
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
}
|
|
4029
|
-
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4030
|
-
if (bal.lessThan(reward.claim.amount)) {
|
|
4031
|
-
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4032
|
-
continue;
|
|
4033
|
-
}
|
|
4034
|
-
unClaimed.unshift(reward);
|
|
4040
|
+
const reward = rewards.sort((a, b) => b.endDate.getTime() - a.endDate.getTime())[0];
|
|
4041
|
+
const cls = await this.config.provider.getClassAt(reward.rewardsContract.address);
|
|
4042
|
+
const contract = new Contract4({ abi: cls.abi, address: reward.rewardsContract.address, providerOrAccount: this.config.provider });
|
|
4043
|
+
const isClaimed = await contract.call("is_claimed", [reward.claim.id]);
|
|
4044
|
+
logger.verbose(`${_Harvests.name}: isClaimed: ${isClaimed}`);
|
|
4045
|
+
if (isClaimed) {
|
|
4046
|
+
return unClaimed;
|
|
4035
4047
|
}
|
|
4048
|
+
const bal = await new ERC20(this.config).balanceOf(reward.token, reward.rewardsContract.address, 18);
|
|
4049
|
+
if (bal.lessThan(reward.claim.amount)) {
|
|
4050
|
+
logger.verbose(`${_Harvests.name}: balance: ${bal.toString()}, amount: ${reward.claim.amount.toString()}`);
|
|
4051
|
+
return unClaimed;
|
|
4052
|
+
}
|
|
4053
|
+
unClaimed.unshift(reward);
|
|
4036
4054
|
return unClaimed;
|
|
4037
4055
|
}
|
|
4038
4056
|
};
|
|
@@ -15299,6 +15317,91 @@ var apolloClient = new ApolloClient({
|
|
|
15299
15317
|
});
|
|
15300
15318
|
var apollo_client_default = apolloClient;
|
|
15301
15319
|
|
|
15320
|
+
// src/utils/math-utils.ts
|
|
15321
|
+
async function binarySearch(lowWei, highWei, callback) {
|
|
15322
|
+
while (lowWei <= highWei) {
|
|
15323
|
+
const diff = highWei - lowWei;
|
|
15324
|
+
const mid = lowWei + diff / 2n;
|
|
15325
|
+
const result = await callback(mid);
|
|
15326
|
+
if (result === "found") {
|
|
15327
|
+
return mid;
|
|
15328
|
+
} else if (result == "retry") {
|
|
15329
|
+
} else if (result === "go_low") {
|
|
15330
|
+
highWei = mid - BigInt(1);
|
|
15331
|
+
} else {
|
|
15332
|
+
lowWei = mid + BigInt(1);
|
|
15333
|
+
}
|
|
15334
|
+
}
|
|
15335
|
+
return null;
|
|
15336
|
+
}
|
|
15337
|
+
async function findMaxInputWithSlippage(options) {
|
|
15338
|
+
const {
|
|
15339
|
+
apiGetOutput,
|
|
15340
|
+
maxInput,
|
|
15341
|
+
maxSlippagePercent,
|
|
15342
|
+
tolerance,
|
|
15343
|
+
minInput = 0,
|
|
15344
|
+
referenceAmountMultiplier = 1e-3,
|
|
15345
|
+
referenceRate = 0
|
|
15346
|
+
} = options;
|
|
15347
|
+
let apiCalls = 0;
|
|
15348
|
+
if (!referenceRate && !referenceAmountMultiplier) {
|
|
15349
|
+
throw new Error("One of referenceRate or referenceAmountMultiplier must be provided");
|
|
15350
|
+
}
|
|
15351
|
+
let _referenceRate = referenceRate;
|
|
15352
|
+
if (!_referenceRate) {
|
|
15353
|
+
const smallAmount = maxInput * referenceAmountMultiplier;
|
|
15354
|
+
const referenceOutput = await apiGetOutput(smallAmount);
|
|
15355
|
+
apiCalls++;
|
|
15356
|
+
_referenceRate = referenceOutput / smallAmount;
|
|
15357
|
+
}
|
|
15358
|
+
async function checkSlippage(inputAmount) {
|
|
15359
|
+
const actualOutput = await apiGetOutput(inputAmount);
|
|
15360
|
+
apiCalls++;
|
|
15361
|
+
const expectedOutput = inputAmount * referenceRate;
|
|
15362
|
+
const slippage = (expectedOutput - actualOutput) / expectedOutput;
|
|
15363
|
+
logger.verbose(`findMaxInputWithSlippage::checkSlippage inputAmount: ${inputAmount}, actualOutput: ${actualOutput}, slippage: ${slippage}, maxSlippagePercent: ${maxSlippagePercent}`);
|
|
15364
|
+
return {
|
|
15365
|
+
acceptable: slippage <= maxSlippagePercent,
|
|
15366
|
+
slippage,
|
|
15367
|
+
output: actualOutput
|
|
15368
|
+
};
|
|
15369
|
+
}
|
|
15370
|
+
const maxCheck = await checkSlippage(maxInput);
|
|
15371
|
+
if (maxCheck.acceptable) {
|
|
15372
|
+
return {
|
|
15373
|
+
optimalInput: maxInput,
|
|
15374
|
+
actualOutput: maxCheck.output,
|
|
15375
|
+
actualSlippage: maxCheck.slippage,
|
|
15376
|
+
apiCallsUsed: apiCalls
|
|
15377
|
+
};
|
|
15378
|
+
}
|
|
15379
|
+
let left = minInput;
|
|
15380
|
+
let right = maxInput;
|
|
15381
|
+
let bestInput = minInput;
|
|
15382
|
+
let bestOutput = 0;
|
|
15383
|
+
let bestSlippage = 0;
|
|
15384
|
+
const convergenceThreshold = tolerance * maxInput;
|
|
15385
|
+
while (right - left > convergenceThreshold) {
|
|
15386
|
+
const mid = (left + right) / 2;
|
|
15387
|
+
const midCheck = await checkSlippage(mid);
|
|
15388
|
+
if (midCheck.acceptable) {
|
|
15389
|
+
bestInput = mid;
|
|
15390
|
+
bestOutput = midCheck.output;
|
|
15391
|
+
bestSlippage = midCheck.slippage;
|
|
15392
|
+
left = mid;
|
|
15393
|
+
} else {
|
|
15394
|
+
right = mid;
|
|
15395
|
+
}
|
|
15396
|
+
}
|
|
15397
|
+
return {
|
|
15398
|
+
optimalInput: bestInput,
|
|
15399
|
+
actualOutput: bestOutput,
|
|
15400
|
+
actualSlippage: bestSlippage,
|
|
15401
|
+
apiCallsUsed: apiCalls
|
|
15402
|
+
};
|
|
15403
|
+
}
|
|
15404
|
+
|
|
15302
15405
|
// src/strategies/ekubo-cl-vault.tsx
|
|
15303
15406
|
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
15304
15407
|
var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
@@ -16421,62 +16524,193 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16421
16524
|
logger.verbose(
|
|
16422
16525
|
`${_EkuboCLVault.name}: harvest => Processing claim, isToken1: ${isToken1} amount: ${postFeeAmount.toWei()}`
|
|
16423
16526
|
);
|
|
16424
|
-
const
|
|
16425
|
-
|
|
16527
|
+
const isRewardTokenMatch = claim.token.eq(poolKey.token0) || claim.token.eq(poolKey.token1);
|
|
16528
|
+
if (isRewardTokenMatch) {
|
|
16529
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMatchHarvest({
|
|
16530
|
+
acc,
|
|
16531
|
+
claim,
|
|
16532
|
+
isToken1,
|
|
16533
|
+
token0Info,
|
|
16534
|
+
token1Info,
|
|
16535
|
+
postFeeAmount,
|
|
16536
|
+
poolKey,
|
|
16537
|
+
bounds,
|
|
16538
|
+
maxIterations,
|
|
16539
|
+
priceRatioPrecision
|
|
16540
|
+
});
|
|
16541
|
+
calls.push(..._callsFinal);
|
|
16542
|
+
} else {
|
|
16543
|
+
const _callsFinal = await this._handleRewardAndVaultTokenMismatchHarvest({
|
|
16544
|
+
claim,
|
|
16545
|
+
token0Info,
|
|
16546
|
+
token1Info,
|
|
16547
|
+
postFeeAmount,
|
|
16548
|
+
poolKey,
|
|
16549
|
+
bounds,
|
|
16550
|
+
maxIterations,
|
|
16551
|
+
priceRatioPrecision,
|
|
16552
|
+
acc
|
|
16553
|
+
});
|
|
16554
|
+
calls.push(..._callsFinal);
|
|
16555
|
+
}
|
|
16556
|
+
}
|
|
16557
|
+
return calls;
|
|
16558
|
+
}
|
|
16559
|
+
/**
|
|
16560
|
+
* @description This funciton requires atleast one of the pool tokens to be reward token
|
|
16561
|
+
* i.e. STRK.
|
|
16562
|
+
* @param params
|
|
16563
|
+
*/
|
|
16564
|
+
async _handleRewardAndVaultTokenMatchHarvest(params) {
|
|
16565
|
+
const { acc, claim, isToken1, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
16566
|
+
const token0Amt = isToken1 ? new Web3Number(0, token0Info.decimals) : postFeeAmount;
|
|
16567
|
+
const token1Amt = isToken1 ? postFeeAmount : new Web3Number(0, token0Info.decimals);
|
|
16568
|
+
logger.verbose(
|
|
16569
|
+
`${_EkuboCLVault.name}: harvest => token0Amt: ${token0Amt.toString()}, token1Amt: ${token1Amt.toString()}`
|
|
16570
|
+
);
|
|
16571
|
+
const swapInfo = await this.getSwapInfoGivenAmounts(
|
|
16572
|
+
poolKey,
|
|
16573
|
+
token0Amt,
|
|
16574
|
+
token1Amt,
|
|
16575
|
+
bounds,
|
|
16576
|
+
maxIterations,
|
|
16577
|
+
priceRatioPrecision
|
|
16578
|
+
);
|
|
16579
|
+
swapInfo.token_to_address = token0Info.address.address;
|
|
16580
|
+
logger.verbose(
|
|
16581
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(swapInfo)}`
|
|
16582
|
+
);
|
|
16583
|
+
logger.verbose(
|
|
16584
|
+
`${_EkuboCLVault.name}: harvest => claim: ${JSON.stringify(claim)}`
|
|
16585
|
+
);
|
|
16586
|
+
const harvestEstimateCall = async (swapInfo1) => {
|
|
16587
|
+
const swap1Amount = Web3Number.fromWei(
|
|
16588
|
+
uint2564.uint256ToBN(swapInfo1.token_from_amount).toString(),
|
|
16589
|
+
18
|
|
16590
|
+
// cause its always STRK?
|
|
16591
|
+
).minimum(
|
|
16592
|
+
postFeeAmount.toFixed(18)
|
|
16593
|
+
// cause always strk
|
|
16594
|
+
);
|
|
16595
|
+
swapInfo.token_from_amount = uint2564.bnToUint256(swap1Amount.toWei());
|
|
16596
|
+
swapInfo.token_to_min_amount = uint2564.bnToUint256(
|
|
16597
|
+
swap1Amount.multipliedBy(0).toWei()
|
|
16598
|
+
// placeholder
|
|
16599
|
+
);
|
|
16426
16600
|
logger.verbose(
|
|
16427
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16601
|
+
`${_EkuboCLVault.name}: harvest => swap1Amount: ${swap1Amount}`
|
|
16428
16602
|
);
|
|
16429
|
-
const
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
token1Amt,
|
|
16433
|
-
bounds,
|
|
16434
|
-
maxIterations,
|
|
16435
|
-
priceRatioPrecision
|
|
16603
|
+
const remainingAmount = postFeeAmount.minus(swap1Amount).maximum(0);
|
|
16604
|
+
logger.verbose(
|
|
16605
|
+
`${_EkuboCLVault.name}: harvest => remainingAmount: ${remainingAmount}`
|
|
16436
16606
|
);
|
|
16437
|
-
|
|
16607
|
+
const swapInfo2 = {
|
|
16608
|
+
...swapInfo,
|
|
16609
|
+
token_from_amount: uint2564.bnToUint256(remainingAmount.toWei())
|
|
16610
|
+
};
|
|
16611
|
+
swapInfo2.token_to_address = token1Info.address.address;
|
|
16438
16612
|
logger.verbose(
|
|
16439
|
-
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16613
|
+
`${_EkuboCLVault.name}: harvest => swapInfo: ${JSON.stringify(
|
|
16614
|
+
swapInfo
|
|
16615
|
+
)}`
|
|
16440
16616
|
);
|
|
16441
16617
|
logger.verbose(
|
|
16442
|
-
`${_EkuboCLVault.name}: harvest =>
|
|
16618
|
+
`${_EkuboCLVault.name}: harvest => swapInfo2: ${JSON.stringify(
|
|
16619
|
+
swapInfo2
|
|
16620
|
+
)}`
|
|
16443
16621
|
);
|
|
16444
|
-
const
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16449
|
-
|
|
16450
|
-
|
|
16451
|
-
|
|
16452
|
-
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
|
|
16462
|
-
|
|
16463
|
-
|
|
16464
|
-
|
|
16465
|
-
|
|
16466
|
-
|
|
16467
|
-
|
|
16468
|
-
|
|
16469
|
-
|
|
16470
|
-
|
|
16471
|
-
|
|
16472
|
-
|
|
16473
|
-
|
|
16474
|
-
|
|
16475
|
-
|
|
16476
|
-
|
|
16477
|
-
|
|
16478
|
-
|
|
16479
|
-
|
|
16622
|
+
const calldata = [
|
|
16623
|
+
claim.rewardsContract.address,
|
|
16624
|
+
{
|
|
16625
|
+
id: claim.claim.id,
|
|
16626
|
+
amount: claim.claim.amount.toWei(),
|
|
16627
|
+
claimee: claim.claim.claimee.address
|
|
16628
|
+
},
|
|
16629
|
+
claim.proof.map((p) => num5.getDecimalString(p)),
|
|
16630
|
+
swapInfo,
|
|
16631
|
+
swapInfo2
|
|
16632
|
+
];
|
|
16633
|
+
logger.verbose(
|
|
16634
|
+
`${_EkuboCLVault.name}: harvest => calldata: ${JSON.stringify(
|
|
16635
|
+
calldata
|
|
16636
|
+
)}`
|
|
16637
|
+
);
|
|
16638
|
+
return [this.contract.populate("harvest", calldata)];
|
|
16639
|
+
};
|
|
16640
|
+
const _callsFinal = await this.rebalanceIter(
|
|
16641
|
+
swapInfo,
|
|
16642
|
+
acc,
|
|
16643
|
+
harvestEstimateCall,
|
|
16644
|
+
claim.token.eq(poolKey.token0),
|
|
16645
|
+
0,
|
|
16646
|
+
0n,
|
|
16647
|
+
BigInt(postFeeAmount.toWei())
|
|
16648
|
+
// upper limit is the post fee amount
|
|
16649
|
+
);
|
|
16650
|
+
logger.verbose(
|
|
16651
|
+
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
16652
|
+
_callsFinal
|
|
16653
|
+
)}`
|
|
16654
|
+
);
|
|
16655
|
+
return _callsFinal;
|
|
16656
|
+
}
|
|
16657
|
+
/**
|
|
16658
|
+
* @description This function handles harvesting of reward token that is not the same as any of the vault token
|
|
16659
|
+
* i.e. STRK is not part of vault tokens like BTC/ETH
|
|
16660
|
+
* @param params
|
|
16661
|
+
* @returns
|
|
16662
|
+
*/
|
|
16663
|
+
async _handleRewardAndVaultTokenMismatchHarvest(params) {
|
|
16664
|
+
const { acc, claim, token0Info, token1Info, postFeeAmount, poolKey, bounds, maxIterations, priceRatioPrecision } = params;
|
|
16665
|
+
let token0Amt = postFeeAmount;
|
|
16666
|
+
const beneficiary = this.address.address;
|
|
16667
|
+
let harvestCall = null;
|
|
16668
|
+
harvestCall = await this.harvestMismatchEstimateCallFn({
|
|
16669
|
+
postFeeAmount,
|
|
16670
|
+
claim,
|
|
16671
|
+
token0Info,
|
|
16672
|
+
token1Info,
|
|
16673
|
+
acc
|
|
16674
|
+
});
|
|
16675
|
+
if (!harvestCall) {
|
|
16676
|
+
throw new Error("Harvest call not found");
|
|
16677
|
+
}
|
|
16678
|
+
return [harvestCall];
|
|
16679
|
+
}
|
|
16680
|
+
// given an amount (i.e. portion of reward to use to swap to token0), returns info on increasing or decreasing
|
|
16681
|
+
// amount for binary search
|
|
16682
|
+
async harvestMismatchEstimateCallFn(params) {
|
|
16683
|
+
const { postFeeAmount, claim, token0Info, token1Info, acc } = params;
|
|
16684
|
+
let harvestCall = null;
|
|
16685
|
+
const binarySearchCallbackFn = async (mid) => {
|
|
16686
|
+
const rewardPart2 = BigInt(postFeeAmount.toWei()) - mid;
|
|
16687
|
+
const avnuWrapper = new AvnuWrapper();
|
|
16688
|
+
const beneficiary = this.address.address;
|
|
16689
|
+
const quote1 = await avnuWrapper.getQuotes(
|
|
16690
|
+
claim.token.address,
|
|
16691
|
+
token0Info.address.address,
|
|
16692
|
+
mid.toString(),
|
|
16693
|
+
beneficiary
|
|
16694
|
+
);
|
|
16695
|
+
const swapInfo1 = await avnuWrapper.getSwapInfo(
|
|
16696
|
+
quote1,
|
|
16697
|
+
beneficiary,
|
|
16698
|
+
0,
|
|
16699
|
+
beneficiary
|
|
16700
|
+
);
|
|
16701
|
+
const quote2 = await avnuWrapper.getQuotes(
|
|
16702
|
+
claim.token.address,
|
|
16703
|
+
token1Info.address.address,
|
|
16704
|
+
rewardPart2.toString(),
|
|
16705
|
+
beneficiary
|
|
16706
|
+
);
|
|
16707
|
+
const swapInfo2 = await avnuWrapper.getSwapInfo(
|
|
16708
|
+
quote2,
|
|
16709
|
+
beneficiary,
|
|
16710
|
+
0,
|
|
16711
|
+
beneficiary
|
|
16712
|
+
);
|
|
16713
|
+
try {
|
|
16480
16714
|
const calldata = [
|
|
16481
16715
|
claim.rewardsContract.address,
|
|
16482
16716
|
{
|
|
@@ -16485,34 +16719,24 @@ var EkuboCLVault = class _EkuboCLVault extends BaseStrategy {
|
|
|
16485
16719
|
claimee: claim.claim.claimee.address
|
|
16486
16720
|
},
|
|
16487
16721
|
claim.proof.map((p) => num5.getDecimalString(p)),
|
|
16488
|
-
|
|
16722
|
+
swapInfo1,
|
|
16489
16723
|
swapInfo2
|
|
16490
16724
|
];
|
|
16491
|
-
|
|
16492
|
-
|
|
16493
|
-
|
|
16494
|
-
|
|
16495
|
-
);
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
// upper limit is the post fee amount
|
|
16507
|
-
);
|
|
16508
|
-
logger.verbose(
|
|
16509
|
-
`${_EkuboCLVault.name}: harvest => _callsFinal: ${JSON.stringify(
|
|
16510
|
-
_callsFinal
|
|
16511
|
-
)}`
|
|
16512
|
-
);
|
|
16513
|
-
calls.push(..._callsFinal);
|
|
16514
|
-
}
|
|
16515
|
-
return calls;
|
|
16725
|
+
harvestCall = this.contract.populate("harvest", calldata);
|
|
16726
|
+
const gas = await acc.estimateInvokeFee(harvestCall);
|
|
16727
|
+
return "found";
|
|
16728
|
+
} catch (err) {
|
|
16729
|
+
console.error(err);
|
|
16730
|
+
if (err.message.includes("invalid token0 amount")) {
|
|
16731
|
+
return "go_low";
|
|
16732
|
+
} else if (err.message.includes("invalid token1 amount")) {
|
|
16733
|
+
return "go_high";
|
|
16734
|
+
}
|
|
16735
|
+
return "retry";
|
|
16736
|
+
}
|
|
16737
|
+
};
|
|
16738
|
+
await binarySearch(0n, BigInt(postFeeAmount.toWei()), binarySearchCallbackFn);
|
|
16739
|
+
return harvestCall;
|
|
16516
16740
|
}
|
|
16517
16741
|
async getInvestmentFlows() {
|
|
16518
16742
|
const netYield = await this.netAPY();
|
|
@@ -19044,7 +19268,58 @@ function toBigInt(value) {
|
|
|
19044
19268
|
}
|
|
19045
19269
|
|
|
19046
19270
|
// src/strategies/universal-adapters/baseAdapter.ts
|
|
19271
|
+
var APYType = /* @__PURE__ */ ((APYType2) => {
|
|
19272
|
+
APYType2["BASE"] = "base";
|
|
19273
|
+
APYType2["REWARD"] = "reward";
|
|
19274
|
+
APYType2["LST"] = "lst";
|
|
19275
|
+
return APYType2;
|
|
19276
|
+
})(APYType || {});
|
|
19047
19277
|
var BaseAdapter = class extends CacheClass {
|
|
19278
|
+
// readonly config: BaseAdapterConfig;
|
|
19279
|
+
// constructor(config: BaseAdapterConfig) {
|
|
19280
|
+
// super();
|
|
19281
|
+
// this.config = config;
|
|
19282
|
+
// }
|
|
19283
|
+
constructor() {
|
|
19284
|
+
super();
|
|
19285
|
+
}
|
|
19286
|
+
// /**
|
|
19287
|
+
// * Loop through all supported positions and return amount, usd value, remarks and apy for each
|
|
19288
|
+
// */
|
|
19289
|
+
// async getPositions(): Promise<PositionInfo[]> {
|
|
19290
|
+
// const results: PositionInfo[] = [];
|
|
19291
|
+
// for (const supported of this.config.supportedPositions) {
|
|
19292
|
+
// const amount = await this.getPosition(supported);
|
|
19293
|
+
// const usdValue = await this.getUSDValue(supported.asset, amount);
|
|
19294
|
+
// const apy = await this.getAPY(supported);
|
|
19295
|
+
// results.push({ amount, usdValue, apy });
|
|
19296
|
+
// }
|
|
19297
|
+
// return results;
|
|
19298
|
+
// }
|
|
19299
|
+
// /**
|
|
19300
|
+
// * Implemented by child adapters to compute APY for a given supported position
|
|
19301
|
+
// */
|
|
19302
|
+
// protected abstract getAPY(supportedPosition: SupportedPosition): Promise<PositionAPY>;
|
|
19303
|
+
// /**
|
|
19304
|
+
// * Implemented by child adapters to fetch amount for a given supported position
|
|
19305
|
+
// */
|
|
19306
|
+
// protected abstract getPosition(supportedPosition: SupportedPosition): Promise<Web3Number>;
|
|
19307
|
+
// /**
|
|
19308
|
+
// * Implemented by child adapters to calculate maximum deposit positions
|
|
19309
|
+
// * @param amount Optional amount in baseToken to deposit
|
|
19310
|
+
// */
|
|
19311
|
+
// protected abstract maxDeposit(amount?: Web3Number): Promise<PositionInfo[]>;
|
|
19312
|
+
// /**
|
|
19313
|
+
// * Implemented by child adapters to calculate maximum withdraw positions
|
|
19314
|
+
// */
|
|
19315
|
+
// protected abstract maxWithdraw(): Promise<PositionInfo[]>;
|
|
19316
|
+
// /**
|
|
19317
|
+
// * Uses pricer to convert an amount of an asset to USD value
|
|
19318
|
+
// */
|
|
19319
|
+
// protected async getUSDValue(asset: TokenInfo, amount: Web3Number): Promise<number> {
|
|
19320
|
+
// const priceInfo = await this.config.pricer.getPrice(asset.symbol);
|
|
19321
|
+
// return amount.toNumber() * priceInfo.price;
|
|
19322
|
+
// }
|
|
19048
19323
|
constructSimpleLeafData(params, sanitizer = SIMPLE_SANITIZER) {
|
|
19049
19324
|
const { id, target, method, packedArguments } = params;
|
|
19050
19325
|
return {
|
|
@@ -19062,6 +19337,94 @@ var BaseAdapter = class extends CacheClass {
|
|
|
19062
19337
|
]
|
|
19063
19338
|
};
|
|
19064
19339
|
}
|
|
19340
|
+
// /**
|
|
19341
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for deposit leaf construction
|
|
19342
|
+
// */
|
|
19343
|
+
// protected abstract _getDepositLeaf(): {
|
|
19344
|
+
// target: ContractAddr,
|
|
19345
|
+
// method: string,
|
|
19346
|
+
// packedArguments: bigint[],
|
|
19347
|
+
// sanitizer: ContractAddr,
|
|
19348
|
+
// id: string
|
|
19349
|
+
// }[];
|
|
19350
|
+
// /**
|
|
19351
|
+
// * Implementor must provide target/method/packedArguments/sanitizer for withdraw leaf construction
|
|
19352
|
+
// */
|
|
19353
|
+
// protected abstract _getWithdrawLeaf(): {
|
|
19354
|
+
// target: ContractAddr,
|
|
19355
|
+
// method: string,
|
|
19356
|
+
// packedArguments: bigint[],
|
|
19357
|
+
// sanitizer: ContractAddr,
|
|
19358
|
+
// id: string
|
|
19359
|
+
// }[];
|
|
19360
|
+
// /**
|
|
19361
|
+
// * Returns deposit leaf adapter using configured proof id
|
|
19362
|
+
// */
|
|
19363
|
+
// getDepositLeaf(): AdapterLeafType<T1> {
|
|
19364
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
19365
|
+
// const leaves = leafConfigs.map(config => {
|
|
19366
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
19367
|
+
// const leaf = this.constructSimpleLeafData({
|
|
19368
|
+
// id: id,
|
|
19369
|
+
// target,
|
|
19370
|
+
// method,
|
|
19371
|
+
// packedArguments
|
|
19372
|
+
// }, sanitizer);
|
|
19373
|
+
// return leaf;
|
|
19374
|
+
// });
|
|
19375
|
+
// return { leaves, callConstructor: this.getDepositCall.bind(this) as unknown as GenerateCallFn<T1> };
|
|
19376
|
+
// }
|
|
19377
|
+
// /**
|
|
19378
|
+
// * Returns withdraw leaf adapter using configured proof id
|
|
19379
|
+
// */
|
|
19380
|
+
// getWithdrawLeaf(): AdapterLeafType<T2> {
|
|
19381
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
19382
|
+
// const leaves = leafConfigs.map(config => {
|
|
19383
|
+
// const { target, method, packedArguments, sanitizer, id } = config;
|
|
19384
|
+
// const leaf = this.constructSimpleLeafData({
|
|
19385
|
+
// id: id,
|
|
19386
|
+
// target,
|
|
19387
|
+
// method,
|
|
19388
|
+
// packedArguments
|
|
19389
|
+
// }, sanitizer ?? SIMPLE_SANITIZER);
|
|
19390
|
+
// return leaf;
|
|
19391
|
+
// });
|
|
19392
|
+
// return { leaves, callConstructor: this.getWithdrawCall.bind(this) as unknown as GenerateCallFn<T2> };
|
|
19393
|
+
// }
|
|
19394
|
+
// /**
|
|
19395
|
+
// * Default deposit callConstructor: expects params as calldata (bigint[])
|
|
19396
|
+
// */
|
|
19397
|
+
// protected getDepositCall<T1 = bigint[]>(params: T1): ManageCall[] {
|
|
19398
|
+
// const leafConfigs = this._getDepositLeaf();
|
|
19399
|
+
// return leafConfigs.map(config => {
|
|
19400
|
+
// const { target, method, sanitizer } = config;
|
|
19401
|
+
// return {
|
|
19402
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
19403
|
+
// call: {
|
|
19404
|
+
// contractAddress: target,
|
|
19405
|
+
// selector: hash.getSelectorFromName(method),
|
|
19406
|
+
// calldata: params as unknown as bigint[]
|
|
19407
|
+
// }
|
|
19408
|
+
// };
|
|
19409
|
+
// });
|
|
19410
|
+
// }
|
|
19411
|
+
// /**
|
|
19412
|
+
// * Default withdraw callConstructor: expects params as calldata (bigint[])
|
|
19413
|
+
// */
|
|
19414
|
+
// protected getWithdrawCall<T2 = bigint[]>(params: T2): ManageCall[] {
|
|
19415
|
+
// const leafConfigs = this._getWithdrawLeaf();
|
|
19416
|
+
// return leafConfigs.map(config => {
|
|
19417
|
+
// const { target, method, sanitizer } = config;
|
|
19418
|
+
// return {
|
|
19419
|
+
// sanitizer: sanitizer ?? SIMPLE_SANITIZER,
|
|
19420
|
+
// call: {
|
|
19421
|
+
// contractAddress: target,
|
|
19422
|
+
// selector: hash.getSelectorFromName(method),
|
|
19423
|
+
// calldata: params as unknown as bigint[]
|
|
19424
|
+
// }
|
|
19425
|
+
// };
|
|
19426
|
+
// });
|
|
19427
|
+
// }
|
|
19065
19428
|
};
|
|
19066
19429
|
|
|
19067
19430
|
// src/strategies/universal-adapters/common-adapter.ts
|
|
@@ -26664,7 +27027,20 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26664
27027
|
}
|
|
26665
27028
|
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
26666
27029
|
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap debt_cap: ${output.debt_cap.toString()}`);
|
|
26667
|
-
|
|
27030
|
+
if (!isV2) {
|
|
27031
|
+
throw new Error("getDebtCap is not supported for v1");
|
|
27032
|
+
}
|
|
27033
|
+
const currentDebt = await this.getCurrentDebtUtilisationAmount(config);
|
|
27034
|
+
logger.verbose(`${this.config.debt.symbol}::VesuAdapter::getDebtCap currentDebt: ${currentDebt.toString()}`);
|
|
27035
|
+
return Web3Number.fromWei(output.debt_cap.toString(), this.config.debt.decimals).minus(currentDebt);
|
|
27036
|
+
}
|
|
27037
|
+
async getCurrentDebtUtilisationAmount(config) {
|
|
27038
|
+
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
27039
|
+
if (!isV2) {
|
|
27040
|
+
throw new Error("getCurrentDebtUtilisationAmount is not supported for v1");
|
|
27041
|
+
}
|
|
27042
|
+
const output = await contract.call("pairs", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27043
|
+
return new Web3Number((Number(output.total_nominal_debt) / 1e18).toFixed(9), this.config.debt.decimals);
|
|
26668
27044
|
}
|
|
26669
27045
|
async getMaxBorrowableByInterestRate(config, asset, maxBorrowAPY) {
|
|
26670
27046
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
@@ -26697,16 +27073,17 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26697
27073
|
const assetConfig = isV2 ? _assetConfig : _assetConfig["0"];
|
|
26698
27074
|
const timeDelta = assetConfig.last_updated;
|
|
26699
27075
|
const lastFullUtilizationRate = assetConfig.last_full_utilization_rate;
|
|
26700
|
-
const
|
|
27076
|
+
const currentDebt = new Web3Number((Number(assetConfig.total_nominal_debt) / 1e18).toFixed(9), asset.decimals);
|
|
27077
|
+
const totalSupply = currentDebt.plus(Web3Number.fromWei(assetConfig.reserve, asset.decimals));
|
|
26701
27078
|
const ratePerSecond = BigInt(Math.round(maxBorrowAPY / 365 / 24 / 60 / 60 * Number(SCALE)));
|
|
26702
27079
|
const maxUtilisation = this.getMaxUtilizationGivenRatePerSecond(interestRateConfig, ratePerSecond, timeDelta, lastFullUtilizationRate);
|
|
26703
27080
|
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate maxUtilisation: ${Number(maxUtilisation) / 1e18}, totalSupply: ${totalSupply.toString()}`);
|
|
26704
27081
|
const maxDebtToHave = totalSupply.multipliedBy(Number(maxUtilisation) / 1e18);
|
|
26705
|
-
|
|
27082
|
+
logger.verbose(`${asset.symbol}::VesuAdapter::getMaxBorrowableByInterestRate currentDebt: ${currentDebt.toString()}, maxDebtToHave: ${maxDebtToHave.toString()}`);
|
|
26706
27083
|
return maxDebtToHave.minus(currentDebt);
|
|
26707
27084
|
}
|
|
26708
|
-
async getLTVConfig(config) {
|
|
26709
|
-
const CACHE_KEY =
|
|
27085
|
+
async getLTVConfig(config, blockNumber = "latest") {
|
|
27086
|
+
const CACHE_KEY = `ltv_config_${blockNumber}`;
|
|
26710
27087
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26711
27088
|
if (cacheData) {
|
|
26712
27089
|
return cacheData;
|
|
@@ -26714,10 +27091,10 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26714
27091
|
const { contract, isV2 } = await this.getVesuSingletonContract(config, this.config.poolId);
|
|
26715
27092
|
let ltv = 0;
|
|
26716
27093
|
if (isV2) {
|
|
26717
|
-
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27094
|
+
const output = await contract.call("pair_config", [this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
26718
27095
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26719
27096
|
} else {
|
|
26720
|
-
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address]);
|
|
27097
|
+
const output = await contract.call("ltv_config", [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address], { blockIdentifier: blockNumber });
|
|
26721
27098
|
ltv = Number(output.max_ltv) / 1e18;
|
|
26722
27099
|
}
|
|
26723
27100
|
if (ltv == 0) {
|
|
@@ -26726,11 +27103,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26726
27103
|
this.setCache(CACHE_KEY, ltv, 3e5);
|
|
26727
27104
|
return this.getCache(CACHE_KEY);
|
|
26728
27105
|
}
|
|
26729
|
-
async getPositions(config) {
|
|
27106
|
+
async getPositions(config, blockNumber = "latest") {
|
|
26730
27107
|
if (!this.pricer) {
|
|
26731
27108
|
throw new Error("Pricer is not initialized");
|
|
26732
27109
|
}
|
|
26733
|
-
const CACHE_KEY =
|
|
27110
|
+
const CACHE_KEY = `positions_${blockNumber}`;
|
|
26734
27111
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26735
27112
|
if (cacheData) {
|
|
26736
27113
|
return cacheData;
|
|
@@ -26742,7 +27119,8 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26742
27119
|
this.config.collateral.address.address,
|
|
26743
27120
|
this.config.debt.address.address,
|
|
26744
27121
|
this.config.vaultAllocator.address
|
|
26745
|
-
]);
|
|
27122
|
+
], { blockIdentifier: blockNumber });
|
|
27123
|
+
console.log(output);
|
|
26746
27124
|
const token1Price = await this.pricer.getPrice(this.config.collateral.symbol);
|
|
26747
27125
|
const token2Price = await this.pricer.getPrice(this.config.debt.symbol);
|
|
26748
27126
|
logger.verbose(`VesuAdapter::getPositions token1Price: ${token1Price.price}, token2Price: ${token2Price.price}`);
|
|
@@ -26762,11 +27140,11 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26762
27140
|
this.setCache(CACHE_KEY, value, 6e4);
|
|
26763
27141
|
return value;
|
|
26764
27142
|
}
|
|
26765
|
-
async getCollateralization(config) {
|
|
27143
|
+
async getCollateralization(config, blockNumber = "latest") {
|
|
26766
27144
|
if (!this.pricer) {
|
|
26767
27145
|
throw new Error("Pricer is not initialized");
|
|
26768
27146
|
}
|
|
26769
|
-
const CACHE_KEY =
|
|
27147
|
+
const CACHE_KEY = `collateralization_${blockNumber}`;
|
|
26770
27148
|
const cacheData = this.getCache(CACHE_KEY);
|
|
26771
27149
|
if (cacheData) {
|
|
26772
27150
|
return cacheData;
|
|
@@ -26778,7 +27156,7 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26778
27156
|
this.config.collateral.address.address,
|
|
26779
27157
|
this.config.debt.address.address,
|
|
26780
27158
|
this.config.vaultAllocator.address
|
|
26781
|
-
]);
|
|
27159
|
+
], { blockIdentifier: blockNumber });
|
|
26782
27160
|
const collateralAmount = Web3Number.fromWei(output["1"].toString(), 18);
|
|
26783
27161
|
const debtAmount = Web3Number.fromWei(output["2"].toString(), 18);
|
|
26784
27162
|
const value = [{
|
|
@@ -26815,9 +27193,9 @@ var VesuAdapter = class _VesuAdapter extends BaseAdapter {
|
|
|
26815
27193
|
ltv
|
|
26816
27194
|
};
|
|
26817
27195
|
}
|
|
26818
|
-
async getHealthFactor() {
|
|
26819
|
-
const ltv = await this.getLTVConfig(this.networkConfig);
|
|
26820
|
-
const collateralisation = await this.getCollateralization(this.networkConfig);
|
|
27196
|
+
async getHealthFactor(blockNumber = "latest") {
|
|
27197
|
+
const ltv = await this.getLTVConfig(this.networkConfig, blockNumber);
|
|
27198
|
+
const collateralisation = await this.getCollateralization(this.networkConfig, blockNumber);
|
|
26821
27199
|
return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
|
|
26822
27200
|
}
|
|
26823
27201
|
static async getVesuPools(retry = 0) {
|
|
@@ -29479,11 +29857,11 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29479
29857
|
vesuAdapter2.networkConfig = this.config;
|
|
29480
29858
|
return [vesuAdapter1, vesuAdapter2];
|
|
29481
29859
|
}
|
|
29482
|
-
async getVesuPositions() {
|
|
29860
|
+
async getVesuPositions(blockNumber = "latest") {
|
|
29483
29861
|
const adapters = this.getVesuAdapters();
|
|
29484
29862
|
const positions = [];
|
|
29485
29863
|
for (const adapter of adapters) {
|
|
29486
|
-
positions.push(...await adapter.getPositions(this.config));
|
|
29864
|
+
positions.push(...await adapter.getPositions(this.config, blockNumber));
|
|
29487
29865
|
}
|
|
29488
29866
|
return positions;
|
|
29489
29867
|
}
|
|
@@ -29552,8 +29930,8 @@ var UniversalStrategy = class _UniversalStrategy extends BaseStrategy {
|
|
|
29552
29930
|
async getLSTAPR(address) {
|
|
29553
29931
|
return 0;
|
|
29554
29932
|
}
|
|
29555
|
-
async getVesuHealthFactors() {
|
|
29556
|
-
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor()));
|
|
29933
|
+
async getVesuHealthFactors(blockNumber = "latest") {
|
|
29934
|
+
return await Promise.all(this.getVesuAdapters().map((v) => v.getHealthFactor(blockNumber)));
|
|
29557
29935
|
}
|
|
29558
29936
|
async computeRebalanceConditionAndReturnCalls() {
|
|
29559
29937
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -30149,6 +30527,42 @@ var UniversalStrategies = [
|
|
|
30149
30527
|
|
|
30150
30528
|
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30151
30529
|
import { Contract as Contract10, uint256 as uint2569 } from "starknet";
|
|
30530
|
+
|
|
30531
|
+
// src/utils/health-factor-math.ts
|
|
30532
|
+
var HealthFactorMath = class {
|
|
30533
|
+
static getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
30534
|
+
const numerator = debtAmount.multipliedBy(debtPrice).multipliedBy(targetHF);
|
|
30535
|
+
const denominator = collateralPrice * maxLTV;
|
|
30536
|
+
const collateralAmount = numerator.dividedBy(denominator);
|
|
30537
|
+
const netCollateral = new Web3Number(collateralAmount.toString(), collateralTokenInfo.decimals);
|
|
30538
|
+
return netCollateral;
|
|
30539
|
+
}
|
|
30540
|
+
static getMinCollateralRequiredOnLooping(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo) {
|
|
30541
|
+
const netCollateral = this.getCollateralRequired(debtAmount, debtPrice, targetHF, maxLTV, collateralPrice, collateralTokenInfo);
|
|
30542
|
+
const collateralFromDebt = new Web3Number(debtAmount.multipliedBy(debtPrice).dividedBy(collateralPrice).toString(), collateralTokenInfo.decimals);
|
|
30543
|
+
return netCollateral.minus(collateralFromDebt);
|
|
30544
|
+
}
|
|
30545
|
+
static getHealthFactor(collateralAmount, collateralPrice, maxLTV, debtAmount, debtPrice) {
|
|
30546
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30547
|
+
const denominator = debtAmount.multipliedBy(debtPrice);
|
|
30548
|
+
const healthFactor = numerator.dividedBy(denominator);
|
|
30549
|
+
return healthFactor.toNumber();
|
|
30550
|
+
}
|
|
30551
|
+
static getMaxDebtAmountOnLooping(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
30552
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30553
|
+
const denominator = targetHF - maxLTV;
|
|
30554
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
30555
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
30556
|
+
}
|
|
30557
|
+
static getMaxDebtAmount(collateralAmount, collateralPrice, maxLTV, targetHF, debtPrice, debtTokenInfo) {
|
|
30558
|
+
const numerator = collateralAmount.multipliedBy(collateralPrice).multipliedBy(maxLTV);
|
|
30559
|
+
const denominator = targetHF * debtPrice;
|
|
30560
|
+
const debtAmount = numerator.dividedBy(denominator);
|
|
30561
|
+
return new Web3Number(debtAmount.toString(), debtTokenInfo.decimals);
|
|
30562
|
+
}
|
|
30563
|
+
};
|
|
30564
|
+
|
|
30565
|
+
// src/strategies/universal-lst-muliplier-strategy.tsx
|
|
30152
30566
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
30153
30567
|
var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy extends UniversalStrategy {
|
|
30154
30568
|
constructor(config, pricer, metadata) {
|
|
@@ -30163,15 +30577,14 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30163
30577
|
}
|
|
30164
30578
|
}
|
|
30165
30579
|
asset() {
|
|
30166
|
-
|
|
30167
|
-
return vesuAdapter1.config.collateral;
|
|
30580
|
+
return this.getVesuSameTokenAdapter().config.collateral;
|
|
30168
30581
|
}
|
|
30169
30582
|
getTag() {
|
|
30170
30583
|
return `${_UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
30171
30584
|
}
|
|
30172
30585
|
// Vesu adapter with LST and base token match
|
|
30173
30586
|
getVesuSameTokenAdapter() {
|
|
30174
|
-
const baseAdapter = this.getAdapter("
|
|
30587
|
+
const baseAdapter = this.getAdapter(getVesuLegId("vesu_leg1" /* VESU_LEG1 */, this.metadata.additionalInfo.underlyingToken.symbol));
|
|
30175
30588
|
baseAdapter.networkConfig = this.config;
|
|
30176
30589
|
baseAdapter.pricer = this.pricer;
|
|
30177
30590
|
return baseAdapter;
|
|
@@ -30219,20 +30632,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30219
30632
|
return price;
|
|
30220
30633
|
}
|
|
30221
30634
|
async getAvnuSwapMultiplyCall(params) {
|
|
30222
|
-
|
|
30223
|
-
|
|
30224
|
-
|
|
30225
|
-
|
|
30226
|
-
|
|
30635
|
+
assert(params.isDeposit, "Only deposit is supported in getAvnuSwapMultiplyCall");
|
|
30636
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount({ isAPYComputation: false });
|
|
30637
|
+
const allVesuAdapters = this.getVesuAdapters();
|
|
30638
|
+
let remainingAmount = params.leg1DepositAmount;
|
|
30639
|
+
const lstExRate = await this.getLSTExchangeRate();
|
|
30640
|
+
const baseAssetPrice = await this.pricer.getPrice(this.getLSTUnderlyingTokenInfo().symbol);
|
|
30641
|
+
const lstPrice = baseAssetPrice.price * lstExRate;
|
|
30642
|
+
for (let i = 0; i < maxBorrowableAmounts.maxBorrowables.length; i++) {
|
|
30643
|
+
const maxBorrowable = maxBorrowableAmounts.maxBorrowables[i];
|
|
30644
|
+
const vesuAdapter = allVesuAdapters.find((adapter) => adapter.config.debt.address.eq(maxBorrowable.borrowableAsset.address));
|
|
30645
|
+
if (!vesuAdapter) {
|
|
30646
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: vesuAdapter not found for borrowable asset: ${maxBorrowable.borrowableAsset.symbol}`);
|
|
30647
|
+
}
|
|
30648
|
+
const maxLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30649
|
+
const debtPrice = await this.pricer.getPrice(maxBorrowable.borrowableAsset.symbol);
|
|
30650
|
+
const maxAmountToDeposit = HealthFactorMath.getMinCollateralRequiredOnLooping(
|
|
30651
|
+
maxBorrowable.amount,
|
|
30652
|
+
debtPrice.price,
|
|
30653
|
+
this.metadata.additionalInfo.targetHealthFactor,
|
|
30654
|
+
maxLTV,
|
|
30655
|
+
lstPrice,
|
|
30656
|
+
this.asset()
|
|
30657
|
+
);
|
|
30658
|
+
const amountToDeposit = remainingAmount.minimum(maxAmountToDeposit);
|
|
30659
|
+
logger.verbose(`${this.getTag()}::getAvnuSwapMultiplyCall::${vesuAdapter.config.debt.symbol}:: remainingAmount: ${remainingAmount}, amountToDeposit: ${amountToDeposit}, depositAmount: ${amountToDeposit}, maxBorrowable: ${maxBorrowable.amount}`);
|
|
30660
|
+
const call = await this._getAvnuDepositSwapLegCall({
|
|
30661
|
+
isDeposit: params.isDeposit,
|
|
30662
|
+
// adjust decimals of debt asset
|
|
30663
|
+
leg1DepositAmount: amountToDeposit,
|
|
30664
|
+
minHF: 1.1,
|
|
30665
|
+
// undo
|
|
30666
|
+
vesuAdapter
|
|
30667
|
+
});
|
|
30668
|
+
remainingAmount = remainingAmount.minus(amountToDeposit);
|
|
30669
|
+
return { call, vesuAdapter };
|
|
30670
|
+
}
|
|
30671
|
+
throw new Error(`${this.getTag()}::getAvnuSwapMultiplyCall: no calls found`);
|
|
30227
30672
|
}
|
|
30228
30673
|
async _getAvnuDepositSwapLegCall(params) {
|
|
30674
|
+
const { vesuAdapter } = params;
|
|
30229
30675
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall params: ${JSON.stringify(params)}`);
|
|
30230
30676
|
assert(params.isDeposit, "Only deposit is supported in _getAvnuDepositSwapLegCall");
|
|
30231
|
-
const
|
|
30232
|
-
const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
30677
|
+
const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
30233
30678
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
30234
|
-
const existingPositions = await
|
|
30235
|
-
const collateralisation = await
|
|
30679
|
+
const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
30680
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30236
30681
|
const existingCollateralInfo = existingPositions[0];
|
|
30237
30682
|
const existingDebtInfo = existingPositions[1];
|
|
30238
30683
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
@@ -30240,11 +30685,40 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30240
30685
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30241
30686
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30242
30687
|
logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30688
|
+
const debtTokenInfo = vesuAdapter.config.debt;
|
|
30689
|
+
let newDepositAmount = params.leg1DepositAmount;
|
|
30243
30690
|
const totalCollateral = existingCollateralInfo.amount.plus(params.leg1DepositAmount);
|
|
30244
30691
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalCollateral: ${totalCollateral}`);
|
|
30245
|
-
const totalDebtAmount =
|
|
30246
|
-
|
|
30247
|
-
|
|
30692
|
+
const totalDebtAmount = new Web3Number(
|
|
30693
|
+
totalCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(debtPrice).dividedBy(params.minHF).toString(),
|
|
30694
|
+
debtTokenInfo.decimals
|
|
30695
|
+
);
|
|
30696
|
+
let debtAmount = totalDebtAmount.minus(existingDebtInfo.amount);
|
|
30697
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall totalDebtAmount: ${totalDebtAmount}, initial computed debt: ${debtAmount}`);
|
|
30698
|
+
const maxBorrowable = await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, false);
|
|
30699
|
+
if (debtAmount.gt(0) && maxBorrowable.amount.eq(0)) {
|
|
30700
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall maxBorrowable is 0, skipping`);
|
|
30701
|
+
return void 0;
|
|
30702
|
+
} else if (debtAmount.gt(0) && maxBorrowable.amount.gt(0)) {
|
|
30703
|
+
debtAmount = maxBorrowable.amount.minimum(debtAmount);
|
|
30704
|
+
const newDebtUSDValue = debtAmount.multipliedBy(debtPrice);
|
|
30705
|
+
const totalCollateralRequired = HealthFactorMath.getCollateralRequired(
|
|
30706
|
+
debtAmount.plus(existingDebtInfo.amount),
|
|
30707
|
+
debtPrice,
|
|
30708
|
+
params.minHF,
|
|
30709
|
+
legLTV,
|
|
30710
|
+
collateralPrice,
|
|
30711
|
+
this.asset()
|
|
30712
|
+
);
|
|
30713
|
+
newDepositAmount = totalCollateralRequired.minus(existingCollateralInfo.amount);
|
|
30714
|
+
if (newDepositAmount.lt(0)) {
|
|
30715
|
+
throw new Error(`${this.getTag()}::_getAvnuDepositSwapLegCall newDepositAmount is less than 0, newDepositAmount: ${newDepositAmount}, totalCollateralRequired: ${totalCollateralRequired}, existingCollateralInfo.amount: ${existingCollateralInfo.amount}`);
|
|
30716
|
+
}
|
|
30717
|
+
if (newDebtUSDValue.toNumber() < 100) {
|
|
30718
|
+
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newDebtUSDValue is less than 100, skipping`);
|
|
30719
|
+
return void 0;
|
|
30720
|
+
}
|
|
30721
|
+
}
|
|
30248
30722
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
30249
30723
|
if (debtAmount.lt(0)) {
|
|
30250
30724
|
const lstDEXPrice = await this.getLSTDexPrice();
|
|
@@ -30256,32 +30730,34 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30256
30730
|
assert(calls.length == 1, `Expected 1 call for unwind, got ${calls.length}`);
|
|
30257
30731
|
return calls[0];
|
|
30258
30732
|
}
|
|
30733
|
+
console.log(`debtAmount`, debtAmount.toWei(), params.leg1DepositAmount.toWei());
|
|
30259
30734
|
const STEP0 = "approve_token1" /* APPROVE_TOKEN1 */;
|
|
30260
30735
|
const manage0Info = this.getProofs(STEP0);
|
|
30261
30736
|
const manageCall0 = manage0Info.callConstructor({
|
|
30262
|
-
amount:
|
|
30737
|
+
amount: newDepositAmount
|
|
30263
30738
|
});
|
|
30264
|
-
const STEP1 = "vesu_leg1" /* VESU_LEG1
|
|
30739
|
+
const STEP1 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30265
30740
|
const manage1Info = this.getProofs(STEP1);
|
|
30266
30741
|
const manageCall1 = manage1Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30267
|
-
collateralAmount:
|
|
30742
|
+
collateralAmount: newDepositAmount,
|
|
30268
30743
|
isAddCollateral: params.isDeposit,
|
|
30269
30744
|
debtAmount,
|
|
30270
30745
|
isBorrow: params.isDeposit
|
|
30271
30746
|
}));
|
|
30747
|
+
console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
30272
30748
|
const proofIds = [STEP0, STEP1];
|
|
30273
30749
|
const manageCalls = [manageCall0, manageCall1];
|
|
30274
30750
|
if (debtAmount.gt(0)) {
|
|
30275
|
-
const STEP2 = "
|
|
30751
|
+
const STEP2 = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30276
30752
|
const manage2Info = this.getProofs(STEP2);
|
|
30277
30753
|
const manageCall2 = manage2Info.callConstructor({
|
|
30278
30754
|
amount: debtAmount
|
|
30279
30755
|
});
|
|
30280
|
-
const
|
|
30756
|
+
const debtTokenInfo2 = vesuAdapter.config.debt;
|
|
30281
30757
|
const lstTokenInfo = this.asset();
|
|
30282
30758
|
const avnuModule = new AvnuWrapper();
|
|
30283
30759
|
const quote = await avnuModule.getQuotes(
|
|
30284
|
-
|
|
30760
|
+
debtTokenInfo2.address.address,
|
|
30285
30761
|
lstTokenInfo.address.address,
|
|
30286
30762
|
debtAmount.toWei(),
|
|
30287
30763
|
this.metadata.additionalInfo.vaultAllocator.address
|
|
@@ -30297,7 +30773,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30297
30773
|
minAmountWei
|
|
30298
30774
|
);
|
|
30299
30775
|
logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall swapInfo: ${JSON.stringify(swapInfo)}`);
|
|
30300
|
-
const STEP3 = "
|
|
30776
|
+
const STEP3 = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, vesuAdapter.config.debt.symbol);
|
|
30301
30777
|
const manage3Info = this.getProofs(STEP3);
|
|
30302
30778
|
const manageCall3 = manage3Info.callConstructor({
|
|
30303
30779
|
props: swapInfo
|
|
@@ -30315,7 +30791,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30315
30791
|
const manageCall4 = manage4Info.callConstructor({
|
|
30316
30792
|
amount: minAmount
|
|
30317
30793
|
});
|
|
30318
|
-
const STEP5 = "vesu_leg1" /* VESU_LEG1
|
|
30794
|
+
const STEP5 = getVesuLegId("vesu_leg1" /* VESU_LEG1 */, vesuAdapter.config.debt.symbol);
|
|
30319
30795
|
const manage5Info = this.getProofs(STEP5);
|
|
30320
30796
|
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
30321
30797
|
collateralAmount: minAmount,
|
|
@@ -30332,28 +30808,41 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30332
30808
|
}
|
|
30333
30809
|
// todo unwind or not deposit when the yield is bad.
|
|
30334
30810
|
async getLSTMultiplierRebalanceCall() {
|
|
30335
|
-
|
|
30336
|
-
|
|
30811
|
+
let shouldRebalance = false;
|
|
30812
|
+
const calls = [];
|
|
30813
|
+
const allVesuAdapters = this.getVesuAdapters().filter((vesuAdapter) => vesuAdapter.config.debt.symbol === "LBTC");
|
|
30814
|
+
for (const vesuAdapter of allVesuAdapters) {
|
|
30815
|
+
const call = await this._getLSTMultiplierRebalanceCall(vesuAdapter);
|
|
30816
|
+
if (call.shouldRebalance && call.manageCall) {
|
|
30817
|
+
shouldRebalance = true;
|
|
30818
|
+
calls.push({ vesuAdapter, manageCall: call.manageCall });
|
|
30819
|
+
}
|
|
30820
|
+
}
|
|
30821
|
+
return { shouldRebalance, manageCalls: calls };
|
|
30822
|
+
}
|
|
30823
|
+
async _getLSTMultiplierRebalanceCall(vesuAdapter) {
|
|
30824
|
+
const positions = await vesuAdapter.getPositions(this.config);
|
|
30825
|
+
assert(positions.length == 2, "Rebalance call is only supported for 2 positions");
|
|
30337
30826
|
const existingCollateralInfo = positions[0];
|
|
30338
30827
|
const existingDebtInfo = positions[1];
|
|
30339
|
-
const unusedBalance =
|
|
30340
|
-
const
|
|
30341
|
-
const
|
|
30342
|
-
|
|
30343
|
-
const collateralisation = await vesuAdapter1.getCollateralization(this.config);
|
|
30344
|
-
logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
30828
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
30829
|
+
const healthFactor = await vesuAdapter.getHealthFactor();
|
|
30830
|
+
const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
30831
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
30345
30832
|
existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
30346
30833
|
const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
30347
30834
|
const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
30348
30835
|
logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
30836
|
+
logger.debug(`${this.getTag()}::getVesuMultiplyCall healthFactor: ${healthFactor}`);
|
|
30349
30837
|
const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
30350
30838
|
const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
30351
|
-
if (isHFTooLow || isHFTooHigh) {
|
|
30839
|
+
if (isHFTooLow || isHFTooHigh || 1) {
|
|
30352
30840
|
const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
30353
30841
|
isDeposit: true,
|
|
30354
30842
|
leg1DepositAmount: unusedBalance.amount,
|
|
30355
|
-
minHF: 1.02
|
|
30843
|
+
minHF: 1.02,
|
|
30356
30844
|
// todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
30845
|
+
vesuAdapter
|
|
30357
30846
|
});
|
|
30358
30847
|
return { shouldRebalance: true, manageCall };
|
|
30359
30848
|
} else {
|
|
@@ -30386,7 +30875,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30386
30875
|
async _getMinOutputAmountLSTBuy(amountInUnderlying) {
|
|
30387
30876
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
30388
30877
|
const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979);
|
|
30389
|
-
return minOutputAmount;
|
|
30878
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
30390
30879
|
}
|
|
30391
30880
|
async _getMinOutputAmountLSTSell(amountInLST) {
|
|
30392
30881
|
const lstTruePrice = await this.getLSTExchangeRate();
|
|
@@ -30443,21 +30932,52 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30443
30932
|
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
30444
30933
|
return vesuAdapter1.config.debt;
|
|
30445
30934
|
}
|
|
30446
|
-
async getMaxBorrowableAmount() {
|
|
30935
|
+
async getMaxBorrowableAmount(params = { isAPYComputation: false }) {
|
|
30447
30936
|
const vesuAdapters = this.getVesuAdapters();
|
|
30448
30937
|
let netMaxBorrowableAmount = Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals);
|
|
30449
30938
|
const maxBorrowables = [];
|
|
30450
|
-
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30451
|
-
const maxInterestRate = lstAPY * 0.8;
|
|
30452
30939
|
for (const vesuAdapter of vesuAdapters) {
|
|
30453
|
-
|
|
30454
|
-
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
30455
|
-
maxBorrowables.push({ amount: maxBorrowableAmount.minimum(debtCap), borrowableAsset: vesuAdapter.config.debt });
|
|
30940
|
+
maxBorrowables.push(await this.getMaxBorrowableAmountByVesuAdapter(vesuAdapter, params.isAPYComputation));
|
|
30456
30941
|
}
|
|
30457
30942
|
maxBorrowables.sort((a, b) => b.amount.toNumber() - a.amount.toNumber());
|
|
30458
30943
|
netMaxBorrowableAmount = maxBorrowables.reduce((acc, curr) => acc.plus(curr.amount), Web3Number.fromWei("0", this.getLSTUnderlyingTokenInfo().decimals));
|
|
30459
30944
|
return { netMaxBorrowableAmount, maxBorrowables };
|
|
30460
30945
|
}
|
|
30946
|
+
// recursively, using binary search computes max swappable.
|
|
30947
|
+
// @dev assumes 1 token of from == 1 token of to
|
|
30948
|
+
async getMaxSwappableWithMaxSlippage(fromToken, toToken, maxSlippage, maxAmount) {
|
|
30949
|
+
const output = await findMaxInputWithSlippage({
|
|
30950
|
+
apiGetOutput: async (inputAmount) => {
|
|
30951
|
+
const ekuboQuoter = new EkuboQuoter(this.config);
|
|
30952
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
30953
|
+
const quote = await ekuboQuoter.getQuote(fromToken.address.address, toToken.address.address, new Web3Number(inputAmount.toFixed(9), fromToken.decimals));
|
|
30954
|
+
return Web3Number.fromWei(quote.total_calculated.toString(), toToken.decimals).toNumber();
|
|
30955
|
+
},
|
|
30956
|
+
maxInput: maxAmount.toNumber(),
|
|
30957
|
+
maxSlippagePercent: maxSlippage,
|
|
30958
|
+
tolerance: 1e-3,
|
|
30959
|
+
referenceRate: 1
|
|
30960
|
+
});
|
|
30961
|
+
return new Web3Number(output.optimalInput, fromToken.decimals);
|
|
30962
|
+
}
|
|
30963
|
+
async getMaxBorrowableAmountByVesuAdapter(vesuAdapter, isAPYComputation) {
|
|
30964
|
+
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30965
|
+
const maxInterestRate = lstAPY * 0.8;
|
|
30966
|
+
const maxBorrowableAmount = await vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxInterestRate);
|
|
30967
|
+
const debtCap = await vesuAdapter.getDebtCap(this.config);
|
|
30968
|
+
const maxBorrowable = maxBorrowableAmount.minimum(debtCap).multipliedBy(0.999);
|
|
30969
|
+
if (vesuAdapter.config.debt.address.eq(this.getLSTUnderlyingTokenInfo().address) || isAPYComputation) {
|
|
30970
|
+
return { amount: maxBorrowable, dexSwappableAmount: maxBorrowable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
30971
|
+
}
|
|
30972
|
+
try {
|
|
30973
|
+
const maxSwappable = await this.getMaxSwappableWithMaxSlippage(vesuAdapter.config.debt, this.getLSTUnderlyingTokenInfo(), 2e-4, maxBorrowable);
|
|
30974
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
30975
|
+
} catch (error) {
|
|
30976
|
+
logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
|
|
30977
|
+
const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
|
|
30978
|
+
return { amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt };
|
|
30979
|
+
}
|
|
30980
|
+
}
|
|
30461
30981
|
// todo how much to unwind to get back healthy APY zone again
|
|
30462
30982
|
// if net APY < LST APR + 0.5%, we need to unwind to get back to LST APR + 1% atleast or 0 vesu position
|
|
30463
30983
|
// For xSTRK, simply deposit in Vesu if looping is not viable
|
|
@@ -30481,7 +31001,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30481
31001
|
// todo undo this
|
|
30482
31002
|
async netAPY() {
|
|
30483
31003
|
const unusedBalance = await this.getUnusedBalance();
|
|
30484
|
-
const maxNewDeposits = await this.maxNewDeposits();
|
|
31004
|
+
const maxNewDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
30485
31005
|
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
30486
31006
|
if (maxNewDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
30487
31007
|
logger.verbose(`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`);
|
|
@@ -30498,8 +31018,8 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30498
31018
|
return output;
|
|
30499
31019
|
}
|
|
30500
31020
|
}
|
|
30501
|
-
async maxNewDeposits() {
|
|
30502
|
-
const maxBorrowableAmounts = await this.getMaxBorrowableAmount();
|
|
31021
|
+
async maxNewDeposits(params = { isAPYComputation: false }) {
|
|
31022
|
+
const maxBorrowableAmounts = await this.getMaxBorrowableAmount(params);
|
|
30503
31023
|
let ltv = void 0;
|
|
30504
31024
|
for (let adapter of this.getVesuAdapters()) {
|
|
30505
31025
|
const maxBorrowableAmount = maxBorrowableAmounts.maxBorrowables.find((b) => b.borrowableAsset.address.eq(adapter.config.debt.address))?.amount;
|
|
@@ -30602,7 +31122,7 @@ var UniversalLstMultiplierStrategy = class _UniversalLstMultiplierStrategy exten
|
|
|
30602
31122
|
const manageCall2 = manage2Info.callConstructor({
|
|
30603
31123
|
delegation: true
|
|
30604
31124
|
});
|
|
30605
|
-
const STEP3_ID = "multiply_vesu" /* MULTIPLY_VESU
|
|
31125
|
+
const STEP3_ID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, vesuAdapter1.config.debt.symbol);
|
|
30606
31126
|
const manage3Info = this.getProofs(STEP3_ID);
|
|
30607
31127
|
const multiplyParams = params.isIncrease ? {
|
|
30608
31128
|
isIncrease: true,
|
|
@@ -30668,6 +31188,7 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
|
|
|
30668
31188
|
/* @__PURE__ */ jsxs4("p", { style: { fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }, children: [
|
|
30669
31189
|
"This vault uses Vesu for lending and borrowing. The oracle used by this pool is a ",
|
|
30670
31190
|
highlightTextWithLinks("conversion rate oracle", [{ highlight: "conversion rate oracle", link: "https://docs.pragma.build/starknet/development#conversion-rate" }]),
|
|
31191
|
+
" ",
|
|
30671
31192
|
"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."
|
|
30672
31193
|
] }),
|
|
30673
31194
|
/* @__PURE__ */ jsx5("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ jsxs4("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
|
|
@@ -30678,17 +31199,19 @@ function VaultDescription(lstSymbol, underlyingSymbol) {
|
|
|
30678
31199
|
] }) }),
|
|
30679
31200
|
/* @__PURE__ */ jsx5("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ jsxs4("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
|
|
30680
31201
|
/* @__PURE__ */ jsx5("strong", { children: "Debt limits:" }),
|
|
30681
|
-
" 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."
|
|
30682
|
-
] }) }),
|
|
30683
|
-
/* @__PURE__ */ jsx5("div", { style: { backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }, children: /* @__PURE__ */ jsxs4("p", { style: { fontSize: "13px", color: "#ccc" }, children: [
|
|
30684
|
-
/* @__PURE__ */ jsx5("strong", { children: "APY assumptions:" }),
|
|
30685
|
-
" 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."
|
|
31202
|
+
" 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."
|
|
30686
31203
|
] }) })
|
|
30687
31204
|
] });
|
|
30688
31205
|
}
|
|
30689
31206
|
function getDescription2(tokenSymbol, underlyingSymbol) {
|
|
30690
31207
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
30691
31208
|
}
|
|
31209
|
+
function getAvnuManageIDs(baseID, debtTokenSymbol) {
|
|
31210
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31211
|
+
}
|
|
31212
|
+
function getVesuLegId(baseID, debtTokenSymbol) {
|
|
31213
|
+
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
31214
|
+
}
|
|
30692
31215
|
function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
30693
31216
|
vaultSettings.leafAdapters = [];
|
|
30694
31217
|
const lstToken = Global.getDefaultTokens().find((token) => token.symbol === lstSymbol);
|
|
@@ -30698,7 +31221,7 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30698
31221
|
collateral: lstToken,
|
|
30699
31222
|
debt: underlyingToken,
|
|
30700
31223
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
30701
|
-
id: "vesu_leg1" /* VESU_LEG1
|
|
31224
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol)
|
|
30702
31225
|
});
|
|
30703
31226
|
const commonAdapter = new CommonAdapter({
|
|
30704
31227
|
manager: vaultSettings.manager,
|
|
@@ -30707,25 +31230,39 @@ function getLooperSettings2(lstSymbol, underlyingSymbol, vaultSettings, pool1) {
|
|
|
30707
31230
|
vaultAddress: vaultSettings.vaultAddress,
|
|
30708
31231
|
vaultAllocator: vaultSettings.vaultAllocator
|
|
30709
31232
|
});
|
|
30710
|
-
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
30711
|
-
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
30712
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
30713
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getMultiplyAdapter("multiply_vesu" /* MULTIPLY_VESU */).bind(vesuAdapterLST));
|
|
30714
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
30715
|
-
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
30716
31233
|
vaultSettings.adapters.push(...[{
|
|
30717
|
-
id: "
|
|
31234
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, underlyingToken.symbol),
|
|
30718
31235
|
adapter: vesuAdapterLST
|
|
30719
31236
|
}, {
|
|
30720
31237
|
id: "common_adapter" /* COMMON */,
|
|
30721
31238
|
adapter: commonAdapter
|
|
30722
31239
|
}]);
|
|
30723
|
-
|
|
30724
|
-
|
|
30725
|
-
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address,
|
|
30726
|
-
vaultSettings.leafAdapters.push(
|
|
30727
|
-
vaultSettings.leafAdapters.push(
|
|
30728
|
-
vaultSettings.leafAdapters.push(
|
|
31240
|
+
const { isV2, addr: poolAddr } = getVesuSingletonAddress(pool1);
|
|
31241
|
+
const VESU_MULTIPLY = isV2 ? vesuAdapterLST.VESU_MULTIPLY : vesuAdapterLST.VESU_MULTIPLY_V1;
|
|
31242
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, VESU_MULTIPLY, "multiple_approve" /* MULTIPLE_APPROVE */).bind(commonAdapter));
|
|
31243
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_on" /* SWITCH_DELEGATION_ON */).bind(vesuAdapterLST));
|
|
31244
|
+
vaultSettings.leafAdapters.push(vesuAdapterLST.getVesuModifyDelegationAdapter("switch_delegation_off" /* SWITCH_DELEGATION_OFF */).bind(vesuAdapterLST));
|
|
31245
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, AVNU_EXCHANGE, "avnu_mul_approve_withdr" /* AVNU_MULTIPLY_APPROVE_WITHDRAW */).bind(commonAdapter));
|
|
31246
|
+
for (let borrowableAsset of vaultSettings.borrowable_assets) {
|
|
31247
|
+
const debtAsset = borrowableAsset;
|
|
31248
|
+
const approve_debt_token_id = getAvnuManageIDs("avnu_mul_approve_dep" /* AVNU_MULTIPLY_APPROVE_DEPOSIT */, debtAsset.symbol);
|
|
31249
|
+
const swap_debt_token_id = getAvnuManageIDs("avnu_mul_swap_dep" /* AVNU_MULTIPLY_SWAP_DEPOSIT */, debtAsset.symbol);
|
|
31250
|
+
const swap_lst_token_id = getAvnuManageIDs("avnu_mul_swap_withdr" /* AVNU_MULTIPLY_SWAP_WITHDRAW */, debtAsset.symbol);
|
|
31251
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(debtAsset.address, AVNU_EXCHANGE, approve_debt_token_id).bind(commonAdapter));
|
|
31252
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(debtAsset.address, lstToken.address, swap_debt_token_id, false).bind(commonAdapter));
|
|
31253
|
+
vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(lstToken.address, debtAsset.address, swap_lst_token_id, false).bind(commonAdapter));
|
|
31254
|
+
const vesuAdapter = new VesuAdapter({
|
|
31255
|
+
poolId: pool1,
|
|
31256
|
+
collateral: lstToken,
|
|
31257
|
+
debt: debtAsset,
|
|
31258
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
31259
|
+
id: getVesuLegId("vesu_leg1" /* VESU_LEG1 */, debtAsset.symbol)
|
|
31260
|
+
});
|
|
31261
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, poolAddr, "approve_token1" /* APPROVE_TOKEN1 */).bind(commonAdapter));
|
|
31262
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getModifyPosition.bind(vesuAdapter));
|
|
31263
|
+
const multiplID = getVesuLegId("multiply_vesu" /* MULTIPLY_VESU */, debtAsset.symbol);
|
|
31264
|
+
vaultSettings.leafAdapters.push(vesuAdapter.getMultiplyAdapter(multiplID).bind(vesuAdapter));
|
|
31265
|
+
}
|
|
30729
31266
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, "approve_bring_liquidity" /* APPROVE_BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30730
31267
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter("bring_liquidity" /* BRING_LIQUIDITY */).bind(commonAdapter));
|
|
30731
31268
|
vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter("defispring_rewards" /* DEFISPRING_REWARDS */).bind(vesuAdapterLST));
|
|
@@ -30803,7 +31340,8 @@ var hyperxSTRK = {
|
|
|
30803
31340
|
adapters: [],
|
|
30804
31341
|
targetHealthFactor: 1.1,
|
|
30805
31342
|
minHealthFactor: 1.05,
|
|
30806
|
-
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK")
|
|
31343
|
+
borrowable_assets: Global.getDefaultTokens().filter((token) => token.symbol === "STRK"),
|
|
31344
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "STRK")
|
|
30807
31345
|
};
|
|
30808
31346
|
var hyperxWBTC = {
|
|
30809
31347
|
vaultAddress: ContractAddr.from("0x2da9d0f96a46b453f55604313785dc866424240b1c6811d13bef594343db818"),
|
|
@@ -30815,7 +31353,8 @@ var hyperxWBTC = {
|
|
|
30815
31353
|
adapters: [],
|
|
30816
31354
|
targetHealthFactor: 1.1,
|
|
30817
31355
|
minHealthFactor: 1.05,
|
|
30818
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31356
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31357
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "WBTC")
|
|
30819
31358
|
};
|
|
30820
31359
|
var hyperxtBTC = {
|
|
30821
31360
|
vaultAddress: ContractAddr.from("0x47d5f68477e5637ce0e56436c6b5eee5a354e6828995dae106b11a48679328"),
|
|
@@ -30827,7 +31366,8 @@ var hyperxtBTC = {
|
|
|
30827
31366
|
adapters: [],
|
|
30828
31367
|
targetHealthFactor: 1.1,
|
|
30829
31368
|
minHealthFactor: 1.05,
|
|
30830
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31369
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31370
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "tBTC")
|
|
30831
31371
|
};
|
|
30832
31372
|
var hyperxsBTC = {
|
|
30833
31373
|
vaultAddress: ContractAddr.from("0x437ef1e7d0f100b2e070b7a65cafec0b2be31b0290776da8b4112f5473d8d9"),
|
|
@@ -30839,7 +31379,8 @@ var hyperxsBTC = {
|
|
|
30839
31379
|
adapters: [],
|
|
30840
31380
|
targetHealthFactor: 1.1,
|
|
30841
31381
|
minHealthFactor: 1.05,
|
|
30842
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31382
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31383
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "solvBTC")
|
|
30843
31384
|
};
|
|
30844
31385
|
var hyperxLBTC = {
|
|
30845
31386
|
vaultAddress: ContractAddr.from("0x64cf24d4883fe569926419a0569ab34497c6956a1a308fa883257f7486d7030"),
|
|
@@ -30851,7 +31392,8 @@ var hyperxLBTC = {
|
|
|
30851
31392
|
adapters: [],
|
|
30852
31393
|
targetHealthFactor: 1.1,
|
|
30853
31394
|
minHealthFactor: 1.05,
|
|
30854
|
-
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset))
|
|
31395
|
+
borrowable_assets: borrowableAssets.map((asset) => Global.getDefaultTokens().find((token) => token.symbol === asset)),
|
|
31396
|
+
underlyingToken: Global.getDefaultTokens().find((token) => token.symbol === "LBTC")
|
|
30855
31397
|
};
|
|
30856
31398
|
function getInvestmentSteps(lstSymbol, underlyingSymbol) {
|
|
30857
31399
|
return [
|
|
@@ -30883,7 +31425,7 @@ function getStrategySettings(lstSymbol, underlyingSymbol, addresses, isPreview =
|
|
|
30883
31425
|
faqs: getFAQs2(lstSymbol, underlyingSymbol),
|
|
30884
31426
|
investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
|
|
30885
31427
|
isPreview,
|
|
30886
|
-
apyMethodology: "Current annualized APY in terms of base asset of the LST"
|
|
31428
|
+
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."
|
|
30887
31429
|
};
|
|
30888
31430
|
}
|
|
30889
31431
|
var HyperLSTStrategies = [
|
|
@@ -31553,6 +32095,7 @@ var Deployer = {
|
|
|
31553
32095
|
};
|
|
31554
32096
|
var deployer_default = Deployer;
|
|
31555
32097
|
export {
|
|
32098
|
+
APYType,
|
|
31556
32099
|
AUMTypes,
|
|
31557
32100
|
AVNU_EXCHANGE,
|
|
31558
32101
|
AVNU_MIDDLEWARE,
|