@strkfarm/sdk 2.0.0-dev.35 → 2.0.0-dev.36
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 +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/index.browser.global.js +19244 -28574
- package/dist/index.browser.mjs +8439 -17951
- package/dist/index.d.ts +578 -2746
- package/dist/index.js +8528 -18078
- package/dist/index.mjs +8456 -17968
- package/package.json +3 -3
- package/src/data/universal-vault.abi.json +8 -7
- package/src/dataTypes/bignumber.browser.ts +5 -1
- package/src/dataTypes/bignumber.node.ts +5 -0
- package/src/global.ts +21 -1
- package/src/interfaces/common.tsx +39 -4
- package/src/modules/avnu.ts +19 -10
- package/src/modules/index.ts +1 -1
- package/src/strategies/base-strategy.ts +92 -8
- package/src/strategies/constants.ts +8 -3
- package/src/strategies/ekubo-cl-vault.tsx +150 -16
- package/src/strategies/factory.ts +21 -1
- package/src/strategies/index.ts +2 -7
- package/src/strategies/registry.ts +28 -5
- package/src/strategies/sensei.ts +29 -13
- package/src/strategies/svk-strategy.ts +26 -2
- package/src/strategies/token-boosted-xstrk-carry-strategy.tsx +1057 -0
- package/src/strategies/universal-adapters/avnu-adapter.ts +16 -8
- package/src/strategies/universal-adapters/index.ts +1 -2
- package/src/strategies/universal-adapters/svk-troves-adapter.ts +19 -6
- package/src/strategies/universal-adapters/vesu-modify-position-adapter.ts +22 -3
- package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +75 -52
- package/src/strategies/universal-adapters/vesu-position-common.ts +38 -31
- package/src/strategies/universal-lst-muliplier-strategy.tsx +222 -269
- package/src/strategies/universal-strategy.tsx +166 -105
- package/src/strategies/vesu-rebalance.tsx +3 -6
- package/src/strategies/yoloVault.ts +1084 -0
- package/src/utils/health-factor-math.ts +29 -0
- package/src/modules/ExtendedWrapperSDk/index.ts +0 -62
- package/src/modules/ExtendedWrapperSDk/types.ts +0 -334
- package/src/modules/ExtendedWrapperSDk/wrapper.ts +0 -611
- package/src/strategies/universal-adapters/extended-adapter.ts +0 -860
- package/src/strategies/universal-adapters/usdc<>usdce-adapter.ts +0 -200
- package/src/strategies/usdc-boosted-strategy.tsx +0 -693
- package/src/strategies/vesu-extended-strategy/services/executionService.ts +0 -2234
- package/src/strategies/vesu-extended-strategy/services/extended-vesu-state-manager.ts +0 -4254
- package/src/strategies/vesu-extended-strategy/services/ltv-imbalance-rebalance-math.ts +0 -783
- package/src/strategies/vesu-extended-strategy/services/operationService.ts +0 -56
- package/src/strategies/vesu-extended-strategy/types/transaction-metadata.ts +0 -88
- package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +0 -78
- package/src/strategies/vesu-extended-strategy/utils/constants.ts +0 -48
- package/src/strategies/vesu-extended-strategy/utils/helper.ts +0 -528
- package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +0 -1014
|
@@ -1,1014 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getMainnetConfig,
|
|
3
|
-
IConfig,
|
|
4
|
-
IStrategyMetadata,
|
|
5
|
-
TokenInfo,
|
|
6
|
-
AuditStatus,
|
|
7
|
-
SourceCodeType,
|
|
8
|
-
AccessControlType,
|
|
9
|
-
InstantWithdrawalVault,
|
|
10
|
-
VaultType,
|
|
11
|
-
VaultPosition,
|
|
12
|
-
} from "@/interfaces";
|
|
13
|
-
import {
|
|
14
|
-
UNIVERSAL_MANAGE_IDS,
|
|
15
|
-
UniversalStrategySettings,
|
|
16
|
-
} from "../universal-strategy";
|
|
17
|
-
import {
|
|
18
|
-
ExtendedSVKVesuStateManager,
|
|
19
|
-
StateManagerConfig,
|
|
20
|
-
} from "./services/extended-vesu-state-manager";
|
|
21
|
-
import { ExecutionService, ExecutionConfig } from "./services/executionService";
|
|
22
|
-
import { logger } from "@/utils";
|
|
23
|
-
import { AUDIT_URL } from "../universal-lst-muliplier-strategy";
|
|
24
|
-
import { getNoRiskTags } from "@/interfaces";
|
|
25
|
-
import { _riskFactor } from "../universal-lst-muliplier-strategy";
|
|
26
|
-
import {
|
|
27
|
-
LIMIT_BALANCE,
|
|
28
|
-
USDC_TOKEN_DECIMALS,
|
|
29
|
-
WALLET_ADDRESS,
|
|
30
|
-
WBTC_TOKEN_DECIMALS,
|
|
31
|
-
} from "./utils/constants";
|
|
32
|
-
import { ExecutionCallback } from "./types/transaction-metadata";
|
|
33
|
-
import { PricerBase } from "@/modules/pricerBase";
|
|
34
|
-
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
35
|
-
import { Global } from "@/global";
|
|
36
|
-
import { ERC20 } from "@/modules";
|
|
37
|
-
import { Protocols } from "@/interfaces";
|
|
38
|
-
import { MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP } from "./utils/constants";
|
|
39
|
-
import {
|
|
40
|
-
getInvestmentSteps,
|
|
41
|
-
getFAQs,
|
|
42
|
-
} from "../universal-lst-muliplier-strategy";
|
|
43
|
-
import { getContractDetails } from "../universal-strategy";
|
|
44
|
-
import { highlightTextWithLinks } from "@/interfaces";
|
|
45
|
-
import { PositionInfo } from "../universal-adapters";
|
|
46
|
-
import { APYType } from "../universal-adapters";
|
|
47
|
-
import { AUMTypes } from "../universal-strategy";
|
|
48
|
-
import { VesuPools } from "../universal-adapters";
|
|
49
|
-
import {
|
|
50
|
-
BaseAdapterConfig,
|
|
51
|
-
CommonAdapter,
|
|
52
|
-
TokenTransferAdapter,
|
|
53
|
-
VesuModifyPositionAdapter,
|
|
54
|
-
VesuMultiplyAdapter,
|
|
55
|
-
} from "../universal-adapters";
|
|
56
|
-
import {
|
|
57
|
-
AVNU_QUOTE_URL,
|
|
58
|
-
AVNU_MIDDLEWARE,
|
|
59
|
-
EXTENDED_CONTRACT,
|
|
60
|
-
} from "../universal-adapters/adapter-utils";
|
|
61
|
-
import { PricerFromApi } from "@/modules";
|
|
62
|
-
import { ExtendedAdapter } from "../universal-adapters/extended-adapter";
|
|
63
|
-
import { SVKStrategy } from "../svk-strategy";
|
|
64
|
-
import { AvnuAdapter } from "../universal-adapters/avnu-adapter";
|
|
65
|
-
import { SingleTokenInfo } from "../base-strategy";
|
|
66
|
-
import { VesuConfig } from "./utils/config.runtime";
|
|
67
|
-
|
|
68
|
-
export interface VesuExtendedStrategySettings extends UniversalStrategySettings {
|
|
69
|
-
underlyingToken: TokenInfo;
|
|
70
|
-
borrowable_assets: TokenInfo[];
|
|
71
|
-
targetHealthFactor: number;
|
|
72
|
-
quoteAmountToFetchPrice: Web3Number;
|
|
73
|
-
minHealthFactor: number;
|
|
74
|
-
aumOracle: ContractAddr;
|
|
75
|
-
minimumWBTCDifferenceForAvnuSwap: number;
|
|
76
|
-
walletAddress: string;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export class VesuExtendedMultiplierStrategy<
|
|
80
|
-
S extends VesuExtendedStrategySettings,
|
|
81
|
-
> extends SVKStrategy<S> {
|
|
82
|
-
public wbtcToken: TokenInfo;
|
|
83
|
-
public usdcToken: TokenInfo;
|
|
84
|
-
public readonly stateManager: ExtendedSVKVesuStateManager;
|
|
85
|
-
|
|
86
|
-
constructor(
|
|
87
|
-
config: IConfig,
|
|
88
|
-
pricer: PricerBase,
|
|
89
|
-
metadata: IStrategyMetadata<S>,
|
|
90
|
-
) {
|
|
91
|
-
super(config, pricer, metadata);
|
|
92
|
-
this.metadata.additionalInfo.adapters.forEach((adapter) => {
|
|
93
|
-
adapter.adapter.config.networkConfig = this.config;
|
|
94
|
-
adapter.adapter.config.pricer = this.pricer;
|
|
95
|
-
if ((adapter.adapter as any)._vesuAdapter) {
|
|
96
|
-
(adapter.adapter as any)._vesuAdapter.networkConfig =
|
|
97
|
-
this.config;
|
|
98
|
-
(adapter.adapter as any)._vesuAdapter.pricer =
|
|
99
|
-
this.pricer;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
// todo check if this can be generalized
|
|
103
|
-
this.wbtcToken = Global.getDefaultTokens().find((token) => token.symbol === "WBTC")!;
|
|
104
|
-
this.usdcToken = this.metadata.additionalInfo.borrowable_assets[0]!;
|
|
105
|
-
this.stateManager = this._initializeStateManager();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Extracts the required adapters from metadata and constructs the
|
|
110
|
-
* state manager used by shouldInvest / handleWithdraw.
|
|
111
|
-
*/
|
|
112
|
-
private _initializeStateManager(): ExtendedSVKVesuStateManager {
|
|
113
|
-
const vesuAdapters = this.metadata.additionalInfo.adapters
|
|
114
|
-
.filter((a) => a.adapter.name === VesuMultiplyAdapter.name)
|
|
115
|
-
.map((a) => a.adapter as VesuMultiplyAdapter);
|
|
116
|
-
|
|
117
|
-
const extendedAdapterEntry = this.metadata.additionalInfo.adapters.find(
|
|
118
|
-
(a) => a.adapter.name === ExtendedAdapter.name,
|
|
119
|
-
);
|
|
120
|
-
if (!extendedAdapterEntry) {
|
|
121
|
-
throw new Error(
|
|
122
|
-
`${this.getTag()} ExtendedAdapter not found in adapters — cannot initialise state manager.`,
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const stateManagerConfig: StateManagerConfig = {
|
|
127
|
-
pricer: this.pricer,
|
|
128
|
-
networkConfig: this.config,
|
|
129
|
-
vesuAdapters,
|
|
130
|
-
extendedAdapter: extendedAdapterEntry.adapter as ExtendedAdapter,
|
|
131
|
-
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
132
|
-
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
133
|
-
assetToken: this.asset(),
|
|
134
|
-
usdcToken: this.usdcToken,
|
|
135
|
-
collateralToken: this.wbtcToken,
|
|
136
|
-
limitBalanceBufferFactor: LIMIT_BALANCE,
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
return new ExtendedSVKVesuStateManager(stateManagerConfig);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
getTag() {
|
|
143
|
-
return `${VesuExtendedMultiplierStrategy.name}:${this.metadata.name}`;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Fetches current WBTC (collateral) and USDC (debt) prices from the pricer.
|
|
148
|
-
* Validates that both prices are finite and positive, throwing if not.
|
|
149
|
-
*/
|
|
150
|
-
async getAssetPrices() {
|
|
151
|
-
const wbtcToken = Global.getDefaultTokens().find(
|
|
152
|
-
(token) => token.symbol === "WBTC"
|
|
153
|
-
)!;
|
|
154
|
-
const usdcToken = Global.getDefaultTokens().find(
|
|
155
|
-
(token) => token.symbol === "USDC"
|
|
156
|
-
)!;
|
|
157
|
-
const collateralPrice = await this.pricer.getPrice(wbtcToken.symbol);
|
|
158
|
-
const debtPrice = await this.pricer.getPrice(usdcToken.symbol);
|
|
159
|
-
|
|
160
|
-
if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
|
|
161
|
-
throw new Error(
|
|
162
|
-
`${this.getTag()} Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
|
|
166
|
-
throw new Error(
|
|
167
|
-
`${this.getTag()} Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return { collateralPrice, debtPrice };
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
async getVesuMultiplyAdapter(): Promise<VesuMultiplyAdapter> {
|
|
175
|
-
const vesuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
176
|
-
(adapter) => adapter.adapter.name === VesuMultiplyAdapter.name,
|
|
177
|
-
);
|
|
178
|
-
if (!vesuAdapter) {
|
|
179
|
-
throw new Error(
|
|
180
|
-
`${this.getTag()} Vesu adapter not configured in metadata.`
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
return vesuAdapter.adapter as VesuMultiplyAdapter;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async getVesuModifyPositionAdapter(): Promise<VesuModifyPositionAdapter> {
|
|
187
|
-
const vesuModifyPositionAdapter = this.metadata.additionalInfo.adapters.find(
|
|
188
|
-
(adapter) => adapter.adapter.name === VesuModifyPositionAdapter.name,
|
|
189
|
-
);
|
|
190
|
-
if (!vesuModifyPositionAdapter) {
|
|
191
|
-
throw new Error(
|
|
192
|
-
`${this.getTag()} Vesu modify position adapter not configured in metadata.`,
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
return vesuModifyPositionAdapter.adapter as VesuModifyPositionAdapter;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
async getUsdcTransferAdapter(): Promise<TokenTransferAdapter> {
|
|
199
|
-
const usdcTransferAdapter = this.metadata.additionalInfo.adapters.find(
|
|
200
|
-
(adapter) => adapter.adapter.name === TokenTransferAdapter.name,
|
|
201
|
-
);
|
|
202
|
-
if (!usdcTransferAdapter) {
|
|
203
|
-
throw new Error(
|
|
204
|
-
`${this.getTag()} Usdc transfer adapter not configured in metadata.`
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
return usdcTransferAdapter.adapter as TokenTransferAdapter;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async getAvnuAdapter(): Promise<AvnuAdapter> {
|
|
211
|
-
const avnuAdapter = this.metadata.additionalInfo.adapters.find(
|
|
212
|
-
(adapter) => adapter.adapter.name === AvnuAdapter.name,
|
|
213
|
-
);
|
|
214
|
-
if (!avnuAdapter) {
|
|
215
|
-
throw new Error(
|
|
216
|
-
`${this.getTag()} Avnu adapter not configured in metadata.`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
return avnuAdapter.adapter as AvnuAdapter;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
async getExtendedAdapter(): Promise<ExtendedAdapter> {
|
|
223
|
-
const extendedAdapter = this.metadata.additionalInfo.adapters.find(
|
|
224
|
-
(adapter) => adapter.adapter.name === ExtendedAdapter.name,
|
|
225
|
-
);
|
|
226
|
-
if (!extendedAdapter) {
|
|
227
|
-
throw new Error(
|
|
228
|
-
`${this.getTag()} Extended adapter not configured in metadata.`
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
if (!extendedAdapter.adapter || !(extendedAdapter.adapter as ExtendedAdapter).client) {
|
|
232
|
-
throw new Error(
|
|
233
|
-
`${this.getTag()} Extended adapter client not initialized.`
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
return extendedAdapter.adapter as ExtendedAdapter;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Creates an ExecutionService wired to this strategy's adapters and config.
|
|
241
|
-
* Use with `stateManager.solve()` to get a SolveResult, then pass it to
|
|
242
|
-
* `executionService.execute(solveResult)` for execution.
|
|
243
|
-
*
|
|
244
|
-
* @param onExecutionEvent - Optional callback for execution lifecycle events (DB persistence, alerts, etc.)
|
|
245
|
-
* @param extendedAcceptableSlippageBps - Slippage for Extended limit orders (default: 10 = 0.1%)
|
|
246
|
-
* @param maxPriceDivergenceBps - Max price divergence between Extended and AVNU (default: 50 = 0.5%)
|
|
247
|
-
*/
|
|
248
|
-
async createExecutionService(opts?: {
|
|
249
|
-
onExecutionEvent?: ExecutionCallback;
|
|
250
|
-
extendedAcceptableSlippageBps?: number;
|
|
251
|
-
maxPriceDivergenceBps?: number;
|
|
252
|
-
}): Promise<ExecutionService> {
|
|
253
|
-
const [
|
|
254
|
-
vesuMultiplyAdapter,
|
|
255
|
-
vesuModifyPositionAdapter,
|
|
256
|
-
extendedAdapter,
|
|
257
|
-
avnuAdapter,
|
|
258
|
-
usdcTransferAdapter,
|
|
259
|
-
] =
|
|
260
|
-
await Promise.all([
|
|
261
|
-
this.getVesuMultiplyAdapter(),
|
|
262
|
-
this.getVesuModifyPositionAdapter(),
|
|
263
|
-
this.getExtendedAdapter(),
|
|
264
|
-
this.getAvnuAdapter(),
|
|
265
|
-
this.getUsdcTransferAdapter(),
|
|
266
|
-
]);
|
|
267
|
-
|
|
268
|
-
const executionConfig: ExecutionConfig = {
|
|
269
|
-
networkConfig: this.config,
|
|
270
|
-
pricer: this.pricer,
|
|
271
|
-
vesuMultiplyAdapter,
|
|
272
|
-
vesuModifyPositionAdapter,
|
|
273
|
-
extendedAdapter,
|
|
274
|
-
avnuAdapter,
|
|
275
|
-
usdcTransferAdapter,
|
|
276
|
-
vaultAllocator: this.metadata.additionalInfo.vaultAllocator,
|
|
277
|
-
walletAddress: this.metadata.additionalInfo.walletAddress,
|
|
278
|
-
wbtcToken: this.wbtcToken,
|
|
279
|
-
usdcToken: this.usdcToken,
|
|
280
|
-
getMerkleTree: () => this.getMerkleTree(),
|
|
281
|
-
getManageCall: (proofs, manageCalls) => this.getManageCall(proofs, manageCalls),
|
|
282
|
-
getBringLiquidityCall: (params) => this.getBringLiquidityCall(params),
|
|
283
|
-
onExecutionEvent: opts?.onExecutionEvent,
|
|
284
|
-
extendedAcceptableSlippageBps: opts?.extendedAcceptableSlippageBps,
|
|
285
|
-
maxPriceDivergenceBps: opts?.maxPriceDivergenceBps,
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
return new ExecutionService(executionConfig);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Calculates the total Assets Under Management across all adapters.
|
|
293
|
-
* Aggregates position values from every adapter, converts to the vault's
|
|
294
|
-
* base asset, and returns the net AUM along with the previous AUM snapshot
|
|
295
|
-
* and per-position breakdowns.
|
|
296
|
-
*/
|
|
297
|
-
async getAUM(): Promise<{
|
|
298
|
-
net: SingleTokenInfo;
|
|
299
|
-
prevAum: Web3Number;
|
|
300
|
-
splits: PositionInfo[];
|
|
301
|
-
}> {
|
|
302
|
-
const allPositions: PositionInfo[] = [];
|
|
303
|
-
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
304
|
-
let positions = await adapter.adapter.getPositions();
|
|
305
|
-
if (positions && positions.length > 0) {
|
|
306
|
-
const filteredPositions = positions;
|
|
307
|
-
allPositions.push(...filteredPositions);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
const assetPrice = await this.pricer.getPrice(this.asset().symbol);
|
|
311
|
-
let netAUM = new Web3Number(0, this.asset().decimals);
|
|
312
|
-
for (let position of allPositions) {
|
|
313
|
-
if (position.tokenInfo.address.eq(this.asset().address)) {
|
|
314
|
-
netAUM = netAUM.plus(position.amount);
|
|
315
|
-
} else {
|
|
316
|
-
netAUM = netAUM.plus(position.usdValue / assetPrice.price);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
// ! IMO should also include USDC in wallet.
|
|
321
|
-
const walletHoldings = await this.getWalletHoldings();
|
|
322
|
-
for (let holding of walletHoldings) {
|
|
323
|
-
if (holding.tokenInfo.address.eq(this.asset().address)) {
|
|
324
|
-
netAUM = netAUM.plus(holding.amount);
|
|
325
|
-
} else {
|
|
326
|
-
netAUM = netAUM.plus(holding.usdValue / assetPrice.price);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const prevAum = await this.getPrevAUM();
|
|
331
|
-
const realAUM: PositionInfo = {
|
|
332
|
-
tokenInfo: this.asset(),
|
|
333
|
-
amount: netAUM,
|
|
334
|
-
usdValue: netAUM.toNumber() * assetPrice.price,
|
|
335
|
-
apy: { apy: netAUM.toNumber() * assetPrice.price, type: APYType.BASE },
|
|
336
|
-
remarks: AUMTypes.FINALISED,
|
|
337
|
-
protocol: Protocols.NONE, // just placeholder
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
const estimatedAUMDelta: PositionInfo = {
|
|
341
|
-
tokenInfo: this.asset(),
|
|
342
|
-
amount: Web3Number.fromWei("0", this.asset().decimals),
|
|
343
|
-
usdValue: 0,
|
|
344
|
-
apy: { apy: 0, type: APYType.BASE },
|
|
345
|
-
remarks: AUMTypes.DEFISPRING,
|
|
346
|
-
protocol: Protocols.NONE, // just placeholder
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
return {
|
|
350
|
-
net: {
|
|
351
|
-
tokenInfo: this.asset(),
|
|
352
|
-
amount: netAUM,
|
|
353
|
-
usdValue: netAUM.toNumber() * assetPrice.price,
|
|
354
|
-
},
|
|
355
|
-
prevAum: prevAum,
|
|
356
|
-
splits: [realAUM, estimatedAUMDelta],
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Computes the maximum additional USDC that can be borrowed from Vesu
|
|
363
|
-
* while keeping the strategy profitable. Uses the Extended funding rate
|
|
364
|
-
* and Vesu supply APY to derive a break-even borrow APY, then queries
|
|
365
|
-
* Vesu for the max borrowable amount at that rate.
|
|
366
|
-
*/
|
|
367
|
-
async getMaxBorrowableAmount(): Promise<Web3Number> {
|
|
368
|
-
const vesuAdapter = await this.getVesuModifyPositionAdapter();
|
|
369
|
-
const extendedAdapter = await this.getExtendedAdapter();
|
|
370
|
-
const extendedFundingRate = new Web3Number(
|
|
371
|
-
(await extendedAdapter.getNetAPY()).toFixed(4),
|
|
372
|
-
0,
|
|
373
|
-
);
|
|
374
|
-
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
375
|
-
if (!extendedPositions || extendedPositions.length === 0) {
|
|
376
|
-
logger.warn(`${this.getTag()} getMaxBorrowableAmount: no extended positions found`);
|
|
377
|
-
return new Web3Number(0, 0);
|
|
378
|
-
}
|
|
379
|
-
const extendePositionSizeUSD = new Web3Number(
|
|
380
|
-
extendedPositions[0].value || 0,
|
|
381
|
-
0,
|
|
382
|
-
);
|
|
383
|
-
const vesuPositions = await vesuAdapter.getPositions();
|
|
384
|
-
const vesuSupplyApy = vesuPositions[0].apy.apy;
|
|
385
|
-
const vesuCollateralSizeUSD = new Web3Number(
|
|
386
|
-
vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
387
|
-
USDC_TOKEN_DECIMALS,
|
|
388
|
-
);
|
|
389
|
-
const vesuDebtSizeUSD = new Web3Number(
|
|
390
|
-
vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
391
|
-
USDC_TOKEN_DECIMALS,
|
|
392
|
-
);
|
|
393
|
-
const num1 = extendePositionSizeUSD.multipliedBy(extendedFundingRate);
|
|
394
|
-
const num2 = vesuCollateralSizeUSD.multipliedBy(vesuSupplyApy);
|
|
395
|
-
const num3 = vesuDebtSizeUSD.abs();
|
|
396
|
-
const maxBorrowApy = num1.plus(num2).minus(0.1).dividedBy(num3);
|
|
397
|
-
const vesuMaxBorrowableResult =
|
|
398
|
-
await vesuAdapter._vesuAdapter.getMaxBorrowableByInterestRate(
|
|
399
|
-
this.config,
|
|
400
|
-
vesuAdapter.config.debt,
|
|
401
|
-
maxBorrowApy.toNumber(),
|
|
402
|
-
);
|
|
403
|
-
return new Web3Number(
|
|
404
|
-
vesuMaxBorrowableResult.maxDebtToHave.toFixed(USDC_TOKEN_DECIMALS),
|
|
405
|
-
USDC_TOKEN_DECIMALS,
|
|
406
|
-
);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Returns the current health metrics for the strategy:
|
|
411
|
-
* [0] Vesu health factor (maxLTV / actualLTV) — higher is safer.
|
|
412
|
-
* [1] Extended margin ratio (as percentage) — higher means more margin available.
|
|
413
|
-
*/
|
|
414
|
-
async getVesuHealthFactors(): Promise<number[]> {
|
|
415
|
-
const vesuAdapter = await this.getVesuModifyPositionAdapter();
|
|
416
|
-
const extendedAdapter = await this.getExtendedAdapter();
|
|
417
|
-
const vesuPositions = await vesuAdapter.getPositions();
|
|
418
|
-
const vesuCollateralSizeUSD = new Web3Number(
|
|
419
|
-
vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
420
|
-
0,
|
|
421
|
-
);
|
|
422
|
-
const vesuDebtSizeUSD = new Web3Number(
|
|
423
|
-
vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS),
|
|
424
|
-
0,
|
|
425
|
-
);
|
|
426
|
-
const actualLtv = vesuDebtSizeUSD.dividedBy(vesuCollateralSizeUSD).abs();
|
|
427
|
-
logger.debug(`${this.getTag()} getVesuHealthFactors: actualLtv=${actualLtv.toNumber()}`);
|
|
428
|
-
const maxLtv = new Web3Number(
|
|
429
|
-
await vesuAdapter._vesuAdapter.getLTVConfig(this.config),
|
|
430
|
-
4,
|
|
431
|
-
);
|
|
432
|
-
const healthFactor = new Web3Number(
|
|
433
|
-
maxLtv.dividedBy(actualLtv).toFixed(4),
|
|
434
|
-
4,
|
|
435
|
-
);
|
|
436
|
-
logger.debug(`${this.getTag()} getVesuHealthFactors: healthFactor=${healthFactor.toNumber()}`);
|
|
437
|
-
const extendedBalance = await extendedAdapter.getExtendedDepositAmount();
|
|
438
|
-
if (!extendedBalance) {
|
|
439
|
-
return [0, 0];
|
|
440
|
-
}
|
|
441
|
-
const extendedLeverage = new Web3Number(
|
|
442
|
-
(Number(extendedBalance.marginRatio) * 100).toFixed(4),
|
|
443
|
-
4,
|
|
444
|
-
);
|
|
445
|
-
logger.debug(`${this.getTag()} getVesuHealthFactors: extendedLeverage=${extendedLeverage.toNumber()}`);
|
|
446
|
-
return [healthFactor.toNumber(), extendedLeverage.toNumber()];
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Calculates the weighted net APY of the strategy across all positions.
|
|
451
|
-
* Combines Vesu supply APY (scaled by 0.1 performance fee) and Extended
|
|
452
|
-
* position APY, weighted by their respective USD values.
|
|
453
|
-
* Also returns per-position APY splits.
|
|
454
|
-
*/
|
|
455
|
-
async netAPY(): Promise<{
|
|
456
|
-
net: number;
|
|
457
|
-
splits: { apy: number; id: string }[];
|
|
458
|
-
}> {
|
|
459
|
-
const allPositions: PositionInfo[] = [];
|
|
460
|
-
for (let adapter of this.metadata.additionalInfo.adapters) {
|
|
461
|
-
if (adapter.adapter.name !== ExtendedAdapter.name) {
|
|
462
|
-
let positions = await adapter.adapter.getPositions();
|
|
463
|
-
if (positions.length > 0) {
|
|
464
|
-
allPositions.push(...positions);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
const extendedAdapter = await this.getExtendedAdapter();
|
|
469
|
-
let vesuPositions = allPositions.filter(
|
|
470
|
-
(item) => item.protocol === Protocols.VESU,
|
|
471
|
-
);
|
|
472
|
-
vesuPositions.map((item) => {
|
|
473
|
-
item.apy.apy = item.apy.apy * 0.1;
|
|
474
|
-
});
|
|
475
|
-
const extendedPositions = await extendedAdapter.getAllOpenPositions();
|
|
476
|
-
if (!extendedPositions || !this.usdcToken) {
|
|
477
|
-
return {
|
|
478
|
-
net: 0,
|
|
479
|
-
splits: [],
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
const extendedPosition = extendedPositions[0] || 0;
|
|
483
|
-
const extendedEquity =
|
|
484
|
-
(await extendedAdapter.getExtendedDepositAmount())?.equity || 0;
|
|
485
|
-
const extendedApy = await extendedAdapter.getNetAPY();
|
|
486
|
-
const totalHoldingsUSDValue =
|
|
487
|
-
allPositions.reduce((acc, curr) => acc + curr.usdValue, 0) +
|
|
488
|
-
Number(extendedEquity);
|
|
489
|
-
const extendedPositionSizeMultipliedByApy =
|
|
490
|
-
Number(extendedPosition.value) * extendedApy;
|
|
491
|
-
let weightedAPYs =
|
|
492
|
-
allPositions.reduce(
|
|
493
|
-
(acc, curr) => acc + curr.apy.apy * curr.usdValue,
|
|
494
|
-
0,
|
|
495
|
-
) + extendedPositionSizeMultipliedByApy;
|
|
496
|
-
const netAPY = weightedAPYs / totalHoldingsUSDValue;
|
|
497
|
-
logger.debug(
|
|
498
|
-
`${this.getTag()} netAPY: holdingsUsd=${totalHoldingsUSDValue}, weightedApy=${weightedAPYs}, net=${netAPY}`,
|
|
499
|
-
);
|
|
500
|
-
allPositions.push({
|
|
501
|
-
tokenInfo: this.usdcToken,
|
|
502
|
-
amount: new Web3Number(extendedPosition?.size || 0, 0),
|
|
503
|
-
usdValue: Number(extendedEquity),
|
|
504
|
-
apy: { apy: extendedApy, type: APYType.BASE },
|
|
505
|
-
remarks: AUMTypes.FINALISED,
|
|
506
|
-
protocol: Protocols.EXTENDED,
|
|
507
|
-
});
|
|
508
|
-
return {
|
|
509
|
-
net: netAPY,
|
|
510
|
-
splits: allPositions.map((p) => ({
|
|
511
|
-
apy: p.apy.apy,
|
|
512
|
-
id: p.remarks ?? "",
|
|
513
|
-
})),
|
|
514
|
-
};
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Fetches the operator wallet's current holdings for USDC and WBTC,
|
|
519
|
-
* returning each token's balance and USD value.
|
|
520
|
-
*/
|
|
521
|
-
async getWalletHoldings(): Promise<
|
|
522
|
-
{
|
|
523
|
-
tokenInfo: TokenInfo;
|
|
524
|
-
amount: Web3Number;
|
|
525
|
-
usdValue: number;
|
|
526
|
-
}[]
|
|
527
|
-
> {
|
|
528
|
-
if (!this.wbtcToken || !this.usdcToken) {
|
|
529
|
-
return [];
|
|
530
|
-
}
|
|
531
|
-
const walletAddress = this.metadata.additionalInfo.walletAddress;
|
|
532
|
-
const usdcWalletBalance = await new ERC20(this.config).balanceOf(
|
|
533
|
-
this.usdcToken.address,
|
|
534
|
-
walletAddress,
|
|
535
|
-
this.usdcToken.decimals,
|
|
536
|
-
);
|
|
537
|
-
const price = await this.pricer.getPrice(this.usdcToken.symbol);
|
|
538
|
-
const usdcUsdValue =
|
|
539
|
-
Number(usdcWalletBalance.toFixed(this.usdcToken.decimals)) * price.price;
|
|
540
|
-
return [
|
|
541
|
-
{
|
|
542
|
-
tokenInfo: this.usdcToken,
|
|
543
|
-
amount: usdcWalletBalance,
|
|
544
|
-
usdValue: usdcUsdValue,
|
|
545
|
-
}
|
|
546
|
-
];
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Configures all adapters (Vesu, Extended, Avnu, TokenTransfer)
|
|
552
|
-
* and registers their leaf adapters on the vault settings. This is the central
|
|
553
|
-
* wiring function that connects the strategy to its underlying protocol adapters.
|
|
554
|
-
*/
|
|
555
|
-
function getLooperSettings(
|
|
556
|
-
collateralSymbol: string,
|
|
557
|
-
underlyingSymbol: string,
|
|
558
|
-
vaultSettings: VesuExtendedStrategySettings,
|
|
559
|
-
pool1: ContractAddr,
|
|
560
|
-
extendedBackendReadUrl: string,
|
|
561
|
-
extendedBackendWriteUrl: string,
|
|
562
|
-
vaultIdExtended: number,
|
|
563
|
-
minimumExtendedMovementAmount: number,
|
|
564
|
-
minimumVesuMovementAmount: number,
|
|
565
|
-
minimumExtendedRetriesDelayForOrderStatus: number,
|
|
566
|
-
minimumExtendedPriceDifferenceForSwapOpen: number,
|
|
567
|
-
maximumExtendedPriceDifferenceForSwapClosing: number,
|
|
568
|
-
) {
|
|
569
|
-
vaultSettings.leafAdapters = [];
|
|
570
|
-
|
|
571
|
-
const wbtcToken = Global.getDefaultTokens().find(
|
|
572
|
-
(token) => token.symbol === collateralSymbol,
|
|
573
|
-
)!;
|
|
574
|
-
const usdcToken = Global.getDefaultTokens().find(
|
|
575
|
-
(token) => token.symbol === underlyingSymbol,
|
|
576
|
-
)!;
|
|
577
|
-
|
|
578
|
-
const baseAdapterConfig: BaseAdapterConfig = {
|
|
579
|
-
baseToken: usdcToken,
|
|
580
|
-
supportedPositions: [
|
|
581
|
-
{ asset: usdcToken, isDebt: true },
|
|
582
|
-
{ asset: wbtcToken, isDebt: false },
|
|
583
|
-
],
|
|
584
|
-
//Since we open 2 positions, we need to add both positions, one is debt another is collateral
|
|
585
|
-
networkConfig: getMainnetConfig(),
|
|
586
|
-
pricer: new PricerFromApi(getMainnetConfig(), Global.getDefaultTokens()),
|
|
587
|
-
vaultAllocator: vaultSettings.vaultAllocator,
|
|
588
|
-
vaultAddress: vaultSettings.vaultAddress,
|
|
589
|
-
};
|
|
590
|
-
|
|
591
|
-
const avnuAdapter = new AvnuAdapter({
|
|
592
|
-
...baseAdapterConfig,
|
|
593
|
-
avnuContract: AVNU_MIDDLEWARE,
|
|
594
|
-
slippage: 0.01,
|
|
595
|
-
baseUrl: AVNU_QUOTE_URL,
|
|
596
|
-
minimumExtendedPriceDifferenceForSwapOpen:
|
|
597
|
-
minimumExtendedPriceDifferenceForSwapOpen,
|
|
598
|
-
maximumExtendedPriceDifferenceForSwapClosing:
|
|
599
|
-
maximumExtendedPriceDifferenceForSwapClosing,
|
|
600
|
-
});
|
|
601
|
-
|
|
602
|
-
const extendedAdapter = new ExtendedAdapter({
|
|
603
|
-
...baseAdapterConfig,
|
|
604
|
-
supportedPositions: [
|
|
605
|
-
{ asset: usdcToken, isDebt: false },
|
|
606
|
-
],
|
|
607
|
-
vaultIdExtended: vaultIdExtended,
|
|
608
|
-
extendedContract: EXTENDED_CONTRACT,
|
|
609
|
-
extendedBackendWriteUrl: extendedBackendWriteUrl,
|
|
610
|
-
extendedBackendReadUrl: extendedBackendReadUrl,
|
|
611
|
-
extendedTimeout: 30000,
|
|
612
|
-
extendedRetries: 3,
|
|
613
|
-
extendedBaseUrl: "https://api.starknet.extended.exchange",
|
|
614
|
-
extendedMarketName: "BTC-USD",
|
|
615
|
-
extendedPrecision: 5,
|
|
616
|
-
avnuAdapter: avnuAdapter,
|
|
617
|
-
retryDelayForOrderStatus: minimumExtendedRetriesDelayForOrderStatus ?? 3000,
|
|
618
|
-
minimumExtendedMovementAmount: minimumExtendedMovementAmount ?? 5, //5 usdcs
|
|
619
|
-
});
|
|
620
|
-
|
|
621
|
-
const vesuMultiplyAdapter = new VesuMultiplyAdapter({
|
|
622
|
-
poolId: pool1,
|
|
623
|
-
collateral: wbtcToken,
|
|
624
|
-
debt: usdcToken,
|
|
625
|
-
marginToken: usdcToken,
|
|
626
|
-
targetHealthFactor: vaultSettings.targetHealthFactor,
|
|
627
|
-
minHealthFactor: vaultSettings.minHealthFactor,
|
|
628
|
-
quoteAmountToFetchPrice: vaultSettings.quoteAmountToFetchPrice,
|
|
629
|
-
...baseAdapterConfig,
|
|
630
|
-
supportedPositions: [
|
|
631
|
-
{ asset: wbtcToken, isDebt: false },
|
|
632
|
-
{ asset: usdcToken, isDebt: true },
|
|
633
|
-
],
|
|
634
|
-
minimumVesuMovementAmount: minimumVesuMovementAmount ?? 5, //5 usdc
|
|
635
|
-
});
|
|
636
|
-
|
|
637
|
-
const vesuModifyPositionMaxLtv = VesuConfig.maxLtv;
|
|
638
|
-
const vesuModifyPositionTargetLtv = VesuConfig.targetLtv;
|
|
639
|
-
const vesuModifyPositionAdapter = new VesuModifyPositionAdapter({
|
|
640
|
-
poolId: pool1,
|
|
641
|
-
collateral: wbtcToken,
|
|
642
|
-
debt: usdcToken,
|
|
643
|
-
targetLtv: vesuModifyPositionTargetLtv,
|
|
644
|
-
maxLtv: vesuModifyPositionMaxLtv,
|
|
645
|
-
...baseAdapterConfig,
|
|
646
|
-
supportedPositions: [
|
|
647
|
-
{ asset: wbtcToken, isDebt: false },
|
|
648
|
-
{ asset: usdcToken, isDebt: true },
|
|
649
|
-
],
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
// Transfers USDC between the vault allocator (fromAddress) and the operator wallet (toAddress)
|
|
653
|
-
const usdcTransferAdapter = new TokenTransferAdapter({
|
|
654
|
-
...baseAdapterConfig,
|
|
655
|
-
baseToken: usdcToken,
|
|
656
|
-
supportedPositions: [{ asset: usdcToken, isDebt: false }],
|
|
657
|
-
fromAddress: vaultSettings.vaultAllocator,
|
|
658
|
-
toAddress: ContractAddr.from(vaultSettings.walletAddress),
|
|
659
|
-
});
|
|
660
|
-
|
|
661
|
-
vaultSettings.adapters.push({
|
|
662
|
-
id: `${vesuMultiplyAdapter.name}_${wbtcToken.symbol}_${usdcToken.symbol}`,
|
|
663
|
-
adapter: vesuMultiplyAdapter,
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
vaultSettings.adapters.push({
|
|
667
|
-
id: `${vesuModifyPositionAdapter.name}_${wbtcToken.symbol}_${usdcToken.symbol}`,
|
|
668
|
-
adapter: vesuModifyPositionAdapter,
|
|
669
|
-
});
|
|
670
|
-
|
|
671
|
-
vaultSettings.adapters.push({
|
|
672
|
-
id: `${usdcTransferAdapter.name}_${usdcToken.symbol}`,
|
|
673
|
-
adapter: usdcTransferAdapter,
|
|
674
|
-
});
|
|
675
|
-
|
|
676
|
-
vaultSettings.adapters.push({
|
|
677
|
-
id: `${extendedAdapter.name}_${wbtcToken.symbol}`,
|
|
678
|
-
adapter: extendedAdapter,
|
|
679
|
-
});
|
|
680
|
-
|
|
681
|
-
vaultSettings.adapters.push({
|
|
682
|
-
id: `${avnuAdapter.name}_${wbtcToken.symbol}`,
|
|
683
|
-
adapter: avnuAdapter,
|
|
684
|
-
});
|
|
685
|
-
|
|
686
|
-
const commonAdapter = new CommonAdapter({
|
|
687
|
-
id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
|
|
688
|
-
vaultAddress: vaultSettings.vaultAddress,
|
|
689
|
-
vaultAllocator: vaultSettings.vaultAllocator,
|
|
690
|
-
manager: vaultSettings.manager,
|
|
691
|
-
asset: usdcToken.address,
|
|
692
|
-
});
|
|
693
|
-
|
|
694
|
-
vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getDepositLeaf());
|
|
695
|
-
vaultSettings.leafAdapters.push(() => vesuMultiplyAdapter.getWithdrawLeaf());
|
|
696
|
-
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getDepositLeaf());
|
|
697
|
-
vaultSettings.leafAdapters.push(() => vesuModifyPositionAdapter.getWithdrawLeaf());
|
|
698
|
-
vaultSettings.leafAdapters.push(() => extendedAdapter.getDepositLeaf());
|
|
699
|
-
vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
|
|
700
|
-
vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
|
|
701
|
-
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getDepositLeaf());
|
|
702
|
-
vaultSettings.leafAdapters.push(() => usdcTransferAdapter.getWithdrawLeaf());
|
|
703
|
-
vaultSettings.leafAdapters.push(
|
|
704
|
-
commonAdapter
|
|
705
|
-
.getApproveAdapter(
|
|
706
|
-
usdcToken.address,
|
|
707
|
-
vaultSettings.vaultAddress,
|
|
708
|
-
UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY,
|
|
709
|
-
)
|
|
710
|
-
.bind(commonAdapter),
|
|
711
|
-
);
|
|
712
|
-
|
|
713
|
-
vaultSettings.leafAdapters.push(
|
|
714
|
-
commonAdapter
|
|
715
|
-
.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY)
|
|
716
|
-
.bind(commonAdapter),
|
|
717
|
-
);
|
|
718
|
-
return vaultSettings;
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
function getDescription(tokenSymbol: string, underlyingSymbol: string) {
|
|
722
|
-
return VaultDescription(tokenSymbol, underlyingSymbol);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
export default function VaultDescription(
|
|
726
|
-
lstSymbol: string,
|
|
727
|
-
underlyingSymbol: string,
|
|
728
|
-
) {
|
|
729
|
-
const containerStyle = {
|
|
730
|
-
maxWidth: "800px",
|
|
731
|
-
margin: "0 auto",
|
|
732
|
-
backgroundColor: "#111",
|
|
733
|
-
color: "#eee",
|
|
734
|
-
fontFamily: "Arial, sans-serif",
|
|
735
|
-
borderRadius: "12px",
|
|
736
|
-
};
|
|
737
|
-
|
|
738
|
-
return (
|
|
739
|
-
<div style={containerStyle}>
|
|
740
|
-
<h1 style={{ fontSize: "18px", marginBottom: "10px" }}>
|
|
741
|
-
Liquidation risk managed leverged {lstSymbol} Vault
|
|
742
|
-
</h1>
|
|
743
|
-
<p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
744
|
-
This Levered Endur {lstSymbol} vault is a tokenized leveraged Vault,
|
|
745
|
-
auto-compounding strategy that takes upto 5x leverage on {lstSymbol} by
|
|
746
|
-
borrow {underlyingSymbol}. Borrowed amount is swapped to {lstSymbol} to
|
|
747
|
-
create leverage. Depositors receive vault shares that represent a
|
|
748
|
-
proportional claim on the underlying assets and accrued yield.
|
|
749
|
-
</p>
|
|
750
|
-
|
|
751
|
-
<p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
752
|
-
This vault uses Vesu for lending and borrowing. The oracle used by this
|
|
753
|
-
pool is a{" "}
|
|
754
|
-
{highlightTextWithLinks("conversion rate oracle", [
|
|
755
|
-
{
|
|
756
|
-
highlight: "conversion rate oracle",
|
|
757
|
-
link: "https://docs.pragma.build/starknet/development#conversion-rate",
|
|
758
|
-
},
|
|
759
|
-
])}{" "}
|
|
760
|
-
which is resilient to liquidity issues and price volatility, hence
|
|
761
|
-
reducing the risk of liquidation. However, overtime, if left
|
|
762
|
-
un-monitored, debt can increase enough to trigger a liquidation. But no
|
|
763
|
-
worries, our continuous monitoring systems look for situations with
|
|
764
|
-
reduced health factor and balance collateral/debt to bring it back to
|
|
765
|
-
safe levels. With Troves, you can have a peaceful sleep.
|
|
766
|
-
</p>
|
|
767
|
-
|
|
768
|
-
<div
|
|
769
|
-
style={{
|
|
770
|
-
backgroundColor: "#222",
|
|
771
|
-
padding: "10px",
|
|
772
|
-
borderRadius: "8px",
|
|
773
|
-
marginBottom: "20px",
|
|
774
|
-
border: "1px solid #444",
|
|
775
|
-
}}
|
|
776
|
-
>
|
|
777
|
-
<p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
778
|
-
<strong>Withdrawals:</strong> Requests can take up to{" "}
|
|
779
|
-
<strong>1-2 hours</strong> to process as the vault unwinds and settles
|
|
780
|
-
routing.
|
|
781
|
-
</p>
|
|
782
|
-
</div>
|
|
783
|
-
<div
|
|
784
|
-
style={{
|
|
785
|
-
backgroundColor: "#222",
|
|
786
|
-
padding: "10px",
|
|
787
|
-
borderRadius: "8px",
|
|
788
|
-
marginBottom: "20px",
|
|
789
|
-
border: "1px solid #444",
|
|
790
|
-
}}
|
|
791
|
-
>
|
|
792
|
-
<p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
793
|
-
<strong>Debt limits:</strong> Pools on Vesu have debt caps that are
|
|
794
|
-
gradually increased over time. Until caps are raised, deposited Tokens
|
|
795
|
-
remain in the vault, generating a shared net return for all
|
|
796
|
-
depositors. There is no additional fee taken by Troves on Yield
|
|
797
|
-
token's APY, its only on added gain.
|
|
798
|
-
</p>
|
|
799
|
-
</div>
|
|
800
|
-
{/* <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
|
|
801
|
-
<p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
802
|
-
<strong>APY assumptions:</strong> APY shown is the max possible value given current LST and borrowing rates. True APY will be subject to the actual leverage, based on above point. More insights on exact APY will be added soon.
|
|
803
|
-
</p>
|
|
804
|
-
</div> */}
|
|
805
|
-
</div>
|
|
806
|
-
);
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
|
|
810
|
-
vaultAddress: ContractAddr.from(
|
|
811
|
-
"0x772d6cf5038c18ff5ab89f8945017bbf4d2c6959891339975c70a4f74ac6c8e",
|
|
812
|
-
),
|
|
813
|
-
manager: ContractAddr.from(
|
|
814
|
-
"0x3340c9d7231838e2dccff72b9004f1598a74e65c74b954f07fe1ea19d04a625",
|
|
815
|
-
),
|
|
816
|
-
vaultAllocator: ContractAddr.from(
|
|
817
|
-
"0x537353b35eee5ca2d9a45eb646977baddd4e89ce870a231dcada79884117292",
|
|
818
|
-
),
|
|
819
|
-
redeemRequestNFT: ContractAddr.from(
|
|
820
|
-
"0x6117d1a8c72c0457948083757e1a17ee8c0833b969d5c959b629e5f8feb56ec",
|
|
821
|
-
),
|
|
822
|
-
aumOracle: ContractAddr.from(
|
|
823
|
-
"0x6d7d68045bf5e0b5a4cec43241549851cb9645f7a73a20894152165dbe7083a",
|
|
824
|
-
),
|
|
825
|
-
leafAdapters: [],
|
|
826
|
-
adapters: [],
|
|
827
|
-
targetHealthFactor: 1.4,
|
|
828
|
-
minHealthFactor: 1.05,
|
|
829
|
-
underlyingToken: Global.getDefaultTokens().find(
|
|
830
|
-
(token) => token.symbol === "USDC",
|
|
831
|
-
)!,
|
|
832
|
-
quoteAmountToFetchPrice: new Web3Number(
|
|
833
|
-
"0.001",
|
|
834
|
-
Global.getDefaultTokens().find((token) => token.symbol === "WBTC")!
|
|
835
|
-
.decimals,
|
|
836
|
-
),
|
|
837
|
-
borrowable_assets: [
|
|
838
|
-
Global.getDefaultTokens().find((token) => token.symbol === "USDC")!,
|
|
839
|
-
],
|
|
840
|
-
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
|
|
841
|
-
walletAddress: '0x024b563C1C7d41B32BF4EFB9F38828508a65Be2d6e25268E9f63F22C5e9E51c5',
|
|
842
|
-
};
|
|
843
|
-
|
|
844
|
-
const pureUsdc: VesuExtendedStrategySettings = {
|
|
845
|
-
vaultAddress: ContractAddr.from(
|
|
846
|
-
"0x745c972db65bdee10022fd875dd328c7f40a90849135b6a0f875a40f3c632ae",
|
|
847
|
-
),
|
|
848
|
-
manager: ContractAddr.from(
|
|
849
|
-
"0x364e0894edefb616ec090f57f5c0274517fcd98ab276ae1f021c5e962fa1deb",
|
|
850
|
-
),
|
|
851
|
-
vaultAllocator: ContractAddr.from(
|
|
852
|
-
"0x6fceed28e03a96091877568893df0dd89b9bb80fec30da2b742dacbd5526179",
|
|
853
|
-
),
|
|
854
|
-
redeemRequestNFT: ContractAddr.from(
|
|
855
|
-
"0x501c2b87728e22c6dfcebe4c0b2b3a9fba5845606e4d59fa7bf591badcbb42",
|
|
856
|
-
),
|
|
857
|
-
aumOracle: ContractAddr.from(
|
|
858
|
-
"0x6ccd95f5765242695d3c75e1440b1d0b30efac8babb864ce15729977b97cb82",
|
|
859
|
-
),
|
|
860
|
-
leafAdapters: [],
|
|
861
|
-
adapters: [],
|
|
862
|
-
targetHealthFactor: 1.4,
|
|
863
|
-
minHealthFactor: 1.35,
|
|
864
|
-
underlyingToken: Global.getDefaultTokens().find(
|
|
865
|
-
(token) => token.symbol === "USDC",
|
|
866
|
-
)!,
|
|
867
|
-
quoteAmountToFetchPrice: new Web3Number(
|
|
868
|
-
"0.001",
|
|
869
|
-
Global.getDefaultTokens().find((token) => token.symbol === "USDC")!
|
|
870
|
-
.decimals,
|
|
871
|
-
),
|
|
872
|
-
borrowable_assets: [
|
|
873
|
-
Global.getDefaultTokens().find((token) => token.symbol === "USDC")!,
|
|
874
|
-
],
|
|
875
|
-
minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
|
|
876
|
-
walletAddress: '0x058571C23da5FEdd4e36003FAE3fE2fA9782f2692E552f081839142B10770D0B',
|
|
877
|
-
};
|
|
878
|
-
|
|
879
|
-
export const VesuExtendedTestStrategies = (
|
|
880
|
-
extendedBackendReadUrl: string,
|
|
881
|
-
extendedBackendWriteUrl: string,
|
|
882
|
-
vaultIdExtended: number,
|
|
883
|
-
minimumExtendedMovementAmount: number,
|
|
884
|
-
minimumVesuMovementAmount: number,
|
|
885
|
-
minimumExtendedRetriesDelayForOrderStatus: number,
|
|
886
|
-
minimumExtendedPriceDifferenceForSwapOpen: number,
|
|
887
|
-
maximumExtendedPriceDifferenceForSwapClosing: number,
|
|
888
|
-
): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
|
|
889
|
-
return [
|
|
890
|
-
getStrategySettingsVesuExtended(
|
|
891
|
-
0, // index
|
|
892
|
-
"WBTC",
|
|
893
|
-
"USDC",
|
|
894
|
-
re7UsdcPrimeDevansh,
|
|
895
|
-
false,
|
|
896
|
-
false,
|
|
897
|
-
extendedBackendReadUrl,
|
|
898
|
-
extendedBackendWriteUrl,
|
|
899
|
-
vaultIdExtended,
|
|
900
|
-
minimumExtendedMovementAmount,
|
|
901
|
-
minimumVesuMovementAmount,
|
|
902
|
-
minimumExtendedRetriesDelayForOrderStatus,
|
|
903
|
-
minimumExtendedPriceDifferenceForSwapOpen,
|
|
904
|
-
maximumExtendedPriceDifferenceForSwapClosing,
|
|
905
|
-
),
|
|
906
|
-
getStrategySettingsVesuExtended(
|
|
907
|
-
1, // index
|
|
908
|
-
"WBTC",
|
|
909
|
-
"USDC",
|
|
910
|
-
pureUsdc,
|
|
911
|
-
false,
|
|
912
|
-
false,
|
|
913
|
-
extendedBackendReadUrl,
|
|
914
|
-
extendedBackendWriteUrl,
|
|
915
|
-
vaultIdExtended,
|
|
916
|
-
minimumExtendedMovementAmount,
|
|
917
|
-
minimumVesuMovementAmount,
|
|
918
|
-
minimumExtendedRetriesDelayForOrderStatus,
|
|
919
|
-
minimumExtendedPriceDifferenceForSwapOpen,
|
|
920
|
-
maximumExtendedPriceDifferenceForSwapClosing,
|
|
921
|
-
),
|
|
922
|
-
];
|
|
923
|
-
};
|
|
924
|
-
|
|
925
|
-
/**
|
|
926
|
-
* Constructs a complete IStrategyMetadata object for a Vesu-Extended strategy,
|
|
927
|
-
* including adapter wiring, risk configuration, FAQ, and UI description.
|
|
928
|
-
*/
|
|
929
|
-
function getStrategySettingsVesuExtended(
|
|
930
|
-
index: number,
|
|
931
|
-
collateralSymbol: string,
|
|
932
|
-
underlyingSymbol: string,
|
|
933
|
-
addresses: VesuExtendedStrategySettings,
|
|
934
|
-
isPreview: boolean = false,
|
|
935
|
-
isLST: boolean,
|
|
936
|
-
extendedBackendReadUrl: string,
|
|
937
|
-
extendedBackendWriteUrl: string,
|
|
938
|
-
vaultIdExtended: number,
|
|
939
|
-
minimumExtendedMovementAmount: number,
|
|
940
|
-
minimumVesuMovementAmount: number,
|
|
941
|
-
minimumExtendedRetriesDelayForOrderStatus: number,
|
|
942
|
-
minimumExtendedPriceDifferenceForSwapOpen: number,
|
|
943
|
-
maximumExtendedPriceDifferenceForSwapClosing: number,
|
|
944
|
-
): IStrategyMetadata<VesuExtendedStrategySettings> {
|
|
945
|
-
return {
|
|
946
|
-
id: `extended_${underlyingSymbol.toLowerCase()}_test_${index}`,
|
|
947
|
-
name: `Extended Test ${underlyingSymbol} ${index}`,
|
|
948
|
-
description: getDescription(collateralSymbol, underlyingSymbol),
|
|
949
|
-
address: addresses.vaultAddress,
|
|
950
|
-
launchBlock: 0,
|
|
951
|
-
type: "Other",
|
|
952
|
-
vaultType: {
|
|
953
|
-
type: VaultType.DELTA_NEUTRAL,
|
|
954
|
-
description: "Delta Neutral strategy using extended position on Vesu"
|
|
955
|
-
},
|
|
956
|
-
depositTokens: [
|
|
957
|
-
Global.getDefaultTokens().find(
|
|
958
|
-
(token) => token.symbol === underlyingSymbol,
|
|
959
|
-
)!,
|
|
960
|
-
],
|
|
961
|
-
additionalInfo: getLooperSettings(
|
|
962
|
-
collateralSymbol,
|
|
963
|
-
underlyingSymbol,
|
|
964
|
-
addresses,
|
|
965
|
-
VesuPools.Re7USDCPrime,
|
|
966
|
-
extendedBackendReadUrl,
|
|
967
|
-
extendedBackendWriteUrl,
|
|
968
|
-
vaultIdExtended,
|
|
969
|
-
minimumExtendedMovementAmount,
|
|
970
|
-
minimumVesuMovementAmount,
|
|
971
|
-
minimumExtendedRetriesDelayForOrderStatus,
|
|
972
|
-
minimumExtendedPriceDifferenceForSwapOpen,
|
|
973
|
-
maximumExtendedPriceDifferenceForSwapClosing,
|
|
974
|
-
),
|
|
975
|
-
risk: {
|
|
976
|
-
riskFactor: _riskFactor,
|
|
977
|
-
netRisk:
|
|
978
|
-
_riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
979
|
-
_riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
980
|
-
notARisks: getNoRiskTags(_riskFactor),
|
|
981
|
-
},
|
|
982
|
-
auditUrl: AUDIT_URL,
|
|
983
|
-
protocols: [Protocols.ENDUR, Protocols.VESU],
|
|
984
|
-
contractDetails: getContractDetails(addresses),
|
|
985
|
-
faqs: getFAQs(collateralSymbol, underlyingSymbol, isLST),
|
|
986
|
-
investmentSteps: getInvestmentSteps(collateralSymbol, underlyingSymbol),
|
|
987
|
-
isPreview: isPreview,
|
|
988
|
-
apyMethodology: isLST
|
|
989
|
-
? "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."
|
|
990
|
-
: "Current annualized APY in terms of base asset of the Yield Token. There is no additional fee taken by Troves on yield token APY. We charge a 10% performance fee on the additional gain which is already accounted in the APY shown.",
|
|
991
|
-
security: {
|
|
992
|
-
auditStatus: AuditStatus.NOT_AUDITED,
|
|
993
|
-
sourceCode: {
|
|
994
|
-
type: SourceCodeType.OPEN_SOURCE,
|
|
995
|
-
contractLink: AUDIT_URL,
|
|
996
|
-
},
|
|
997
|
-
accessControl: {
|
|
998
|
-
type: AccessControlType.MULTISIG_ACCOUNT,
|
|
999
|
-
addresses: [addresses.vaultAddress],
|
|
1000
|
-
timeLock: "None",
|
|
1001
|
-
},
|
|
1002
|
-
},
|
|
1003
|
-
redemptionInfo: {
|
|
1004
|
-
instantWithdrawalVault: InstantWithdrawalVault.NO,
|
|
1005
|
-
redemptionsInfo: [{
|
|
1006
|
-
title: "Up to $500k",
|
|
1007
|
-
description: "1-24 hours",
|
|
1008
|
-
}],
|
|
1009
|
-
alerts: [],
|
|
1010
|
-
},
|
|
1011
|
-
usualTimeToEarnings: null,
|
|
1012
|
-
usualTimeToEarningsDescription: null,
|
|
1013
|
-
};
|
|
1014
|
-
}
|