@strkfarm/sdk 2.0.0-dev.4 → 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/cli.js +190 -36
- package/dist/cli.mjs +188 -34
- package/dist/index.browser.global.js +116250 -90801
- package/dist/index.browser.mjs +13050 -10957
- package/dist/index.d.ts +2232 -1933
- package/dist/index.js +13380 -11084
- package/dist/index.mjs +13280 -11007
- package/package.json +6 -7
- package/src/data/avnu.abi.json +840 -0
- package/src/data/ekubo-price-fethcer.abi.json +265 -0
- package/src/data/redeem-request-nft.abi.json +752 -0
- package/src/data/universal-vault.abi.json +8 -7
- package/src/dataTypes/_bignumber.ts +13 -4
- package/src/dataTypes/bignumber.browser.ts +10 -1
- package/src/dataTypes/bignumber.node.ts +10 -1
- package/src/dataTypes/index.ts +3 -2
- package/src/dataTypes/mynumber.ts +141 -0
- package/src/global.ts +93 -36
- package/src/index.browser.ts +2 -1
- package/src/interfaces/common.tsx +218 -5
- package/src/modules/apollo-client-config.ts +28 -0
- package/src/modules/avnu.ts +21 -12
- package/src/modules/ekubo-pricer.ts +79 -0
- package/src/modules/ekubo-quoter.ts +48 -30
- package/src/modules/erc20.ts +17 -0
- package/src/modules/harvests.ts +43 -29
- package/src/modules/index.ts +2 -1
- package/src/modules/pragma.ts +23 -8
- package/src/modules/pricer-avnu-api.ts +114 -0
- package/src/modules/pricer-from-api.ts +156 -15
- package/src/modules/pricer-lst.ts +1 -1
- package/src/modules/pricer.ts +94 -40
- package/src/modules/pricerBase.ts +2 -1
- package/src/node/deployer.ts +36 -1
- package/src/node/pricer-redis.ts +3 -1
- package/src/strategies/base-strategy.ts +168 -16
- package/src/strategies/constants.ts +8 -3
- package/src/strategies/ekubo-cl-vault.tsx +1047 -351
- package/src/strategies/factory.ts +199 -0
- package/src/strategies/index.ts +5 -3
- package/src/strategies/registry.ts +262 -0
- package/src/strategies/sensei.ts +353 -9
- package/src/strategies/svk-strategy.ts +283 -31
- package/src/strategies/token-boosted-xstrk-carry-strategy.tsx +1262 -0
- package/src/strategies/types.ts +4 -0
- package/src/strategies/universal-adapters/adapter-utils.ts +4 -1
- package/src/strategies/universal-adapters/avnu-adapter.ts +196 -272
- package/src/strategies/universal-adapters/baseAdapter.ts +263 -251
- package/src/strategies/universal-adapters/common-adapter.ts +206 -203
- package/src/strategies/universal-adapters/index.ts +10 -8
- package/src/strategies/universal-adapters/svk-troves-adapter.ts +511 -0
- package/src/strategies/universal-adapters/token-transfer-adapter.ts +200 -0
- package/src/strategies/universal-adapters/vesu-adapter.ts +120 -82
- package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +525 -0
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +1098 -712
- package/src/strategies/universal-adapters/vesu-position-common.ts +258 -0
- package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +18 -3
- package/src/strategies/universal-lst-muliplier-strategy.tsx +631 -414
- package/src/strategies/universal-strategy.tsx +1331 -1173
- package/src/strategies/vesu-rebalance.tsx +252 -152
- package/src/strategies/yoloVault.ts +1087 -0
- package/src/utils/cacheClass.ts +11 -2
- package/src/utils/health-factor-math.ts +33 -1
- package/src/utils/index.ts +3 -1
- package/src/utils/logger.browser.ts +22 -4
- package/src/utils/logger.node.ts +259 -24
- package/src/utils/starknet-call-parser.ts +1036 -0
- package/src/utils/strategy-utils.ts +61 -0
- package/src/modules/ExtendedWrapperSDk/index.ts +0 -62
- package/src/modules/ExtendedWrapperSDk/types.ts +0 -311
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +0 -395
- package/src/strategies/universal-adapters/extended-adapter.ts +0 -661
- package/src/strategies/universal-adapters/unused-balance-adapter.ts +0 -109
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +0 -34
- package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +0 -77
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +0 -49
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +0 -372
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +0 -1140
|
@@ -1,51 +1,74 @@
|
|
|
1
|
-
import { FAQ, getMainnetConfig, getNoRiskTags, highlightTextWithLinks, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, TokenInfo, VaultPosition } from "@/interfaces";
|
|
1
|
+
import { FAQ, getMainnetConfig, getNoRiskTags, highlightTextWithLinks, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, TokenInfo, VaultPosition, StrategyTag, AuditStatus, SourceCodeType, AccessControlType, InstantWithdrawalVault, StrategyLiveStatus, StrategySettings, VaultType, RedemptionInfo } from "@/interfaces";
|
|
2
2
|
import { AUMTypes, getContractDetails, UNIVERSAL_MANAGE_IDS, UniversalManageCall, UniversalStrategySettings } from "./universal-strategy";
|
|
3
3
|
import { PricerBase } from "@/modules/pricerBase";
|
|
4
4
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
5
5
|
import { Global } from "@/global";
|
|
6
|
-
import { ApproveCallParams, APYType, AvnuSwapCallParams, BaseAdapterConfig, CommonAdapter, ManageCall, PositionInfo,
|
|
6
|
+
import { ApproveCallParams, APYType, AvnuSwapCallParams, BaseAdapterConfig, CommonAdapter, ManageCall, PositionInfo, TokenTransferAdapter, VesuModifyPositionAdapter, VesuMultiplyAdapter, VesuPools, VesuSupplyOnlyAdapter } from "./universal-adapters";
|
|
7
7
|
import { AVNU_EXCHANGE } from "./universal-adapters/adapter-utils";
|
|
8
8
|
import { DepegRiskLevel, LiquidationRiskLevel, SmartContractRiskLevel, TechnicalRiskLevel } from "@/interfaces/risks";
|
|
9
|
-
import { AvnuWrapper, EkuboQuoter, ERC20, PricerFromApi, PricerLST } from "@/modules";
|
|
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
|
-
import { Call, uint256 } from "starknet";
|
|
13
|
+
import { Call, Contract, uint256 } from "starknet";
|
|
14
14
|
import ERC4626Abi from "@/data/erc4626.abi.json";
|
|
15
15
|
import { AdapterOptimizer } from "./universal-adapters/adapter-optimizer";
|
|
16
|
-
import {
|
|
17
|
-
import { VesuExtendedStrategySettings } from "./vesu-extended-strategy/vesu-extended-strategy";
|
|
16
|
+
import { LSTPriceType } from "./types";
|
|
18
17
|
|
|
19
18
|
export interface HyperLSTStrategySettings extends UniversalStrategySettings {
|
|
20
|
-
borrowable_assets: TokenInfo[];
|
|
19
|
+
borrowable_assets: { tokenInfo: TokenInfo, poolId: ContractAddr }[];
|
|
21
20
|
underlyingToken: TokenInfo;
|
|
22
21
|
quoteAmountToFetchPrice: Web3Number;
|
|
23
22
|
targetHealthFactor: number;
|
|
24
23
|
minHealthFactor: number;
|
|
25
24
|
aumOracle: ContractAddr;
|
|
25
|
+
adapterIds?: {
|
|
26
|
+
/** VesuMultiplyAdapter for underlying-matched debt (first matching borrowable pool) */
|
|
27
|
+
primaryMultiply: string;
|
|
28
|
+
multiply: Record<string, string>;
|
|
29
|
+
modify: Record<string, string>;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getHyperLSTAdapterKey(debtSymbol: string, poolId: ContractAddr): string {
|
|
34
|
+
return `${debtSymbol.toLowerCase()}_${poolId.shortString()}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getHyperLSTMultiplyAdapterId(
|
|
38
|
+
lstSymbol: string,
|
|
39
|
+
debtSymbol: string,
|
|
40
|
+
poolId: ContractAddr,
|
|
41
|
+
): string {
|
|
42
|
+
return `vesu_multiply_${lstSymbol.toLowerCase()}_${getHyperLSTAdapterKey(debtSymbol, poolId)}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getHyperLSTModifyAdapterId(
|
|
46
|
+
lstSymbol: string,
|
|
47
|
+
debtSymbol: string,
|
|
48
|
+
poolId: ContractAddr,
|
|
49
|
+
): string {
|
|
50
|
+
return `vesu_modify_${lstSymbol.toLowerCase()}_${getHyperLSTAdapterKey(debtSymbol, poolId)}`;
|
|
26
51
|
}
|
|
27
52
|
|
|
28
53
|
export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings> extends SVKStrategy<S> {
|
|
29
54
|
|
|
30
55
|
private quoteAmountToFetchPrice = new Web3Number(1, 18);
|
|
31
|
-
|
|
56
|
+
|
|
32
57
|
constructor(config: IConfig, pricer: PricerBase, metadata: IStrategyMetadata<S>) {
|
|
33
58
|
super(config, pricer, metadata);
|
|
34
59
|
const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
|
|
35
60
|
const underlyingToken = this.getLSTUnderlyingTokenInfo();
|
|
36
|
-
if (
|
|
37
|
-
this.quoteAmountToFetchPrice
|
|
38
|
-
} else {
|
|
39
|
-
// else this BTC
|
|
40
|
-
this.quoteAmountToFetchPrice = new Web3Number(0.01, this.asset().decimals);
|
|
61
|
+
if (metadata.additionalInfo.quoteAmountToFetchPrice.isZero()) {
|
|
62
|
+
throw new Error(`${this.getTag()}::quoteAmountToFetchPrice is zero`);
|
|
41
63
|
}
|
|
64
|
+
this.quoteAmountToFetchPrice = metadata.additionalInfo.quoteAmountToFetchPrice;
|
|
42
65
|
|
|
43
66
|
this.metadata.additionalInfo.adapters.forEach(adapter => {
|
|
44
67
|
adapter.adapter.config.networkConfig = this.config;
|
|
45
68
|
adapter.adapter.config.pricer = this.pricer;
|
|
46
|
-
if ((adapter.adapter as
|
|
47
|
-
(adapter.adapter as
|
|
48
|
-
(adapter.adapter as
|
|
69
|
+
if ((adapter.adapter as any)._vesuAdapter) {
|
|
70
|
+
(adapter.adapter as any)._vesuAdapter.networkConfig = this.config;
|
|
71
|
+
(adapter.adapter as any)._vesuAdapter.pricer = this.pricer;
|
|
49
72
|
}
|
|
50
73
|
});
|
|
51
74
|
}
|
|
@@ -54,13 +77,36 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
54
77
|
return `${UniversalLstMultiplierStrategy.name}:${this.metadata.name}`;
|
|
55
78
|
}
|
|
56
79
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
private getAdapterById<T>(id: string): T {
|
|
81
|
+
const entry = this.metadata.additionalInfo.adapters.find((a) => a.id === id);
|
|
82
|
+
if (!entry) {
|
|
83
|
+
throw new Error(`${this.getTag()}::getAdapterById: adapter not found for id "${id}"`);
|
|
84
|
+
}
|
|
85
|
+
return entry.adapter as T;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getVesuMultiplyAdapterByKey(key: string): VesuMultiplyAdapter {
|
|
89
|
+
const id = this.metadata.additionalInfo.adapterIds?.multiply[key];
|
|
90
|
+
if (!id) {
|
|
91
|
+
throw new Error(`${this.getTag()}::getVesuMultiplyAdapterByKey: unknown key "${key}"`);
|
|
92
|
+
}
|
|
93
|
+
return this.getAdapterById<VesuMultiplyAdapter>(id);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Vesu multiply adapter whose debt matches the LST underlying (e.g. STRK for xSTRK)
|
|
97
|
+
getVesuSameTokenAdapter(): VesuMultiplyAdapter {
|
|
98
|
+
const primaryId = this.metadata.additionalInfo.adapterIds?.primaryMultiply;
|
|
99
|
+
if (primaryId) {
|
|
100
|
+
const adapter = this.getAdapterById<VesuMultiplyAdapter>(primaryId);
|
|
101
|
+
adapter.config.networkConfig = this.config;
|
|
102
|
+
adapter.config.pricer = this.pricer;
|
|
103
|
+
adapter._vesuAdapter.networkConfig = this.config;
|
|
104
|
+
adapter._vesuAdapter.pricer = this.pricer;
|
|
105
|
+
return adapter;
|
|
106
|
+
}
|
|
107
|
+
const baseAdapter = this.getVesuMultiplyAdapters().find((adapter) =>
|
|
108
|
+
adapter.config.debt.address.eq(this.metadata.additionalInfo.underlyingToken.address),
|
|
109
|
+
);
|
|
64
110
|
if (!baseAdapter) {
|
|
65
111
|
throw new Error(`${this.getTag()}::getVesuSameTokenAdapter: base adapter not found`);
|
|
66
112
|
}
|
|
@@ -71,10 +117,10 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
71
117
|
|
|
72
118
|
// only one leg is used
|
|
73
119
|
// todo support lending assets of underlying as well (like if xSTRK looping is not viable, simply supply STRK)
|
|
74
|
-
|
|
120
|
+
getVesuMultiplyAdapters() {
|
|
75
121
|
const vesuMultipleAdapters = this.metadata.additionalInfo.adapters
|
|
76
|
-
|
|
77
|
-
|
|
122
|
+
.filter(adapter => adapter.adapter.name === VesuMultiplyAdapter.name)
|
|
123
|
+
.map(adapter => adapter.adapter) as VesuMultiplyAdapter[]
|
|
78
124
|
|
|
79
125
|
for (const vesuAdapter of vesuMultipleAdapters) {
|
|
80
126
|
vesuAdapter.config.pricer = this.pricer;
|
|
@@ -83,6 +129,82 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
83
129
|
return vesuMultipleAdapters;
|
|
84
130
|
}
|
|
85
131
|
|
|
132
|
+
async getRewardsAUM(_prevAum: Web3Number) {
|
|
133
|
+
const lstToken = this.asset();
|
|
134
|
+
// Defi spring rewards handling; currently returns 0 as SVKStrategy has no built-in rewards logic
|
|
135
|
+
return Web3Number.fromWei("0", lstToken.decimals);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async getLSTAvnuRate() {
|
|
139
|
+
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
140
|
+
const lstTokenInfo = vesuAdapter1._vesuAdapter.config.collateral;
|
|
141
|
+
const underlyingTokenInfo = vesuAdapter1._vesuAdapter.config.debt;
|
|
142
|
+
|
|
143
|
+
const avnuModule = new AvnuWrapper();
|
|
144
|
+
|
|
145
|
+
const sellAmount = (lstTokenInfo as any).priceCheckAmount
|
|
146
|
+
? new Web3Number(
|
|
147
|
+
(lstTokenInfo as any).priceCheckAmount,
|
|
148
|
+
underlyingTokenInfo.decimals,
|
|
149
|
+
)
|
|
150
|
+
: new Web3Number(1, underlyingTokenInfo.decimals);
|
|
151
|
+
|
|
152
|
+
const quote = await avnuModule.getQuotes(
|
|
153
|
+
underlyingTokenInfo.address.address,
|
|
154
|
+
lstTokenInfo.address.address,
|
|
155
|
+
sellAmount.toWei(),
|
|
156
|
+
this.metadata.additionalInfo.vaultAllocator.address,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const underlyingAmountNumber = sellAmount.toNumber();
|
|
160
|
+
const lstAmountNumber = Web3Number.fromWei(
|
|
161
|
+
quote.buyAmount.toString(),
|
|
162
|
+
lstTokenInfo.decimals,
|
|
163
|
+
).toNumber();
|
|
164
|
+
|
|
165
|
+
assert(lstAmountNumber > 0, "Avnu LST amount is zero");
|
|
166
|
+
|
|
167
|
+
const exchangeRate = underlyingAmountNumber / lstAmountNumber;
|
|
168
|
+
logger.verbose(
|
|
169
|
+
`${this.getTag()}:: LST Avnu Exchange Rate: ${exchangeRate}`,
|
|
170
|
+
);
|
|
171
|
+
return exchangeRate;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async getLSTExchangeRate() {
|
|
175
|
+
const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
176
|
+
const lstTokenInfo = vesuAdapter1._vesuAdapter.config.collateral;
|
|
177
|
+
const lstABI = new Contract({
|
|
178
|
+
abi: ERC4626Abi,
|
|
179
|
+
address: lstTokenInfo.address.address,
|
|
180
|
+
providerOrAccount: this.config.provider,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const price: any = await lstABI.call("convert_to_assets", [
|
|
184
|
+
uint256.bnToUint256(new Web3Number(1, lstTokenInfo.decimals).toWei()),
|
|
185
|
+
]);
|
|
186
|
+
const exchangeRate =
|
|
187
|
+
Number(uint256.uint256ToBN(price).toString()) /
|
|
188
|
+
Math.pow(10, lstTokenInfo.decimals);
|
|
189
|
+
logger.verbose(`${this.getTag()}:: LST Exchange Rate: ${exchangeRate}`);
|
|
190
|
+
return exchangeRate;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private async _getMinOutputAmountLSTBuy(amountInUnderlying: Web3Number) {
|
|
194
|
+
const lstTruePrice = await this.getLSTExchangeRate();
|
|
195
|
+
const minOutputAmount = amountInUnderlying
|
|
196
|
+
.dividedBy(lstTruePrice)
|
|
197
|
+
.multipliedBy(0.99979);
|
|
198
|
+
return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private async _getMinOutputAmountLSTSell(amountInLST: Web3Number) {
|
|
202
|
+
const lstTruePrice = await this.getLSTExchangeRate();
|
|
203
|
+
const minOutputAmount = amountInLST
|
|
204
|
+
.multipliedBy(lstTruePrice)
|
|
205
|
+
.multipliedBy(0.995);
|
|
206
|
+
return minOutputAmount;
|
|
207
|
+
}
|
|
86
208
|
|
|
87
209
|
// async getAvnuSwapMultiplyCall(params: {
|
|
88
210
|
// isDeposit: boolean,
|
|
@@ -132,7 +254,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
132
254
|
|
|
133
255
|
// async _getAvnuDepositSwapLegCall(params: {
|
|
134
256
|
// isDeposit: boolean,
|
|
135
|
-
// leg1DepositAmount: Web3Number,
|
|
257
|
+
// leg1DepositAmount: Web3Number,
|
|
136
258
|
// minHF: number, // e.g. 1.01
|
|
137
259
|
// vesuAdapter: VesuAdapter
|
|
138
260
|
// }) {
|
|
@@ -144,18 +266,18 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
144
266
|
// // approve and swap strk
|
|
145
267
|
// // add collateral again
|
|
146
268
|
|
|
147
|
-
|
|
269
|
+
|
|
148
270
|
// const legLTV = await vesuAdapter.getLTVConfig(this.config);
|
|
149
271
|
// logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall legLTV: ${legLTV}`);
|
|
150
272
|
// const existingPositions = await vesuAdapter.getPositions(this.config);
|
|
151
273
|
// const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
152
274
|
// const existingCollateralInfo = existingPositions[0];
|
|
153
275
|
// const existingDebtInfo = existingPositions[1];
|
|
154
|
-
// logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
276
|
+
// logger.debug(`${this.getTag()}::_getAvnuDepositSwapLegCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
155
277
|
// existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
156
278
|
|
|
157
279
|
// // - Prices as seen by Vesu contracts, ideal for HF math
|
|
158
|
-
// // Price 1 is ok as fallback bcz that would relatively price the
|
|
280
|
+
// // Price 1 is ok as fallback bcz that would relatively price the
|
|
159
281
|
// // collateral and debt as equal.
|
|
160
282
|
// const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
161
283
|
// const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
@@ -202,7 +324,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
202
324
|
|
|
203
325
|
// logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall debtAmount: ${debtAmount}`);
|
|
204
326
|
// if (debtAmount.lt(0)) {
|
|
205
|
-
// // this is to unwind the position to optimal HF.
|
|
327
|
+
// // this is to unwind the position to optimal HF.
|
|
206
328
|
// const lstDEXPrice = await this.getLSTDexPrice();
|
|
207
329
|
// const debtAmountInLST = debtAmount.abs().dividedBy(lstDEXPrice);
|
|
208
330
|
// const calls = await this.getVesuMultiplyCall({
|
|
@@ -228,7 +350,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
228
350
|
// }));
|
|
229
351
|
|
|
230
352
|
// console.log(`manageCall1`, manageCall1.call, debtAmount.toWei(), newDepositAmount.toWei());
|
|
231
|
-
|
|
353
|
+
|
|
232
354
|
// const proofIds: string[] = [STEP0, STEP1];
|
|
233
355
|
// const manageCalls: ManageCall[] = [manageCall0, manageCall1];
|
|
234
356
|
|
|
@@ -253,9 +375,9 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
253
375
|
// const minAmountWei = (minAmount).toWei();
|
|
254
376
|
// logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall minAmount: ${minAmount}`);
|
|
255
377
|
// const swapInfo = await avnuModule.getSwapInfo(
|
|
256
|
-
// quote,
|
|
257
|
-
// this.metadata.additionalInfo.vaultAllocator.address,
|
|
258
|
-
// 0,
|
|
378
|
+
// quote,
|
|
379
|
+
// this.metadata.additionalInfo.vaultAllocator.address,
|
|
380
|
+
// 0,
|
|
259
381
|
// this.address.address,
|
|
260
382
|
// minAmountWei
|
|
261
383
|
// );
|
|
@@ -271,7 +393,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
271
393
|
|
|
272
394
|
|
|
273
395
|
// // if the created debt, when added is collateral will put the total HF above min, but below (target + 0.05),
|
|
274
|
-
// // then lets close the looping cycle by adding this as collateral.
|
|
396
|
+
// // then lets close the looping cycle by adding this as collateral.
|
|
275
397
|
// const newCollateral = minAmount.plus(totalCollateral);
|
|
276
398
|
// const newHF = newCollateral.multipliedBy(collateralPrice).multipliedBy(legLTV).dividedBy(totalDebtAmount).dividedBy(debtPrice).toNumber();
|
|
277
399
|
// logger.verbose(`${this.getTag()}::_getAvnuDepositSwapLegCall newHF: ${newHF}`);
|
|
@@ -283,7 +405,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
283
405
|
// const manageCall4 = manage4Info.callConstructor({
|
|
284
406
|
// amount: minAmount
|
|
285
407
|
// });
|
|
286
|
-
|
|
408
|
+
|
|
287
409
|
// const STEP5 = getVesuLegId(UNIVERSAL_MANAGE_IDS.VESU_LEG1, vesuAdapter.config.debt.symbol);
|
|
288
410
|
// const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP5);
|
|
289
411
|
// const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
@@ -301,7 +423,7 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
301
423
|
// return manageCall;
|
|
302
424
|
// }
|
|
303
425
|
|
|
304
|
-
// todo unwind or not deposit when the yield is bad.
|
|
426
|
+
// todo unwind or not deposit when the yield is bad.
|
|
305
427
|
|
|
306
428
|
// async getLSTMultiplierRebalanceCall(): Promise<{ shouldRebalance: boolean, manageCalls: {vesuAdapter: VesuAdapter, manageCall: Call}[] }> {
|
|
307
429
|
// let shouldRebalance = false;
|
|
@@ -327,11 +449,11 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
327
449
|
// const healthFactor = await vesuAdapter.getHealthFactor();
|
|
328
450
|
|
|
329
451
|
// const collateralisation = await vesuAdapter.getCollateralization(this.config);
|
|
330
|
-
// logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
452
|
+
// logger.debug(`${this.getTag()}::getVesuMultiplyCall::${vesuAdapter.config.debt.symbol} existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
331
453
|
// existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
332
454
|
|
|
333
455
|
// // - Prices as seen by Vesu contracts, ideal for HF math
|
|
334
|
-
// // Price 1 is ok as fallback bcz that would relatively price the
|
|
456
|
+
// // Price 1 is ok as fallback bcz that would relatively price the
|
|
335
457
|
// // collateral and debt as equal.
|
|
336
458
|
// const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
337
459
|
// const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
@@ -341,11 +463,11 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
341
463
|
// const isHFTooLow = healthFactor < this.metadata.additionalInfo.minHealthFactor;
|
|
342
464
|
// const isHFTooHigh = healthFactor > this.metadata.additionalInfo.targetHealthFactor + 0.05;
|
|
343
465
|
// if (isHFTooLow || isHFTooHigh || 1) {
|
|
344
|
-
// // use unused collateral to target more.
|
|
466
|
+
// // use unused collateral to target more.
|
|
345
467
|
// const manageCall = await this._getAvnuDepositSwapLegCall({
|
|
346
468
|
// isDeposit: true,
|
|
347
469
|
// leg1DepositAmount: unusedBalance.amount,
|
|
348
|
-
// minHF: 1.02, // todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
470
|
+
// minHF: 1.02, // todo, shouldnt use this 1.02 HF, if there isn;t more looping left.
|
|
349
471
|
// vesuAdapter
|
|
350
472
|
// })
|
|
351
473
|
// return { shouldRebalance: true, manageCall };
|
|
@@ -355,61 +477,17 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
355
477
|
// }
|
|
356
478
|
// }
|
|
357
479
|
|
|
358
|
-
// protected async getVesuAUM(adapter: VesuAdapter) {
|
|
359
|
-
// const legAUM = await adapter.getPositions(this.config);
|
|
360
|
-
// const underlying = this.asset();
|
|
361
|
-
// // assert its an LST of Endur
|
|
362
|
-
// assert(underlying.symbol.startsWith('x'), 'Underlying is not an LST of Endur');
|
|
363
|
-
|
|
364
|
-
// let vesuAum = Web3Number.fromWei("0", underlying.decimals);
|
|
365
|
-
|
|
366
|
-
// let tokenUnderlyingPrice = await this.getLSTExchangeRate();
|
|
367
|
-
// // to offset for usual DEX lag, we multiply by 0.998 (i.e. 0.2% loss)
|
|
368
|
-
// tokenUnderlyingPrice = tokenUnderlyingPrice * 0.998;
|
|
369
|
-
// logger.verbose(`${this.getTag()} tokenUnderlyingPrice: ${tokenUnderlyingPrice}`);
|
|
370
|
-
|
|
371
|
-
// // handle collateral
|
|
372
|
-
// if (legAUM[0].token.address.eq(underlying.address)) {
|
|
373
|
-
// vesuAum = vesuAum.plus(legAUM[0].amount);
|
|
374
|
-
// } else {
|
|
375
|
-
// vesuAum = vesuAum.plus(legAUM[0].amount.dividedBy(tokenUnderlyingPrice));
|
|
376
|
-
// }
|
|
377
|
-
|
|
378
|
-
// // handle debt
|
|
379
|
-
// if (legAUM[1].token.address.eq(underlying.address)) {
|
|
380
|
-
// vesuAum = vesuAum.minus(legAUM[1].amount);
|
|
381
|
-
// } else {
|
|
382
|
-
// vesuAum = vesuAum.minus(legAUM[1].amount.dividedBy(tokenUnderlyingPrice));
|
|
383
|
-
// };
|
|
384
|
-
|
|
385
|
-
// logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
|
|
386
|
-
// return vesuAum;
|
|
387
|
-
// }
|
|
388
480
|
|
|
389
|
-
//
|
|
390
|
-
// private async _getMinOutputAmountLSTBuy(amountInUnderlying: Web3Number) {
|
|
391
|
-
// const lstTruePrice = await this.getLSTExchangeRate();
|
|
392
|
-
// // during buy, the purchase should always be <= true LST price.
|
|
393
|
-
// const minOutputAmount = amountInUnderlying.dividedBy(lstTruePrice).multipliedBy(0.99979); // minus 0.021% to account for avnu fees
|
|
394
|
-
// return new Web3Number(minOutputAmount.toString(), this.asset().decimals);
|
|
395
|
-
// }
|
|
396
|
-
|
|
397
|
-
// private async _getMinOutputAmountLSTSell(amountInLST: Web3Number) {
|
|
398
|
-
// const lstTruePrice = await this.getLSTExchangeRate();
|
|
399
|
-
// // during sell, the purchase should always be > 0.995 * true LST price.
|
|
400
|
-
// const minOutputAmount = amountInLST.multipliedBy(lstTruePrice).multipliedBy(0.995);
|
|
401
|
-
// return minOutputAmount;
|
|
402
|
-
// }
|
|
403
481
|
|
|
404
482
|
|
|
405
483
|
|
|
406
484
|
// todo add a function to findout max borrowable amount without fucking yield
|
|
407
|
-
// if the current net yield < LST yield, add a function to calculate how much to unwind.
|
|
485
|
+
// if the current net yield < LST yield, add a function to calculate how much to unwind.
|
|
408
486
|
|
|
409
487
|
/**
|
|
410
488
|
* Uses vesu's multiple call to create leverage on LST
|
|
411
489
|
* Deposit amount is in LST
|
|
412
|
-
* @param params
|
|
490
|
+
* @param params
|
|
413
491
|
*/
|
|
414
492
|
async getFundManagementCall(params: {
|
|
415
493
|
isDeposit: boolean,
|
|
@@ -418,268 +496,258 @@ export class UniversalLstMultiplierStrategy<S extends HyperLSTStrategySettings>
|
|
|
418
496
|
logger.verbose(`${this.getTag()}::getFundManagementCall params: ${JSON.stringify(params)}`);
|
|
419
497
|
// const legLTV = await vesuAdapter1.getLTVConfig(this.config);
|
|
420
498
|
// logger.verbose(`${this.getTag()}::getVesuMultiplyCall legLTV: ${legLTV}`);
|
|
421
|
-
const
|
|
499
|
+
const multiplyAdapters = this.getVesuMultiplyAdapters();
|
|
422
500
|
if (!params.isDeposit) {
|
|
423
|
-
// try using unused balance to unwind.
|
|
424
|
-
// no need to unwind.
|
|
501
|
+
// try using unused balance to unwind.
|
|
502
|
+
// no need to unwind.
|
|
425
503
|
const unusedBalance = await this.getUnusedBalance();
|
|
426
504
|
logger.verbose(`${this.getTag()}::getVesuMultiplyCall unusedBalance: ${unusedBalance.amount.toString()}, required: ${params.leg1DepositAmount.toString()}`);
|
|
427
505
|
if (unusedBalance.amount.gte(params.leg1DepositAmount)) {
|
|
428
506
|
return null;
|
|
429
|
-
} else {
|
|
430
|
-
const adapters = await AdapterOptimizer.getAdapterToUse(allAdapters, false, params.leg1DepositAmount);
|
|
431
|
-
if (adapters.length > 0) {
|
|
432
|
-
const proofsInfo = adapters.map(adapter => adapter.getProofs(false, this.getMerkleTree()));
|
|
433
|
-
const calls: Call[] = [];
|
|
434
|
-
for (const info of proofsInfo) {
|
|
435
|
-
const proofGroups = info.proofs;
|
|
436
|
-
const call = this.getManageCall(proofGroups, await info.callConstructor({amount: params.leg1DepositAmount}));
|
|
437
|
-
calls.push(call);
|
|
438
|
-
}
|
|
439
|
-
return calls;
|
|
440
|
-
} else {
|
|
441
|
-
throw new Error(`${this.getTag()}::getVesuMultiplyCall: no adapters to use for unused balance: ${unusedBalance.amount.toString()}`);
|
|
442
|
-
}
|
|
443
507
|
}
|
|
444
508
|
}
|
|
445
509
|
|
|
446
|
-
const adapters = await AdapterOptimizer.getAdapterToUse(
|
|
510
|
+
const adapters = await AdapterOptimizer.getAdapterToUse(multiplyAdapters, params.isDeposit, params.leg1DepositAmount);
|
|
447
511
|
if (adapters.length > 0) {
|
|
448
|
-
const proofsInfo = adapters.map(adapter => adapter.getProofs(
|
|
512
|
+
const proofsInfo = adapters.map(adapter => adapter.getProofs(params.isDeposit, this.getMerkleTree()));
|
|
449
513
|
const calls: Call[] = [];
|
|
450
514
|
for (const info of proofsInfo) {
|
|
451
|
-
const
|
|
452
|
-
const call = this.getManageCall(
|
|
515
|
+
const manageCalls = await info.callConstructor({ amount: params.leg1DepositAmount });
|
|
516
|
+
const call = this.getManageCall(this.getProofGroupsForManageCalls(manageCalls), manageCalls);
|
|
453
517
|
calls.push(call);
|
|
454
518
|
}
|
|
455
519
|
return calls;
|
|
456
520
|
} else {
|
|
457
521
|
throw new Error(`${this.getTag()}::getVesuMultiplyCall: no adapters to use for deposit: ${params.leg1DepositAmount.toString()}`);
|
|
458
522
|
}
|
|
459
|
-
|
|
460
|
-
// const existingPositions = await vesuAdapter1.getPositions(this.config);
|
|
461
|
-
// const collateralisation = await vesuAdapter1.getCollateralization(this.config);
|
|
462
|
-
// const existingCollateralInfo = existingPositions[0];
|
|
463
|
-
// const existingDebtInfo = existingPositions[1];
|
|
464
|
-
// logger.debug(`${this.getTag()}::getVesuMultiplyCall existingCollateralInfo: ${JSON.stringify(existingCollateralInfo)},
|
|
465
|
-
// existingDebtInfo: ${JSON.stringify(existingDebtInfo)}, collateralisation: ${JSON.stringify(collateralisation)}`);
|
|
466
|
-
|
|
467
|
-
// // - Prices as seen by Vesu contracts, ideal for HF math
|
|
468
|
-
// // Price 1 is ok as fallback bcz that would relatively price the
|
|
469
|
-
// // collateral and debt as equal.
|
|
470
|
-
// const collateralPrice = collateralisation[0].usdValue > 0 ? collateralisation[0].usdValue / existingCollateralInfo.amount.toNumber() : 1;
|
|
471
|
-
// const debtPrice = collateralisation[1].usdValue > 0 ? collateralisation[1].usdValue / existingDebtInfo.amount.toNumber() : 1;
|
|
472
|
-
// logger.debug(`${this.getTag()}::getVesuMultiplyCall collateralPrice: ${collateralPrice}, debtPrice: ${debtPrice}`);
|
|
473
|
-
|
|
474
|
-
// // - Prices as seen by actual swap price
|
|
475
|
-
// const dexPrice = await this.getLSTDexPrice();
|
|
476
|
-
|
|
477
|
-
// // compute optimal amount of collateral and debt post addition/removal
|
|
478
|
-
// // target hf = collateral * collateralPrice * ltv / debt * debtPrice
|
|
479
|
-
// // assuming X to be the usd amount of debt borrowed or repaied (negative).
|
|
480
|
-
// // target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv / (debt * debtPrice + X)
|
|
481
|
-
// // => X * target hf = (((collateral + legDepositAmount) * collateralPrice + X)) * ltv - (debt * debtPrice * target hf)
|
|
482
|
-
// // => X * (target hf - ltv)= ((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)
|
|
483
|
-
// // => X = (((collateral + legDepositAmount) * collateralPrice * ltv) - (debt * debtPrice * target hf)) / (target hf - ltv)
|
|
484
|
-
// const addedCollateral = params.leg1DepositAmount
|
|
485
|
-
// .multipliedBy(params.isDeposit ? 1 : -1)
|
|
486
|
-
// logger.verbose(`${this.getTag()}::getVesuMultiplyCall addedCollateral: ${addedCollateral}`);
|
|
487
|
-
// const numeratorPart1 = (existingCollateralInfo.amount.plus((addedCollateral))).multipliedBy(collateralPrice).multipliedBy(legLTV);
|
|
488
|
-
// logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}`);
|
|
489
|
-
// const numeratorPart2 = existingDebtInfo.amount.multipliedBy(debtPrice).multipliedBy(this.metadata.additionalInfo.targetHealthFactor);
|
|
490
|
-
// logger.verbose(`${this.getTag()}::getVesuMultiplyCall numeratorPart2: ${numeratorPart2}`);
|
|
491
|
-
// const denominatorPart = this.metadata.additionalInfo.targetHealthFactor - (legLTV / dexPrice);
|
|
492
|
-
// logger.verbose(`${this.getTag()}::getVesuMultiplyCall denominatorPart: ${denominatorPart}`);
|
|
493
|
-
// const x_debt_usd = numeratorPart1.minus(numeratorPart2).dividedBy(denominatorPart);
|
|
494
|
-
// logger.verbose(`${this.getTag()}::getVesuMultiplyCall x_debt_usd: ${x_debt_usd}`);
|
|
495
|
-
// logger.debug(`${this.getTag()}::getVesuMultiplyCall numeratorPart1: ${numeratorPart1}, numeratorPart2: ${numeratorPart2}, denominatorPart: ${denominatorPart}`);
|
|
496
|
-
|
|
497
|
-
// // both in underlying
|
|
498
|
-
// const debtAmount = x_debt_usd.dividedBy(debtPrice);
|
|
499
|
-
// const marginAmount = addedCollateral;
|
|
500
|
-
// logger.verbose(`${this.getTag()}::getVesuMultiplyCall debtAmount: ${debtAmount}, marginAmount: ${marginAmount}`);
|
|
501
|
-
|
|
502
|
-
// // Cases of lever increase (within the scopr of this function)
|
|
503
|
-
// // 1. debtAmount > 0 and marginAmount > 0
|
|
504
|
-
// // 2. debtAmount > 0 and marginAmount < 0
|
|
505
|
-
|
|
506
|
-
// // Cases of lever decrease
|
|
507
|
-
// // 3. debtAmount < 0 and marginAmount > 0
|
|
508
|
-
// // 4. debtAmount < 0 and marginAmount < 0
|
|
509
|
-
// return this.getModifyLeverCall({
|
|
510
|
-
// marginAmount,
|
|
511
|
-
// debtAmount,
|
|
512
|
-
// lstDexPriceInUnderlying: dexPrice,
|
|
513
|
-
// isIncrease: debtAmount.greaterThan(0)
|
|
514
|
-
// });
|
|
515
523
|
}
|
|
516
524
|
|
|
517
|
-
|
|
518
525
|
getLSTUnderlyingTokenInfo() {
|
|
519
526
|
return this.metadata.additionalInfo.underlyingToken;
|
|
520
527
|
}
|
|
521
528
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
529
|
+
async getLSTAPR(_address: ContractAddr): Promise<number> {
|
|
530
|
+
try {
|
|
531
|
+
const apr = await LSTAPRService.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
532
|
+
if (!apr) {
|
|
533
|
+
throw new Error('Failed to get LST APR');
|
|
534
|
+
}
|
|
535
|
+
return apr;
|
|
536
|
+
} catch (error) {
|
|
537
|
+
logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
|
|
538
|
+
return 0;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
533
541
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
542
|
+
async netAPY(): Promise<{
|
|
543
|
+
net: number;
|
|
544
|
+
splits: { apy: number; id: string }[];
|
|
545
|
+
}> {
|
|
546
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
547
|
+
const maxDeposits = await this.maxNewDeposits({ isAPYComputation: true });
|
|
548
|
+
const lstAPY = await this.getLSTAPR(this.getLSTUnderlyingTokenInfo().address);
|
|
549
|
+
|
|
550
|
+
if (maxDeposits * 1.5 < unusedBalance.amount.toNumber()) {
|
|
551
|
+
logger.verbose(
|
|
552
|
+
`${this.getTag()}::netAPY: unused balance is > max servicable from loan, lstAPY: ${lstAPY}`,
|
|
553
|
+
);
|
|
554
|
+
// TODO, need to add the unused balance APY
|
|
555
|
+
const output = await super.netAPY();
|
|
556
|
+
output.splits.push({ apy: lstAPY, id: "lst_apy" });
|
|
557
|
+
return output;
|
|
558
|
+
} else {
|
|
559
|
+
logger.verbose(
|
|
560
|
+
`${this.getTag()}::netAPY: we can take more deposits, use theoretical max APY`,
|
|
561
|
+
);
|
|
562
|
+
const output = await super.netAPY();
|
|
563
|
+
output.splits.push({ apy: lstAPY, id: "lst_apy" });
|
|
564
|
+
return output;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
551
567
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
568
|
+
async maxNewDeposits(
|
|
569
|
+
params: { isAPYComputation: boolean } = { isAPYComputation: false },
|
|
570
|
+
) {
|
|
571
|
+
let numerator = 0;
|
|
572
|
+
for (let adapter of this.getVesuMultiplyAdapters()) {
|
|
573
|
+
const maxDepositInfo = await adapter.maxDeposit();
|
|
574
|
+
numerator += maxDepositInfo.amount.toNumber();
|
|
575
|
+
}
|
|
576
|
+
return numerator;
|
|
577
|
+
}
|
|
557
578
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
// } catch (error) {
|
|
568
|
-
// logger.warn(`${this.getTag()}: Failed to get max swappable: ${error}`);
|
|
569
|
-
// const maxSwappable = Web3Number.fromWei("0", vesuAdapter.config.debt.decimals);
|
|
570
|
-
// return {amount: maxBorrowable.minimum(maxSwappable), dexSwappableAmount: maxSwappable, maxBorrowableAmount: maxBorrowable, borrowableAsset: vesuAdapter.config.debt};
|
|
571
|
-
// }
|
|
572
|
-
// }
|
|
579
|
+
protected async getUnusedBalanceAPY() {
|
|
580
|
+
const unusedBalance = await this.getUnusedBalance();
|
|
581
|
+
const underlying = this.getLSTUnderlyingTokenInfo();
|
|
582
|
+
const lstAPY = await this.getLSTAPR(underlying.address);
|
|
583
|
+
return {
|
|
584
|
+
apy: lstAPY,
|
|
585
|
+
weight: unusedBalance.usdValue,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
573
588
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
// /**
|
|
579
|
-
// * Gets LST APR for the strategy's underlying asset from Endur API
|
|
580
|
-
// * @returns Promise<number> The LST APR (not divided by 1e18)
|
|
581
|
-
// */
|
|
582
|
-
// async getLSTAPR(_address: ContractAddr): Promise<number> {
|
|
583
|
-
// try {
|
|
584
|
-
// const vesuAdapter1 = this.getVesuSameTokenAdapter();
|
|
585
|
-
// const apr = await LSTAPRService.getLSTAPR(vesuAdapter1.config.debt.address);
|
|
586
|
-
// if (!apr) {
|
|
587
|
-
// throw new Error('Failed to get LST APR');
|
|
588
|
-
// }
|
|
589
|
-
// return apr;
|
|
590
|
-
// } catch (error) {
|
|
591
|
-
// logger.warn(`${this.getTag()}: Failed to get LST APR: ${error}`);
|
|
592
|
-
// return 0;
|
|
593
|
-
// }
|
|
594
|
-
// }
|
|
589
|
+
async getAUM(unrealizedAUM: boolean = false): Promise<{ net: SingleTokenInfo, prevAum: Web3Number, splits: PositionInfo[] }> {
|
|
590
|
+
const underlying = this.asset();
|
|
591
|
+
assert(underlying.symbol.startsWith('x'), 'Underlying is not an LST of Endur');
|
|
595
592
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
// // for simplicity, we assume 1 underlying = 1 LST
|
|
616
|
-
// const numerator = this.metadata.additionalInfo.targetHealthFactor * maxBorrowableAmounts.netMaxBorrowableAmount.toNumber() / (ltv)
|
|
617
|
-
// return numerator - maxBorrowableAmounts.netMaxBorrowableAmount.toNumber();
|
|
618
|
-
// }
|
|
593
|
+
// dynamic computation of aum based on price type
|
|
594
|
+
const priceType = unrealizedAUM ? LSTPriceType.ENDUR_PRICE : LSTPriceType.AVNU_PRICE;
|
|
595
|
+
|
|
596
|
+
// get dex rate
|
|
597
|
+
let tokenUnderlyingPrice: number;
|
|
598
|
+
const avnuRate = await this.getLSTAvnuRate();
|
|
599
|
+
if (avnuRate === 0) {
|
|
600
|
+
throw new Error(`${this.getTag()}::getAUM: tokenUnderlyingPrice (Avnu) is 0`);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// get token underlying price
|
|
604
|
+
if (priceType === LSTPriceType.ENDUR_PRICE) {
|
|
605
|
+
tokenUnderlyingPrice = await this.getLSTExchangeRate();
|
|
606
|
+
if (tokenUnderlyingPrice === 0) {
|
|
607
|
+
throw new Error(`${this.getTag()}::getAUM: tokenUnderlyingPrice (Endur) is 0`);
|
|
608
|
+
}
|
|
609
|
+
} else {
|
|
610
|
+
tokenUnderlyingPrice = avnuRate;
|
|
611
|
+
}
|
|
619
612
|
|
|
620
|
-
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
613
|
+
// check if endur and avnu prices differ by more than 2%
|
|
614
|
+
const diff = Math.abs(tokenUnderlyingPrice - avnuRate) / tokenUnderlyingPrice;
|
|
615
|
+
if (diff > 0.02) {
|
|
616
|
+
throw new Error(
|
|
617
|
+
`${this.getTag()}::getAUM: Endur and Avnu prices differ by more than 2% (Endur: ${tokenUnderlyingPrice}, Avnu: ${avnuRate})`,
|
|
618
|
+
);
|
|
625
619
|
}
|
|
626
620
|
|
|
627
|
-
|
|
628
|
-
|
|
621
|
+
// get all positions
|
|
622
|
+
const allPositions = await this.getVaultPositions();
|
|
623
|
+
|
|
624
|
+
// compute net aum
|
|
625
|
+
let netAUM = new Web3Number(0, underlying.decimals);
|
|
629
626
|
for (let position of allPositions) {
|
|
630
|
-
if (position.
|
|
627
|
+
if (position.token.address.eq(underlying.address)) {
|
|
631
628
|
netAUM = netAUM.plus(position.amount);
|
|
629
|
+
} else if (position.token.address.eq(this.getLSTUnderlyingTokenInfo().address)) {
|
|
630
|
+
netAUM = netAUM.plus(position.amount.dividedBy(tokenUnderlyingPrice));
|
|
632
631
|
} else {
|
|
633
|
-
|
|
632
|
+
throw new Error(`${this.getTag()}::getAUM: unknown token: ${position.token.symbol}`);
|
|
634
633
|
}
|
|
635
634
|
}
|
|
636
635
|
|
|
636
|
+
const assetPrice = await this.pricer.getPrice(underlying.symbol);
|
|
637
637
|
const prevAum = await this.getPrevAUM();
|
|
638
|
+
const priceTypeLabel = priceType === LSTPriceType.ENDUR_PRICE ? "Endur Price" : "Avnu Price";
|
|
639
|
+
logger.verbose(`${this.getTag()} AUM (${priceTypeLabel}): ${netAUM}`);
|
|
640
|
+
|
|
638
641
|
const realAUM: PositionInfo = {
|
|
639
|
-
tokenInfo:
|
|
642
|
+
tokenInfo: underlying,
|
|
640
643
|
amount: netAUM,
|
|
641
644
|
usdValue: netAUM.toNumber() * assetPrice.price,
|
|
642
|
-
apy: {apy:
|
|
645
|
+
apy: { apy: 0, type: APYType.BASE }, // VT: Dont remember why this field exists here. FOr now, set it to 0.
|
|
643
646
|
remarks: AUMTypes.FINALISED,
|
|
644
|
-
protocol: Protocols.NONE
|
|
647
|
+
protocol: Protocols.NONE
|
|
645
648
|
};
|
|
646
649
|
|
|
647
650
|
const estimatedAUMDelta: PositionInfo = {
|
|
648
|
-
tokenInfo:
|
|
649
|
-
amount: Web3Number.fromWei('0',
|
|
651
|
+
tokenInfo: underlying,
|
|
652
|
+
amount: Web3Number.fromWei('0', underlying.decimals),
|
|
650
653
|
usdValue: 0,
|
|
651
|
-
apy: {apy: 0, type: APYType.BASE},
|
|
654
|
+
apy: { apy: 0, type: APYType.BASE },
|
|
652
655
|
remarks: AUMTypes.DEFISPRING,
|
|
653
|
-
protocol: Protocols.NONE
|
|
656
|
+
protocol: Protocols.NONE
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
return {
|
|
660
|
+
net: {
|
|
661
|
+
tokenInfo: underlying,
|
|
662
|
+
amount: netAUM,
|
|
663
|
+
usdValue: netAUM.toNumber() * assetPrice.price
|
|
664
|
+
}, prevAum: prevAum, splits: [realAUM, estimatedAUMDelta]
|
|
654
665
|
};
|
|
666
|
+
}
|
|
655
667
|
|
|
656
|
-
|
|
668
|
+
async getTVLUnrealized() {
|
|
669
|
+
return await this.getAUM(true);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
async getUserUnrealizedGains(user: ContractAddr) {
|
|
673
|
+
const tvl = await this.getTVL();
|
|
674
|
+
const unrealizedTVL = await this.getTVLUnrealized();
|
|
675
|
+
const unrealizedDiff = unrealizedTVL.net.amount.minus(tvl.amount);
|
|
676
|
+
const userTVL = await this.getUserTVL(user);
|
|
677
|
+
const userShare = userTVL.amount.dividedBy(tvl.amount);
|
|
678
|
+
const unrealizedGains = unrealizedDiff.multipliedBy(userShare);
|
|
679
|
+
|
|
680
|
+
return {
|
|
681
|
+
unrealizedGains,
|
|
682
|
+
userShare: userShare.toNumber(),
|
|
657
683
|
tokenInfo: this.asset(),
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
684
|
+
};
|
|
685
|
+
}
|
|
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;
|
|
661
749
|
}
|
|
662
750
|
|
|
663
|
-
/**
|
|
664
|
-
*
|
|
665
|
-
* @param params marginAmount is in LST, debtAmount is in underlying
|
|
666
|
-
*/
|
|
667
|
-
// async getModifyLeverCall(params: {
|
|
668
|
-
// marginAmount: Web3Number, // >0 during deposit
|
|
669
|
-
// debtAmount: Web3Number,
|
|
670
|
-
// lstDexPriceInUnderlying: number,
|
|
671
|
-
// isIncrease: boolean
|
|
672
|
-
// }): Promise<Call[]> {
|
|
673
|
-
// logger.verbose(`${this.getTag()}::getModifyLeverCall marginAmount: ${params.marginAmount}, debtAmount: ${params.debtAmount}, lstDexPriceInUnderlying: ${params.lstDexPriceInUnderlying}, isIncrease: ${params.isIncrease}`);
|
|
674
|
-
|
|
675
|
-
// const vesuAdapter = this.getVesuSameTokenAdapter();
|
|
676
|
-
// const manage0Info = vesuAdapter.
|
|
677
|
-
// const manageCall0 = manage0Info.callConstructor({
|
|
678
|
-
// amount: newDepositAmount
|
|
679
|
-
// });
|
|
680
|
-
// const manageCalls = await vesu
|
|
681
|
-
// return [this.getManageCall(proofsIDs, manageCalls)];
|
|
682
|
-
// }
|
|
683
751
|
}
|
|
684
752
|
|
|
685
753
|
export default function VaultDescription(
|
|
@@ -689,7 +757,6 @@ export default function VaultDescription(
|
|
|
689
757
|
const containerStyle = {
|
|
690
758
|
maxWidth: "800px",
|
|
691
759
|
margin: "0 auto",
|
|
692
|
-
backgroundColor: "#111",
|
|
693
760
|
color: "#eee",
|
|
694
761
|
fontFamily: "Arial, sans-serif",
|
|
695
762
|
borderRadius: "12px",
|
|
@@ -705,7 +772,7 @@ export default function VaultDescription(
|
|
|
705
772
|
</p>
|
|
706
773
|
|
|
707
774
|
<p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
708
|
-
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" }])}
|
|
709
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.
|
|
710
777
|
</p>
|
|
711
778
|
|
|
@@ -716,7 +783,7 @@ export default function VaultDescription(
|
|
|
716
783
|
</div>
|
|
717
784
|
<div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
|
|
718
785
|
<p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
719
|
-
<strong>Debt limits:</strong> Pools on Vesu have debt caps that are gradually increased over time. Until caps are raised, deposited
|
|
786
|
+
<strong>Debt limits:</strong> 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.
|
|
720
787
|
</p>
|
|
721
788
|
</div>
|
|
722
789
|
{/* <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
|
|
@@ -733,69 +800,82 @@ function getDescription(tokenSymbol: string, underlyingSymbol: string) {
|
|
|
733
800
|
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
734
801
|
}
|
|
735
802
|
|
|
736
|
-
|
|
737
|
-
enum LST_MULTIPLIER_MANAGE_IDS {
|
|
738
|
-
MULTIPLE_APPROVE = 'multiple_approve',
|
|
739
|
-
MULTIPLY_VESU = 'multiply_vesu',
|
|
740
|
-
SWITCH_DELEGATION_ON = 'switch_delegation_on',
|
|
741
|
-
SWITCH_DELEGATION_OFF = 'switch_delegation_off',
|
|
742
|
-
AVNU_MULTIPLY_APPROVE_DEPOSIT = 'avnu_mul_approve_dep',
|
|
743
|
-
AVNU_MULTIPLY_SWAP_DEPOSIT = 'avnu_mul_swap_dep',
|
|
744
|
-
AVNU_MULTIPLY_APPROVE_WITHDRAW = 'avnu_mul_approve_withdr',
|
|
745
|
-
AVNU_MULTIPLY_SWAP_WITHDRAW = 'avnu_mul_swap_withdr',
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
function getAvnuManageIDs(baseID: LST_MULTIPLIER_MANAGE_IDS, debtTokenSymbol: string) {
|
|
749
|
-
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
function getVesuLegId(baseID: string, debtTokenSymbol: string) {
|
|
753
|
-
return `${baseID}_${debtTokenSymbol.toLowerCase()}`;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
803
|
function getLooperSettings(
|
|
757
804
|
lstSymbol: string,
|
|
758
805
|
underlyingSymbol: string,
|
|
759
806
|
vaultSettings: HyperLSTStrategySettings,
|
|
760
|
-
pool1: ContractAddr,
|
|
761
807
|
) {
|
|
762
808
|
vaultSettings.leafAdapters = [];
|
|
809
|
+
vaultSettings.adapters = [];
|
|
763
810
|
|
|
764
811
|
const lstToken = Global.getDefaultTokens().find(token => token.symbol === lstSymbol)!;
|
|
765
812
|
const underlyingToken = Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!;
|
|
766
813
|
|
|
767
814
|
const baseAdapterConfig: BaseAdapterConfig = {
|
|
768
815
|
baseToken: lstToken,
|
|
769
|
-
supportedPositions: [{asset: lstToken, isDebt: false}],
|
|
816
|
+
supportedPositions: [{ asset: lstToken, isDebt: false }, { asset: underlyingToken, isDebt: true }],
|
|
770
817
|
networkConfig: getMainnetConfig(),
|
|
771
818
|
pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
|
|
772
819
|
vaultAllocator: vaultSettings.vaultAllocator,
|
|
773
820
|
vaultAddress: vaultSettings.vaultAddress
|
|
774
821
|
}
|
|
775
|
-
const vesuAdapterLST = new VesuSupplyOnlyAdapter({
|
|
776
|
-
// xWBTC vToken on re7 xBTC pool
|
|
777
|
-
vTokenContract: ContractAddr.from('0x062a162d0827db6f43ebb850cbef3c99fc7969e3070b83a2236c9f3713c89fd8'),
|
|
778
|
-
...baseAdapterConfig,
|
|
779
|
-
})
|
|
780
822
|
|
|
781
|
-
const
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
823
|
+
const adapterIds: NonNullable<HyperLSTStrategySettings["adapterIds"]> = {
|
|
824
|
+
primaryMultiply: "",
|
|
825
|
+
multiply: {},
|
|
826
|
+
modify: {},
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
const vesuMultiplyAdapters = vaultSettings.borrowable_assets.map((position) => {
|
|
830
|
+
const key = getHyperLSTAdapterKey(position.tokenInfo.symbol, position.poolId);
|
|
831
|
+
const id = getHyperLSTMultiplyAdapterId(lstSymbol, position.tokenInfo.symbol, position.poolId);
|
|
832
|
+
adapterIds.multiply[key] = id;
|
|
833
|
+
return {
|
|
834
|
+
id,
|
|
835
|
+
adapter: new VesuMultiplyAdapter({
|
|
836
|
+
poolId: position.poolId,
|
|
837
|
+
collateral: lstToken,
|
|
838
|
+
debt: position.tokenInfo,
|
|
839
|
+
marginToken: lstToken,
|
|
840
|
+
targetHealthFactor: vaultSettings.targetHealthFactor,
|
|
841
|
+
minHealthFactor: vaultSettings.minHealthFactor,
|
|
842
|
+
quoteAmountToFetchPrice: vaultSettings.quoteAmountToFetchPrice,
|
|
843
|
+
...baseAdapterConfig,
|
|
844
|
+
minimumVesuMovementAmount: 0,
|
|
845
|
+
}),
|
|
846
|
+
};
|
|
794
847
|
});
|
|
795
848
|
|
|
796
|
-
vaultSettings.
|
|
797
|
-
|
|
798
|
-
|
|
849
|
+
const vesuModifyPositionAdapters = vaultSettings.borrowable_assets.map((position) => {
|
|
850
|
+
const key = getHyperLSTAdapterKey(position.tokenInfo.symbol, position.poolId);
|
|
851
|
+
const id = getHyperLSTModifyAdapterId(lstSymbol, position.tokenInfo.symbol, position.poolId);
|
|
852
|
+
adapterIds.modify[key] = id;
|
|
853
|
+
return {
|
|
854
|
+
id,
|
|
855
|
+
adapter: new VesuModifyPositionAdapter({
|
|
856
|
+
poolId: position.poolId,
|
|
857
|
+
collateral: lstToken,
|
|
858
|
+
debt: position.tokenInfo,
|
|
859
|
+
targetLtv: 0.8,
|
|
860
|
+
maxLtv: 0.9,
|
|
861
|
+
...baseAdapterConfig,
|
|
862
|
+
}),
|
|
863
|
+
};
|
|
864
|
+
});
|
|
865
|
+
|
|
866
|
+
if (!adapterIds.primaryMultiply && vesuMultiplyAdapters.length > 0) {
|
|
867
|
+
adapterIds.primaryMultiply = vesuMultiplyAdapters[0].id;
|
|
868
|
+
} else {
|
|
869
|
+
throw new Error(`${lstSymbol}::getLooperSettings: primaryMultiply adapter not found`);
|
|
870
|
+
}
|
|
871
|
+
vaultSettings.adapterIds = adapterIds;
|
|
872
|
+
|
|
873
|
+
for (const entry of vesuMultiplyAdapters) {
|
|
874
|
+
vaultSettings.adapters.push(entry);
|
|
875
|
+
}
|
|
876
|
+
for (const entry of vesuModifyPositionAdapters) {
|
|
877
|
+
vaultSettings.adapters.push(entry);
|
|
878
|
+
}
|
|
799
879
|
|
|
800
880
|
const commonAdapter = new CommonAdapter({
|
|
801
881
|
id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
|
|
@@ -805,25 +885,21 @@ function getLooperSettings(
|
|
|
805
885
|
asset: lstToken.address
|
|
806
886
|
})
|
|
807
887
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
888
|
+
for (const entry of vesuMultiplyAdapters) {
|
|
889
|
+
const adapter = entry.adapter;
|
|
890
|
+
vaultSettings.leafAdapters.push(() => adapter.getDepositLeaf());
|
|
891
|
+
vaultSettings.leafAdapters.push(() => adapter.getWithdrawLeaf());
|
|
892
|
+
}
|
|
893
|
+
for (const entry of vesuModifyPositionAdapters) {
|
|
894
|
+
const adapter = entry.adapter;
|
|
895
|
+
vaultSettings.leafAdapters.push(() => adapter.getDepositLeaf());
|
|
896
|
+
vaultSettings.leafAdapters.push(() => adapter.getWithdrawLeaf());
|
|
897
|
+
}
|
|
811
898
|
|
|
812
|
-
// push vesu multiply adapter to leaf adapters
|
|
813
|
-
vesuMultiplyAdapters.map(adapter => vaultSettings.leafAdapters.push(() => adapter.getDepositLeaf()));
|
|
814
|
-
vesuMultiplyAdapters.map(adapter => vaultSettings.leafAdapters.push(() => adapter.getWithdrawLeaf()));
|
|
815
|
-
|
|
816
899
|
// to bridge liquidity back to vault (used by bring_liquidity)
|
|
817
900
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(lstToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
|
|
818
901
|
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
|
|
819
|
-
|
|
820
|
-
// claim rewards
|
|
821
|
-
// vaultSettings.leafAdapters.push(vesuAdapterLST.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterLST));
|
|
822
|
-
|
|
823
|
-
// // avnu swap for claims rewards
|
|
824
|
-
// const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
|
|
825
|
-
// vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_EXCHANGE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
|
|
826
|
-
// vabaseAdapterConfigultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, lstToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS, false).bind(commonAdapter));
|
|
902
|
+
|
|
827
903
|
return vaultSettings;
|
|
828
904
|
}
|
|
829
905
|
|
|
@@ -889,13 +965,9 @@ export const _riskFactor: RiskFactor[] = [
|
|
|
889
965
|
{ type: RiskType.SMART_CONTRACT_RISK, value: SmartContractRiskLevel.WELL_AUDITED, weight: 25, reason: "Audited by Zellic" },
|
|
890
966
|
{ type: RiskType.LIQUIDATION_RISK, value: LiquidationRiskLevel.VERY_LOW_PROBABILITY, weight: 25, reason: "The collateral and debt are highly correlated" },
|
|
891
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." },
|
|
892
|
-
{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" },
|
|
893
969
|
];
|
|
894
970
|
|
|
895
|
-
const borrowableAssets = [
|
|
896
|
-
'WBTC', 'tBTC', 'LBTC', 'solvBTC'
|
|
897
|
-
]
|
|
898
|
-
|
|
899
971
|
const hyperxSTRK: HyperLSTStrategySettings = {
|
|
900
972
|
vaultAddress: ContractAddr.from('0x46c7a54c82b1fe374353859f554a40b8bd31d3e30f742901579e7b57b1b5960'),
|
|
901
973
|
manager: ContractAddr.from('0x5d499cd333757f461a0bedaca3dfc4d77320c773037e0aa299f22a6dbfdc03a'),
|
|
@@ -906,9 +978,15 @@ const hyperxSTRK: HyperLSTStrategySettings = {
|
|
|
906
978
|
adapters: [],
|
|
907
979
|
targetHealthFactor: 1.1,
|
|
908
980
|
minHealthFactor: 1.05,
|
|
909
|
-
borrowable_assets:
|
|
981
|
+
borrowable_assets: [{
|
|
982
|
+
tokenInfo: Global.getDefaultTokens().find(token => token.symbol === 'STRK')!,
|
|
983
|
+
poolId: VesuPools.Re7STRK,
|
|
984
|
+
}, {
|
|
985
|
+
tokenInfo: Global.getDefaultTokens().find(token => token.symbol === 'STRK')!,
|
|
986
|
+
poolId: VesuPools.Prime,
|
|
987
|
+
}],
|
|
910
988
|
underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'STRK')!,
|
|
911
|
-
quoteAmountToFetchPrice: new Web3Number('
|
|
989
|
+
quoteAmountToFetchPrice: new Web3Number('1000', Global.getDefaultTokens().find(token => token.symbol === 'STRK')!.decimals),
|
|
912
990
|
}
|
|
913
991
|
|
|
914
992
|
const hyperxWBTC: HyperLSTStrategySettings = {
|
|
@@ -921,9 +999,13 @@ const hyperxWBTC: HyperLSTStrategySettings = {
|
|
|
921
999
|
adapters: [],
|
|
922
1000
|
targetHealthFactor: 1.1,
|
|
923
1001
|
minHealthFactor: 1.05,
|
|
924
|
-
borrowable_assets:
|
|
1002
|
+
borrowable_assets: [{
|
|
1003
|
+
tokenInfo: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
|
|
1004
|
+
poolId: VesuPools.Re7xBTC,
|
|
1005
|
+
}],
|
|
925
1006
|
underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
|
|
926
1007
|
quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!.decimals),
|
|
1008
|
+
redemptionRouter: ContractAddr.from('0x6ea649f402898f69baf775c1afdd08522c071c640b9c4460192070ec2b96417'),
|
|
927
1009
|
}
|
|
928
1010
|
|
|
929
1011
|
const hyperxtBTC: HyperLSTStrategySettings = {
|
|
@@ -936,9 +1018,16 @@ const hyperxtBTC: HyperLSTStrategySettings = {
|
|
|
936
1018
|
adapters: [],
|
|
937
1019
|
targetHealthFactor: 1.1,
|
|
938
1020
|
minHealthFactor: 1.05,
|
|
939
|
-
borrowable_assets:
|
|
1021
|
+
borrowable_assets: [{
|
|
1022
|
+
tokenInfo: Global.getDefaultTokens().find(token => token.symbol === 'tBTC')!,
|
|
1023
|
+
poolId: VesuPools.Re7xBTC,
|
|
1024
|
+
}, {
|
|
1025
|
+
tokenInfo: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
|
|
1026
|
+
poolId: VesuPools.Re7xBTC,
|
|
1027
|
+
}],
|
|
940
1028
|
underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'tBTC')!,
|
|
941
1029
|
quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'tBTC')!.decimals),
|
|
1030
|
+
redemptionRouter: ContractAddr.from('0x3de9c409d1e357e25778fb7a3e2e2393666956846a5c2caa607296fa8e76b5d'),
|
|
942
1031
|
}
|
|
943
1032
|
|
|
944
1033
|
const hyperxsBTC: HyperLSTStrategySettings = {
|
|
@@ -951,7 +1040,10 @@ const hyperxsBTC: HyperLSTStrategySettings = {
|
|
|
951
1040
|
adapters: [],
|
|
952
1041
|
targetHealthFactor: 1.1,
|
|
953
1042
|
minHealthFactor: 1.05,
|
|
954
|
-
borrowable_assets:
|
|
1043
|
+
borrowable_assets: [{
|
|
1044
|
+
tokenInfo: Global.getDefaultTokens().find(token => token.symbol === 'solvBTC')!,
|
|
1045
|
+
poolId: VesuPools.Re7xBTC,
|
|
1046
|
+
}],
|
|
955
1047
|
underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'solvBTC')!,
|
|
956
1048
|
quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'solvBTC')!.decimals),
|
|
957
1049
|
}
|
|
@@ -966,44 +1058,47 @@ const hyperxLBTC: HyperLSTStrategySettings = {
|
|
|
966
1058
|
adapters: [],
|
|
967
1059
|
targetHealthFactor: 1.1,
|
|
968
1060
|
minHealthFactor: 1.05,
|
|
969
|
-
borrowable_assets:
|
|
1061
|
+
borrowable_assets: [{
|
|
1062
|
+
tokenInfo: Global.getDefaultTokens().find(token => token.symbol === 'LBTC')!,
|
|
1063
|
+
poolId: VesuPools.Re7xBTC,
|
|
1064
|
+
}],
|
|
970
1065
|
underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'LBTC')!,
|
|
971
1066
|
quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'LBTC')!.decimals),
|
|
972
1067
|
}
|
|
973
1068
|
|
|
974
|
-
const hypermRe7BTC: HyperLSTStrategySettings = {
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
}
|
|
1069
|
+
// const hypermRe7BTC: HyperLSTStrategySettings = {
|
|
1070
|
+
// vaultAddress: ContractAddr.from('0x6c89b75d09de82477edb86b2c2918cfc1a5dc0177cfbdea46278386b6499645'),
|
|
1071
|
+
// manager: ContractAddr.from('0x7bc2d0535e13352d3ab78ea047616a3162068294297304943d2302122a150a1'),
|
|
1072
|
+
// vaultAllocator: ContractAddr.from('0x760f9cebca9d2ee624f4224591da6da8b3ea5fd2410590735709551bd4e7570'),
|
|
1073
|
+
// redeemRequestNFT: ContractAddr.from('0x5e045ae0160f7650f8a4dd7c826f25630a89fe62434db4441e7e0075608180f'),
|
|
1074
|
+
// aumOracle: ContractAddr.from('0x3958df341b838813c24efb9183c23bddd1c57d44b1b86c0dd57f67887b89fba'),
|
|
1075
|
+
// leafAdapters: [],
|
|
1076
|
+
// adapters: [],
|
|
1077
|
+
// targetHealthFactor: 1.1,
|
|
1078
|
+
// minHealthFactor: 1.05,
|
|
1079
|
+
// borrowable_assets: .map(asset => Global.getDefaultTokens().find(token => token.symbol === asset)!),
|
|
1080
|
+
// underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!,
|
|
1081
|
+
// quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'mRe7BTC')!.decimals),
|
|
1082
|
+
// }
|
|
988
1083
|
// Contract deployed: Vault, addr: 0x42797ab4eb1f72787442e91a73d63a39e3a141c1106470a946ecc328db6896c
|
|
989
1084
|
// Contract deployed: RedeemRequest, addr: 0x4bbb25c2568af07967342833f7db1aece1be1be2330798dab4ee585aa6c2c72
|
|
990
1085
|
// Contract deployed: VaultAllocator, addr: 0x456c4c6afca90512aeb5c735d84405fea6e51ab06d1851ac8cdb0a235e14f15
|
|
991
1086
|
// Contract deployed: Manager, addr: 0x435b45d40fbb406cf69ac84bb471e7b7a4ea2295d0893c05dd2db565295e77f
|
|
992
1087
|
|
|
993
|
-
const hypermRe7YIELD: HyperLSTStrategySettings = {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
}
|
|
1088
|
+
// const hypermRe7YIELD: HyperLSTStrategySettings = {
|
|
1089
|
+
// vaultAddress: ContractAddr.from('0x42797ab4eb1f72787442e91a73d63a39e3a141c1106470a946ecc328db6896c'),
|
|
1090
|
+
// manager: ContractAddr.from('0x435b45d40fbb406cf69ac84bb471e7b7a4ea2295d0893c05dd2db565295e77f'),
|
|
1091
|
+
// vaultAllocator: ContractAddr.from('0x456c4c6afca90512aeb5c735d84405fea6e51ab06d1851ac8cdb0a235e14f15'),
|
|
1092
|
+
// redeemRequestNFT: ContractAddr.from('0x4bbb25c2568af07967342833f7db1aece1be1be2330798dab4ee585aa6c2c72'),
|
|
1093
|
+
// aumOracle: ContractAddr.from('0x3e1f2825158cafccc9b42a8165d17ceb6b8e966474d9c63587d338746888382'),
|
|
1094
|
+
// leafAdapters: [],
|
|
1095
|
+
// adapters: [],
|
|
1096
|
+
// targetHealthFactor: 1.1,
|
|
1097
|
+
// minHealthFactor: 1.05,
|
|
1098
|
+
// borrowable_assets: [Global.getDefaultTokens().find(token => token.symbol === 'USDC')!],
|
|
1099
|
+
// underlyingToken: Global.getDefaultTokens().find(token => token.symbol === 'USDC')!,
|
|
1100
|
+
// quoteAmountToFetchPrice: new Web3Number('0.001', Global.getDefaultTokens().find(token => token.symbol === 'mRe7BTC')!.decimals),
|
|
1101
|
+
// }
|
|
1007
1102
|
|
|
1008
1103
|
export function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string) {
|
|
1009
1104
|
return [
|
|
@@ -1011,35 +1106,157 @@ export function getInvestmentSteps(lstSymbol: string, underlyingSymbol: string)
|
|
|
1011
1106
|
`The vault manager loops the ${underlyingSymbol} to buy ${lstSymbol}`,
|
|
1012
1107
|
`The vault manager collateralizes the ${lstSymbol} on Vesu`,
|
|
1013
1108
|
`The vault manager borrows more ${underlyingSymbol} to loop further`,
|
|
1014
|
-
`If required, adjust leverage or re-allocate assets within pool on Vesu to optimize yield`
|
|
1109
|
+
`If required, adjust leverage or re-allocate assets within LST pool on Vesu to optimize yield`
|
|
1015
1110
|
]
|
|
1016
1111
|
}
|
|
1017
1112
|
|
|
1018
|
-
function
|
|
1113
|
+
function getMaxTVL(lstSymbol: string): Web3Number {
|
|
1114
|
+
const lstMaxTVLs: Record<string, number> = {
|
|
1115
|
+
xWBTC: 5,
|
|
1116
|
+
xLBTC: 5,
|
|
1117
|
+
xtBTC: 5,
|
|
1118
|
+
xsBTC: 5,
|
|
1119
|
+
xSTRK: 7000000,
|
|
1120
|
+
};
|
|
1121
|
+
const maxTVLValue = lstMaxTVLs[lstSymbol] || 0;
|
|
1122
|
+
const token = Global.getDefaultTokens().find(
|
|
1123
|
+
(token) => token.symbol === lstSymbol,
|
|
1124
|
+
);
|
|
1125
|
+
if (!token) {
|
|
1126
|
+
return Web3Number.fromWei(0, 18);
|
|
1127
|
+
}
|
|
1128
|
+
return Web3Number.fromWei(maxTVLValue, token.decimals);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
function createHyperLSTSettings(
|
|
1132
|
+
lstSymbol: string,
|
|
1133
|
+
underlyingSymbol: string,
|
|
1134
|
+
): StrategySettings {
|
|
1135
|
+
const depositToken = Global.getDefaultTokens().find(
|
|
1136
|
+
(token) => token.symbol === lstSymbol,
|
|
1137
|
+
)!;
|
|
1138
|
+
return {
|
|
1139
|
+
maxTVL: getMaxTVL(lstSymbol),
|
|
1140
|
+
isPaused: false,
|
|
1141
|
+
liveStatus: StrategyLiveStatus.HOT,
|
|
1142
|
+
isAudited: true,
|
|
1143
|
+
isInstantWithdrawal: false,
|
|
1144
|
+
hideHarvestInfo: true,
|
|
1145
|
+
quoteToken: depositToken,
|
|
1146
|
+
showWithdrawalWarningModal: false,
|
|
1147
|
+
alerts: [
|
|
1148
|
+
{
|
|
1149
|
+
tab: "withdraw" as const,
|
|
1150
|
+
text: "On withdrawal, you will receive an NFT representing your withdrawal request. The funds will be automatically sent to your wallet (NFT owner) in 24 hours (In this initial phase of Launch). You can monitor the status in transactions tab.",
|
|
1151
|
+
type: "info" as const,
|
|
1152
|
+
},
|
|
1153
|
+
{
|
|
1154
|
+
tab: "deposit" as const,
|
|
1155
|
+
text: (
|
|
1156
|
+
<>
|
|
1157
|
+
To acquire the LST, please visit{" "}
|
|
1158
|
+
<a href="https://app.endur.fi" target="_blank" rel="noopener noreferrer">endur.fi</a>
|
|
1159
|
+
</>
|
|
1160
|
+
),
|
|
1161
|
+
type: "info" as const,
|
|
1162
|
+
},
|
|
1163
|
+
{
|
|
1164
|
+
tab: "deposit" as const,
|
|
1165
|
+
text: "It may take up to one week for your deposit to appreciate in value. This delay occurs because the LST price is sourced from DEXes and liquidity is usually rebased once a week.",
|
|
1166
|
+
type: "info" as const,
|
|
1167
|
+
},
|
|
1168
|
+
],
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
const HYPER_LST_SECURITY = {
|
|
1173
|
+
auditStatus: AuditStatus.AUDITED,
|
|
1174
|
+
sourceCode: {
|
|
1175
|
+
type: SourceCodeType.CLOSED_SOURCE,
|
|
1176
|
+
contractLink: "https://github.com/trovesfi/troves-contracts",
|
|
1177
|
+
},
|
|
1178
|
+
accessControl: {
|
|
1179
|
+
type: AccessControlType.STANDARD_ACCOUNT,
|
|
1180
|
+
addresses: [ContractAddr.from("0x0")],
|
|
1181
|
+
timeLock: "2 Days",
|
|
1182
|
+
},
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
const HYPER_LST_REDEMPTION_INFO: RedemptionInfo = {
|
|
1186
|
+
instantWithdrawalVault: InstantWithdrawalVault.NO,
|
|
1187
|
+
redemptionsInfo: [
|
|
1188
|
+
{
|
|
1189
|
+
title: "Typical Duration",
|
|
1190
|
+
description: "1-2 hours",
|
|
1191
|
+
},
|
|
1192
|
+
],
|
|
1193
|
+
alerts: [
|
|
1194
|
+
{
|
|
1195
|
+
type: "info",
|
|
1196
|
+
text: "In cases of low liquidity, high slippages, the redemptions can take longer time. Redemption times are estimates and may vary based on network conditions and liquidity requirements.",
|
|
1197
|
+
tab: "withdraw",
|
|
1198
|
+
},
|
|
1199
|
+
],
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
function getStrategySettings(
|
|
1203
|
+
lstSymbol: string,
|
|
1204
|
+
underlyingSymbol: string,
|
|
1205
|
+
settings: HyperLSTStrategySettings,
|
|
1206
|
+
isPreview: boolean = false,
|
|
1207
|
+
isLST: boolean,
|
|
1208
|
+
): IStrategyMetadata<HyperLSTStrategySettings> {
|
|
1019
1209
|
return {
|
|
1210
|
+
id: `hyper_${lstSymbol.toLowerCase()}`,
|
|
1020
1211
|
name: `Hyper ${lstSymbol}`,
|
|
1021
1212
|
description: getDescription(lstSymbol, underlyingSymbol),
|
|
1022
|
-
address:
|
|
1213
|
+
address: settings.vaultAddress,
|
|
1023
1214
|
launchBlock: 0,
|
|
1024
1215
|
type: 'Other',
|
|
1216
|
+
vaultType: {
|
|
1217
|
+
type: VaultType.LOOPING,
|
|
1218
|
+
description: `Creates leveraged looping position on ${lstSymbol} by borrowing ${underlyingSymbol} to increase yield`,
|
|
1219
|
+
},
|
|
1025
1220
|
depositTokens: [Global.getDefaultTokens().find(token => token.symbol === lstSymbol)!],
|
|
1026
|
-
additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol,
|
|
1221
|
+
additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, settings),
|
|
1027
1222
|
risk: {
|
|
1028
1223
|
riskFactor: _riskFactor,
|
|
1029
1224
|
netRisk:
|
|
1030
1225
|
_riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1031
1226
|
_riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1032
|
-
notARisks: getNoRiskTags(_riskFactor)
|
|
1227
|
+
notARisks: getNoRiskTags(_riskFactor),
|
|
1033
1228
|
},
|
|
1034
1229
|
auditUrl: AUDIT_URL,
|
|
1035
1230
|
protocols: [Protocols.ENDUR, Protocols.VESU],
|
|
1036
|
-
|
|
1037
|
-
|
|
1231
|
+
curator: {
|
|
1232
|
+
name: "Unwrap Labs",
|
|
1233
|
+
logo: "https://assets.troves.fi/integrations/unwraplabs/white.png",
|
|
1234
|
+
},
|
|
1235
|
+
settings: createHyperLSTSettings(lstSymbol, underlyingSymbol),
|
|
1236
|
+
contractDetails: getContractDetails(settings),
|
|
1038
1237
|
faqs: getFAQs(lstSymbol, underlyingSymbol, isLST),
|
|
1039
1238
|
investmentSteps: getInvestmentSteps(lstSymbol, underlyingSymbol),
|
|
1040
1239
|
isPreview: isPreview,
|
|
1041
|
-
apyMethodology:
|
|
1042
|
-
|
|
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")
|
|
1248
|
+
? [StrategyTag.BTC, StrategyTag.LEVERED]
|
|
1249
|
+
: [StrategyTag.LEVERED],
|
|
1250
|
+
security: HYPER_LST_SECURITY,
|
|
1251
|
+
redemptionInfo: HYPER_LST_REDEMPTION_INFO,
|
|
1252
|
+
usualTimeToEarnings: '2 weeks',
|
|
1253
|
+
usualTimeToEarningsDescription: 'Strategy returns depend on LST price on DEXes. Even though the true price of LST on Endur increases continuously, the DEX price may lag sometimes, and historically is seen to rebase at least once every 2 hours. This is when you realise your earnings.',
|
|
1254
|
+
points: lstSymbol === 'xSTRK' ? [{
|
|
1255
|
+
multiplier: 4,
|
|
1256
|
+
logo: "https://endur.fi/favicon.ico",
|
|
1257
|
+
toolTip: "This strategy holds xSTRK. Earn 3-4x Endur points on your xSTRK due to the leverage. Points can be found on endur.fi.",
|
|
1258
|
+
}] : undefined,
|
|
1259
|
+
};
|
|
1043
1260
|
}
|
|
1044
1261
|
|
|
1045
1262
|
|
|
@@ -1062,10 +1279,10 @@ function getStrategySettings(lstSymbol: string, underlyingSymbol: string, addres
|
|
|
1062
1279
|
export const HyperLSTStrategies: IStrategyMetadata<HyperLSTStrategySettings>[] =
|
|
1063
1280
|
[
|
|
1064
1281
|
getStrategySettings('xSTRK', 'STRK', hyperxSTRK, false, true),
|
|
1065
|
-
getStrategySettings('xWBTC', 'WBTC', hyperxWBTC, false,
|
|
1066
|
-
getStrategySettings('xtBTC', 'tBTC', hyperxtBTC, false,
|
|
1067
|
-
getStrategySettings('xsBTC', 'solvBTC', hyperxsBTC, false,
|
|
1068
|
-
getStrategySettings('xLBTC', 'LBTC', hyperxLBTC, false,
|
|
1069
|
-
getStrategySettings('mRe7BTC', 'mRe7BTC', hypermRe7BTC, false, false),
|
|
1070
|
-
getStrategySettings('mRe7YIELD', 'mRe7YIELD', hypermRe7YIELD, false, false),
|
|
1282
|
+
getStrategySettings('xWBTC', 'WBTC', hyperxWBTC, false, true),
|
|
1283
|
+
getStrategySettings('xtBTC', 'tBTC', hyperxtBTC, false, true),
|
|
1284
|
+
getStrategySettings('xsBTC', 'solvBTC', hyperxsBTC, false, true),
|
|
1285
|
+
getStrategySettings('xLBTC', 'LBTC', hyperxLBTC, false, true),
|
|
1286
|
+
// getStrategySettings('mRe7BTC', 'mRe7BTC', hypermRe7BTC, false, false),
|
|
1287
|
+
// getStrategySettings('mRe7YIELD', 'mRe7YIELD', hypermRe7YIELD, false, false),
|
|
1071
1288
|
]
|