@strkfarm/sdk 2.0.0-dev.40 → 2.0.0-dev.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.global.js +407 -208
- package/dist/index.browser.mjs +425 -225
- package/dist/index.d.ts +38 -14
- package/dist/index.js +427 -225
- package/dist/index.mjs +426 -225
- package/package.json +4 -5
- package/src/global.ts +36 -34
- package/src/interfaces/common.tsx +6 -0
- package/src/modules/index.ts +1 -0
- package/src/modules/pricer-avnu-api.ts +114 -0
- package/src/modules/pricer.ts +63 -45
- package/src/node/pricer-redis.ts +1 -0
- package/src/strategies/ekubo-cl-vault.tsx +3 -0
- package/src/strategies/svk-strategy.ts +159 -2
- package/src/strategies/token-boosted-xstrk-carry-strategy.tsx +46 -9
- package/src/strategies/universal-lst-muliplier-strategy.tsx +90 -19
- package/src/strategies/universal-strategy.tsx +216 -372
- package/src/strategies/yoloVault.ts +3 -0
|
@@ -2,8 +2,8 @@ import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
|
2
2
|
import { IConfig, IStrategyMetadata, Protocols, TokenInfo, VaultPosition } from "@/interfaces";
|
|
3
3
|
import { PricerBase } from "@/modules/pricerBase";
|
|
4
4
|
import { ERC20 } from "@/modules";
|
|
5
|
-
import { BaseStrategy, SingleActionAmount, SingleTokenInfo } from "./base-strategy";
|
|
6
|
-
import { Call, Contract, num, uint256 } from "starknet";
|
|
5
|
+
import { BaseStrategy, SingleActionAmount, SingleTokenInfo, UserPositionCard, UserPositionCardsInput } from "./base-strategy";
|
|
6
|
+
import { BlockIdentifier, Call, Contract, num, uint256 } from "starknet";
|
|
7
7
|
import { assert, LeafData, logger, StandardMerkleTree } from "@/utils";
|
|
8
8
|
import { UniversalStrategySettings } from "./universal-strategy";
|
|
9
9
|
import { UNIVERSAL_MANAGE_IDS } from "./universal-strategy";
|
|
@@ -94,6 +94,34 @@ export abstract class SVKStrategy<S extends UniversalStrategySettings>
|
|
|
94
94
|
return [call];
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
async getUserTVL(user: ContractAddr, blockIdentifier: BlockIdentifier = "latest"): Promise<SingleTokenInfo> {
|
|
98
|
+
const shares: any = await this.contract.call("balanceOf", [user.address], { blockIdentifier });
|
|
99
|
+
const assets: any = await this.contract.call(
|
|
100
|
+
"convert_to_assets",
|
|
101
|
+
[uint256.bnToUint256(shares)],
|
|
102
|
+
{ blockIdentifier }
|
|
103
|
+
);
|
|
104
|
+
const amount = Web3Number.fromWei(
|
|
105
|
+
assets.toString(),
|
|
106
|
+
this.metadata.depositTokens[0].decimals
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const blockNumber = typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint"
|
|
110
|
+
? Number(blockIdentifier)
|
|
111
|
+
: undefined;
|
|
112
|
+
|
|
113
|
+
const price = await this.pricer.getPrice(
|
|
114
|
+
this.metadata.depositTokens[0].symbol,
|
|
115
|
+
blockNumber
|
|
116
|
+
);
|
|
117
|
+
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
118
|
+
return {
|
|
119
|
+
tokenInfo: this.asset(),
|
|
120
|
+
amount,
|
|
121
|
+
usdValue
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
97
125
|
/**
|
|
98
126
|
* Returns the unused balance in the vault allocator.
|
|
99
127
|
* Note: This function is common for any SVK strategy.
|
|
@@ -322,6 +350,135 @@ export abstract class SVKStrategy<S extends UniversalStrategySettings>
|
|
|
322
350
|
};
|
|
323
351
|
}
|
|
324
352
|
|
|
353
|
+
async getUserRealizedAPY(
|
|
354
|
+
blockIdentifier: BlockIdentifier = "latest",
|
|
355
|
+
sinceBlocks = 600000
|
|
356
|
+
): Promise<number> {
|
|
357
|
+
logger.verbose(
|
|
358
|
+
`${this.getTag()}: getUserRealizedAPY => starting with blockIdentifier=${blockIdentifier}, sinceBlocks=${sinceBlocks}`
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
const blockNow =
|
|
362
|
+
typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint"
|
|
363
|
+
? Number(blockIdentifier)
|
|
364
|
+
: (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
365
|
+
const blockNowTime =
|
|
366
|
+
typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint"
|
|
367
|
+
? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp
|
|
368
|
+
: new Date().getTime() / 1000;
|
|
369
|
+
|
|
370
|
+
const blockBefore = Math.max(
|
|
371
|
+
blockNow - sinceBlocks,
|
|
372
|
+
this.metadata.launchBlock
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
const assetsNowRaw: bigint = await this.contract.call("total_assets", [], {
|
|
376
|
+
blockIdentifier,
|
|
377
|
+
}) as bigint;
|
|
378
|
+
const amountNow = Web3Number.fromWei(
|
|
379
|
+
assetsNowRaw.toString(),
|
|
380
|
+
this.metadata.depositTokens[0].decimals
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
const supplyNowRaw: bigint = await this.contract.call("total_supply", [], {
|
|
384
|
+
blockIdentifier,
|
|
385
|
+
}) as bigint;
|
|
386
|
+
const supplyNow = Web3Number.fromWei(supplyNowRaw.toString(), 18);
|
|
387
|
+
|
|
388
|
+
const assetsBeforeRaw: bigint = await this.contract.call(
|
|
389
|
+
"total_assets",
|
|
390
|
+
[],
|
|
391
|
+
{ blockIdentifier: blockBefore }
|
|
392
|
+
) as bigint;
|
|
393
|
+
const amountBefore = Web3Number.fromWei(
|
|
394
|
+
assetsBeforeRaw.toString(),
|
|
395
|
+
this.metadata.depositTokens[0].decimals
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
const supplyBeforeRaw: bigint = await this.contract.call(
|
|
399
|
+
"total_supply",
|
|
400
|
+
[],
|
|
401
|
+
{ blockIdentifier: blockBefore }
|
|
402
|
+
) as bigint;
|
|
403
|
+
const supplyBefore = Web3Number.fromWei(supplyBeforeRaw.toString(), 18);
|
|
404
|
+
|
|
405
|
+
const blockBeforeInfo = await this.config.provider.getBlockWithTxs(
|
|
406
|
+
blockBefore
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
const assetsPerShareNow = amountNow
|
|
410
|
+
.multipliedBy(1e18)
|
|
411
|
+
.dividedBy(supplyNow.toString());
|
|
412
|
+
|
|
413
|
+
const assetsPerShareBf = amountBefore
|
|
414
|
+
.multipliedBy(1e18)
|
|
415
|
+
.dividedBy(supplyBefore.toString());
|
|
416
|
+
|
|
417
|
+
const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
|
|
418
|
+
|
|
419
|
+
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsNow: ${amountNow.toString()}`);
|
|
420
|
+
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsBefore: ${amountBefore.toString()}`);
|
|
421
|
+
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsPerShareNow: ${assetsPerShareNow.toString()}`);
|
|
422
|
+
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsPerShareBf: ${assetsPerShareBf.toString()}`);
|
|
423
|
+
logger.verbose(`${this.getTag()} [getUserRealizedAPY] Supply before: ${supplyBefore.toString()}`);
|
|
424
|
+
logger.verbose(`${this.getTag()} [getUserRealizedAPY] Supply now: ${supplyNow.toString()}`);
|
|
425
|
+
logger.verbose(`${this.getTag()} [getUserRealizedAPY] Time diff in seconds: ${timeDiffSeconds}`);
|
|
426
|
+
|
|
427
|
+
const apyForGivenBlocks =
|
|
428
|
+
Number(
|
|
429
|
+
assetsPerShareNow
|
|
430
|
+
.minus(assetsPerShareBf)
|
|
431
|
+
.multipliedBy(10000)
|
|
432
|
+
.dividedBy(assetsPerShareBf)
|
|
433
|
+
) / 10000;
|
|
434
|
+
|
|
435
|
+
return (apyForGivenBlocks * (365 * 24 * 3600)) / timeDiffSeconds;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
async getUserPositionCards(input: UserPositionCardsInput): Promise<UserPositionCard[]> {
|
|
439
|
+
const { user, investmentFlows = [] } = input;
|
|
440
|
+
const [userTVL] = await Promise.all([
|
|
441
|
+
this.getUserTVL(user),
|
|
442
|
+
]);
|
|
443
|
+
const cards: UserPositionCard[] = [
|
|
444
|
+
{
|
|
445
|
+
title: "Your Holdings",
|
|
446
|
+
tooltip: "Your Holdings",
|
|
447
|
+
value: this.formatTokenAmountForCard(userTVL.amount, userTVL.tokenInfo),
|
|
448
|
+
subValue: `≈ ${this.formatUSDForCard(userTVL.usdValue)}`,
|
|
449
|
+
subValueColor: "positive",
|
|
450
|
+
},
|
|
451
|
+
];
|
|
452
|
+
|
|
453
|
+
let lifetimeAmount = userTVL.amount.multipliedBy(0);
|
|
454
|
+
let lifetimeTokenInfo = userTVL.tokenInfo;
|
|
455
|
+
let lifetimeUsdValue = 0;
|
|
456
|
+
if (investmentFlows.length > 0) {
|
|
457
|
+
try {
|
|
458
|
+
const earningsResult = this.getLifetimeEarnings(userTVL, investmentFlows);
|
|
459
|
+
lifetimeAmount = earningsResult.lifetimeEarnings;
|
|
460
|
+
lifetimeTokenInfo = earningsResult.tokenInfo.tokenInfo;
|
|
461
|
+
const userAmount = userTVL.amount.toNumber();
|
|
462
|
+
if (Number.isFinite(userAmount) && userAmount > 0) {
|
|
463
|
+
const pricePerToken = userTVL.usdValue / userAmount;
|
|
464
|
+
lifetimeUsdValue = lifetimeAmount.toNumber() * pricePerToken;
|
|
465
|
+
}
|
|
466
|
+
} catch (error) {
|
|
467
|
+
logger.warn(`${this.getTag()}::getUserPositionCards lifetime earnings fallback`, error);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
cards.push({
|
|
472
|
+
title: "Lifetime Earnings",
|
|
473
|
+
tooltip: "Lifetime Earnings",
|
|
474
|
+
value: this.formatTokenAmountForCard(lifetimeAmount, lifetimeTokenInfo),
|
|
475
|
+
subValue: `≈ ${this.formatUSDForCard(lifetimeUsdValue)}`,
|
|
476
|
+
subValueColor: this.getSubValueColorFromSignedNumber(lifetimeUsdValue),
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
return cards;
|
|
480
|
+
}
|
|
481
|
+
|
|
325
482
|
async getPrevAUM() {
|
|
326
483
|
const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
|
|
327
484
|
const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
|
|
@@ -33,7 +33,11 @@ import { ERC20, PricerFromApi, TokenMarketData } from "@/modules";
|
|
|
33
33
|
import { PricerBase } from "@/modules/pricerBase";
|
|
34
34
|
import { logger, assert } from "@/utils";
|
|
35
35
|
import { BlockIdentifier, Call, uint256, num } from "starknet";
|
|
36
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
SingleTokenInfo,
|
|
38
|
+
UserPositionCard,
|
|
39
|
+
UserPositionCardsInput,
|
|
40
|
+
} from "./base-strategy";
|
|
37
41
|
import { SVKStrategy } from "./svk-strategy";
|
|
38
42
|
import {
|
|
39
43
|
APYType,
|
|
@@ -320,6 +324,34 @@ export class BoostedxSTRKCarryStrategy<
|
|
|
320
324
|
};
|
|
321
325
|
}
|
|
322
326
|
|
|
327
|
+
async getUserPositionCards(
|
|
328
|
+
input: UserPositionCardsInput,
|
|
329
|
+
): Promise<UserPositionCard[]> {
|
|
330
|
+
const cards = await super.getUserPositionCards(input);
|
|
331
|
+
const realizedApyRaw = await this.getUserRealizedAPY().catch((error) => {
|
|
332
|
+
logger.warn(
|
|
333
|
+
`${this.getTag()}::getUserPositionCards realized APY fallback`,
|
|
334
|
+
error,
|
|
335
|
+
);
|
|
336
|
+
return null;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
const realizedApy =
|
|
340
|
+
typeof realizedApyRaw === "number"
|
|
341
|
+
? this.formatPercentForCard(realizedApyRaw)
|
|
342
|
+
: "N/A";
|
|
343
|
+
|
|
344
|
+
cards.push({
|
|
345
|
+
title: "Realized APY",
|
|
346
|
+
tooltip:
|
|
347
|
+
this.metadata.realizedApyMethodology ||
|
|
348
|
+
"Realized APY is based on past 14 days performance",
|
|
349
|
+
value: realizedApy,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
return cards;
|
|
353
|
+
}
|
|
354
|
+
|
|
323
355
|
async getAUM(): Promise<{
|
|
324
356
|
net: SingleTokenInfo;
|
|
325
357
|
prevAum: Web3Number;
|
|
@@ -952,7 +984,7 @@ const wbtcBoostedSettings: BoostedxSTRKCarryStrategySettings = {
|
|
|
952
984
|
depositToken: Global.getDefaultTokens().find((t) => t.symbol === "WBTC")!,
|
|
953
985
|
debtToken: Global.getDefaultTokens().find((t) => t.symbol === "STRK")!,
|
|
954
986
|
lstHyperToken: Global.getDefaultTokens().find((t) => t.symbol === "xSTRK")!,
|
|
955
|
-
maxLTV: 0.
|
|
987
|
+
maxLTV: 0.7,
|
|
956
988
|
targetLTV: 0.5,
|
|
957
989
|
hasBtcFiRewards: true,
|
|
958
990
|
hyperLstVaultAddress: ContractAddr.from(
|
|
@@ -1013,8 +1045,7 @@ const boostedCarryRiskFactors: RiskFactor[] = [
|
|
|
1013
1045
|
value: OracleRiskLevel.SINGLE_RELIABLE,
|
|
1014
1046
|
// 10% — Vesu HF depends on feeds; Starknet oracles are established but not redundant here.
|
|
1015
1047
|
weight: 10,
|
|
1016
|
-
reason:
|
|
1017
|
-
"Vesu collateral and debt valuations rely on Starknet price feeds.",
|
|
1048
|
+
reason: "Vesu collateral and debt valuations rely on Starknet price feeds.",
|
|
1018
1049
|
},
|
|
1019
1050
|
{
|
|
1020
1051
|
type: RiskType.COUNTERPARTY_RISK,
|
|
@@ -1065,9 +1096,10 @@ function getBoostedCarryFAQs(
|
|
|
1065
1096
|
question: "Which protocols are used?",
|
|
1066
1097
|
answer: (
|
|
1067
1098
|
<span>
|
|
1068
|
-
<strong>Vesu</strong> for collateral and borrowing,
|
|
1069
|
-
for swaps, <strong>Endur</strong> for
|
|
1070
|
-
<strong>Hyper-{lstSymbol}</strong> vault
|
|
1099
|
+
<strong>Vesu</strong> for collateral and borrowing,{" "}
|
|
1100
|
+
<strong>Avnu</strong> for swaps, <strong>Endur</strong> for{" "}
|
|
1101
|
+
{lstSymbol}, and the Troves <strong>Hyper-{lstSymbol}</strong> vault
|
|
1102
|
+
for the boosted leg.
|
|
1071
1103
|
</span>
|
|
1072
1104
|
),
|
|
1073
1105
|
},
|
|
@@ -1160,6 +1192,9 @@ function getStrategySettings(
|
|
|
1160
1192
|
],
|
|
1161
1193
|
},
|
|
1162
1194
|
contractDetails: getContractDetails(settings),
|
|
1195
|
+
feeBps: {
|
|
1196
|
+
performanceFeeBps: 1500,
|
|
1197
|
+
},
|
|
1163
1198
|
faqs: getBoostedCarryFAQs(
|
|
1164
1199
|
depositToken.symbol,
|
|
1165
1200
|
debtToken.symbol,
|
|
@@ -1180,7 +1215,8 @@ function getStrategySettings(
|
|
|
1180
1215
|
auditStatus: AuditStatus.AUDITED,
|
|
1181
1216
|
sourceCode: {
|
|
1182
1217
|
type: SourceCodeType.OPEN_SOURCE,
|
|
1183
|
-
contractLink:
|
|
1218
|
+
contractLink:
|
|
1219
|
+
"https://github.com/trovesfi/starknet_vault_kit/tree/sherlock-audited",
|
|
1184
1220
|
},
|
|
1185
1221
|
// TODO
|
|
1186
1222
|
accessControl: {
|
|
@@ -1206,7 +1242,8 @@ function getStrategySettings(
|
|
|
1206
1242
|
],
|
|
1207
1243
|
},
|
|
1208
1244
|
usualTimeToEarnings: "2 weeks",
|
|
1209
|
-
usualTimeToEarningsDescription:
|
|
1245
|
+
usualTimeToEarningsDescription:
|
|
1246
|
+
"This strategy depends on Hyper xSTRK's yield, which depends on the price of xSTRK on DEX appreciating. It may be possible the increase is not continuous and generally rebases atleast once every 2 weeks.",
|
|
1210
1247
|
};
|
|
1211
1248
|
}
|
|
1212
1249
|
|
|
@@ -8,7 +8,7 @@ import { AVNU_EXCHANGE } from "./universal-adapters/adapter-utils";
|
|
|
8
8
|
import { DepegRiskLevel, LiquidationRiskLevel, SmartContractRiskLevel, TechnicalRiskLevel } from "@/interfaces/risks";
|
|
9
9
|
import { AvnuWrapper, EkuboQuoter, ERC20, LSTAPRService, PricerFromApi, PricerLST } from "@/modules";
|
|
10
10
|
import { assert, logger } from "@/utils";
|
|
11
|
-
import { SingleActionAmount, SingleTokenInfo } from "./base-strategy";
|
|
11
|
+
import { SingleActionAmount, SingleTokenInfo, UserPositionCard, UserPositionCardsInput } from "./base-strategy";
|
|
12
12
|
import { SVKStrategy } from "./svk-strategy";
|
|
13
13
|
import { Call, Contract, uint256 } from "starknet";
|
|
14
14
|
import ERC4626Abi from "@/data/erc4626.abi.json";
|
|
@@ -119,8 +119,8 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
119
119
|
// todo support lending assets of underlying as well (like if xSTRK looping is not viable, simply supply STRK)
|
|
120
120
|
getVesuMultiplyAdapters() {
|
|
121
121
|
const vesuMultipleAdapters = this.metadata.additionalInfo.adapters
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
.filter(adapter => adapter.adapter.name === VesuMultiplyAdapter.name)
|
|
123
|
+
.map(adapter => adapter.adapter) as VesuMultiplyAdapter[]
|
|
124
124
|
|
|
125
125
|
for (const vesuAdapter of vesuMultipleAdapters) {
|
|
126
126
|
vesuAdapter.config.pricer = this.pricer;
|
|
@@ -586,7 +586,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
586
586
|
};
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
-
async getAUM(unrealizedAUM: boolean = false): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: PositionInfo[]}> {
|
|
589
|
+
async getAUM(unrealizedAUM: boolean = false): Promise<{ net: SingleTokenInfo, prevAum: Web3Number, splits: PositionInfo[] }> {
|
|
590
590
|
const underlying = this.asset();
|
|
591
591
|
assert(underlying.symbol.startsWith('x'), 'Underlying is not an LST of Endur');
|
|
592
592
|
|
|
@@ -642,7 +642,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
642
642
|
tokenInfo: underlying,
|
|
643
643
|
amount: netAUM,
|
|
644
644
|
usdValue: netAUM.toNumber() * assetPrice.price,
|
|
645
|
-
apy: {apy: 0, type: APYType.BASE}, // VT: Dont remember why this field exists here. FOr now, set it to 0.
|
|
645
|
+
apy: { apy: 0, type: APYType.BASE }, // VT: Dont remember why this field exists here. FOr now, set it to 0.
|
|
646
646
|
remarks: AUMTypes.FINALISED,
|
|
647
647
|
protocol: Protocols.NONE
|
|
648
648
|
};
|
|
@@ -651,16 +651,18 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
651
651
|
tokenInfo: underlying,
|
|
652
652
|
amount: Web3Number.fromWei('0', underlying.decimals),
|
|
653
653
|
usdValue: 0,
|
|
654
|
-
apy: {apy: 0, type: APYType.BASE},
|
|
654
|
+
apy: { apy: 0, type: APYType.BASE },
|
|
655
655
|
remarks: AUMTypes.DEFISPRING,
|
|
656
656
|
protocol: Protocols.NONE
|
|
657
657
|
};
|
|
658
658
|
|
|
659
|
-
return {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
659
|
+
return {
|
|
660
|
+
net: {
|
|
661
|
+
tokenInfo: underlying,
|
|
662
|
+
amount: netAUM,
|
|
663
|
+
usdValue: netAUM.toNumber() * assetPrice.price
|
|
664
|
+
}, prevAum: prevAum, splits: [realAUM, estimatedAUMDelta]
|
|
665
|
+
};
|
|
664
666
|
}
|
|
665
667
|
|
|
666
668
|
async getTVLUnrealized() {
|
|
@@ -682,6 +684,70 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
682
684
|
};
|
|
683
685
|
}
|
|
684
686
|
|
|
687
|
+
async getUserPositionCards(input: UserPositionCardsInput): Promise<UserPositionCard[]> {
|
|
688
|
+
const cards = await super.getUserPositionCards(input);
|
|
689
|
+
|
|
690
|
+
try {
|
|
691
|
+
const [unrealizedResult, userTVL, realizedApyRaw] = await Promise.all([
|
|
692
|
+
this.getUserUnrealizedGains(input.user),
|
|
693
|
+
this.getUserTVL(input.user),
|
|
694
|
+
this.getUserRealizedAPY().catch(() => null),
|
|
695
|
+
]);
|
|
696
|
+
const amount = unrealizedResult.unrealizedGains;
|
|
697
|
+
let usdValue = 0;
|
|
698
|
+
const userAmount = userTVL.amount.toNumber();
|
|
699
|
+
if (Number.isFinite(userAmount) && userAmount > 0) {
|
|
700
|
+
usdValue = (userTVL.usdValue / userAmount) * amount.toNumber();
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
cards.push({
|
|
704
|
+
title: "Unrealized Gains",
|
|
705
|
+
tooltip: "Unrealized gains based on current market prices vs Endur prices. If you withdraw now, you will forgo these gains.",
|
|
706
|
+
value: this.formatTokenAmountForCard(amount, unrealizedResult.tokenInfo),
|
|
707
|
+
subValue: `≈ ${this.formatUSDForCard(usdValue)}`,
|
|
708
|
+
subValueColor: this.getSubValueColorFromSignedNumber(usdValue),
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
const realizedApy = typeof realizedApyRaw === "number"
|
|
712
|
+
? this.formatPercentForCard(realizedApyRaw)
|
|
713
|
+
: "N/A";
|
|
714
|
+
cards.push({
|
|
715
|
+
title: "Realized APY",
|
|
716
|
+
tooltip: this.metadata.realizedApyMethodology || "Realized APY is based on past 14 days performance",
|
|
717
|
+
value: realizedApy,
|
|
718
|
+
});
|
|
719
|
+
} catch (error) {
|
|
720
|
+
logger.warn(`${this.getTag()}::getUserPositionCards unrealized gains fallback`, error);
|
|
721
|
+
cards.push({
|
|
722
|
+
title: "Unrealized Gains",
|
|
723
|
+
tooltip: "Unrealized gains based on current market prices vs Endur prices. If you withdraw now, you will forgo these gains.",
|
|
724
|
+
value: this.formatTokenAmountForCard(
|
|
725
|
+
Web3Number.fromWei("0", this.asset().decimals),
|
|
726
|
+
this.asset()
|
|
727
|
+
),
|
|
728
|
+
subValue: `≈ ${this.formatUSDForCard(0)}`,
|
|
729
|
+
subValueColor: "default",
|
|
730
|
+
});
|
|
731
|
+
cards.push({
|
|
732
|
+
title: "Realized APY",
|
|
733
|
+
tooltip: this.metadata.realizedApyMethodology || "Realized APY is based on past 14 days performance",
|
|
734
|
+
value: "N/A",
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (this.asset().symbol === "xSTRK") {
|
|
739
|
+
const index = cards.findIndex((card) => card.title === "Lifetime Earnings");
|
|
740
|
+
if (index >= 0) {
|
|
741
|
+
cards[index] = {
|
|
742
|
+
...cards[index],
|
|
743
|
+
tooltip: "Lifetime earnings of the vault. Due to migration of xSTRK Sensei to this vault, any migrated funds are also seen as lifetime earnings. Team is working to fix this soon.",
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
return cards;
|
|
749
|
+
}
|
|
750
|
+
|
|
685
751
|
}
|
|
686
752
|
|
|
687
753
|
export default function VaultDescription(
|
|
@@ -706,7 +772,7 @@ export default function VaultDescription(
|
|
|
706
772
|
</p>
|
|
707
773
|
|
|
708
774
|
<p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
709
|
-
This vault uses Vesu for lending and borrowing. The oracle used by this pool is a {highlightTextWithLinks("conversion rate oracle", [{highlight: "conversion rate oracle", link: "https://docs.pragma.build/starknet/development#conversion-rate"}])}
|
|
775
|
+
This vault uses Vesu for lending and borrowing. The oracle used by this pool is a {highlightTextWithLinks("conversion rate oracle", [{ highlight: "conversion rate oracle", link: "https://docs.pragma.build/starknet/development#conversion-rate" }])}
|
|
710
776
|
{" "}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.
|
|
711
777
|
</p>
|
|
712
778
|
|
|
@@ -747,7 +813,7 @@ function getLooperSettings(
|
|
|
747
813
|
|
|
748
814
|
const baseAdapterConfig: BaseAdapterConfig = {
|
|
749
815
|
baseToken: lstToken,
|
|
750
|
-
supportedPositions: [{asset: lstToken, isDebt: false}, {asset: underlyingToken, isDebt: true}],
|
|
816
|
+
supportedPositions: [{ asset: lstToken, isDebt: false }, { asset: underlyingToken, isDebt: true }],
|
|
751
817
|
networkConfig: getMainnetConfig(),
|
|
752
818
|
pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
|
|
753
819
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
@@ -899,7 +965,7 @@ export const _riskFactor: RiskFactor[] = [
|
|
|
899
965
|
{ type: RiskType.SMART_CONTRACT_RISK, value: SmartContractRiskLevel.WELL_AUDITED, weight: 25, reason: "Audited by Zellic" },
|
|
900
966
|
{ type: RiskType.LIQUIDATION_RISK, value: LiquidationRiskLevel.VERY_LOW_PROBABILITY, weight: 25, reason: "The collateral and debt are highly correlated" },
|
|
901
967
|
{ type: RiskType.TECHNICAL_RISK, value: TechnicalRiskLevel.STABLE_INFRASTRUCTURE, weight: 25, reason: "Liquidation can only happen if vault is left un-monitored for weeks, which is highly unlikely. We actively monitor all services on a daily basis." },
|
|
902
|
-
{type: RiskType.DEPEG_RISK, value: DepegRiskLevel.GENERALLY_STABLE, weight: 25, reason: "Generally stable pegged assets" },
|
|
968
|
+
{ type: RiskType.DEPEG_RISK, value: DepegRiskLevel.GENERALLY_STABLE, weight: 25, reason: "Generally stable pegged assets" },
|
|
903
969
|
];
|
|
904
970
|
|
|
905
971
|
const hyperxSTRK: HyperLSTStrategySettings = {
|
|
@@ -1088,8 +1154,8 @@ function createHyperLSTSettings(
|
|
|
1088
1154
|
tab: "deposit" as const,
|
|
1089
1155
|
text: (
|
|
1090
1156
|
<>
|
|
1091
|
-
|
|
1092
|
-
|
|
1157
|
+
To acquire the LST, please visit{" "}
|
|
1158
|
+
<a href="https://app.endur.fi" target="_blank" rel="noopener noreferrer">endur.fi</a>
|
|
1093
1159
|
</>
|
|
1094
1160
|
),
|
|
1095
1161
|
type: "info" as const,
|
|
@@ -1171,9 +1237,14 @@ function getStrategySettings(
|
|
|
1171
1237
|
faqs: getFAQs(lstSymbol, underlyingSymbol, isLST),
|
|
1172
1238
|
investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
|
|
1173
1239
|
isPreview: isPreview,
|
|
1174
|
-
apyMethodology:
|
|
1175
|
-
|
|
1176
|
-
|
|
1240
|
+
apyMethodology:
|
|
1241
|
+
"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.",
|
|
1242
|
+
realizedApyMethodology:
|
|
1243
|
+
"The realizedAPY is based on past 14 days performance by the vault",
|
|
1244
|
+
feeBps: {
|
|
1245
|
+
performanceFeeBps: 1000,
|
|
1246
|
+
},
|
|
1247
|
+
tags: lstSymbol.includes("BTC")
|
|
1177
1248
|
? [StrategyTag.BTC, StrategyTag.LEVERED]
|
|
1178
1249
|
: [StrategyTag.LEVERED],
|
|
1179
1250
|
security: HYPER_LST_SECURITY,
|