@strkfarm/sdk 2.0.0-dev.40 → 2.0.0-dev.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.global.js +407 -208
- package/dist/index.browser.mjs +425 -225
- package/dist/index.d.ts +38 -14
- package/dist/index.js +427 -225
- package/dist/index.mjs +426 -225
- package/package.json +4 -5
- package/src/global.ts +36 -34
- package/src/interfaces/common.tsx +6 -0
- package/src/modules/index.ts +1 -0
- package/src/modules/pricer-avnu-api.ts +114 -0
- package/src/modules/pricer.ts +63 -45
- package/src/node/pricer-redis.ts +1 -0
- package/src/strategies/ekubo-cl-vault.tsx +3 -0
- package/src/strategies/svk-strategy.ts +159 -2
- package/src/strategies/token-boosted-xstrk-carry-strategy.tsx +46 -9
- package/src/strategies/universal-lst-muliplier-strategy.tsx +90 -19
- package/src/strategies/universal-strategy.tsx +216 -372
- package/src/strategies/yoloVault.ts +3 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
2
|
-
import { SingleActionAmount, SingleTokenInfo
|
|
2
|
+
import { SingleActionAmount, SingleTokenInfo } from "./base-strategy";
|
|
3
3
|
import { PricerBase } from "@/modules/pricerBase";
|
|
4
4
|
import { FAQ, getNoRiskTags, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, StrategyTag, VaultPosition, AuditStatus, SourceCodeType, AccessControlType, InstantWithdrawalVault, StrategyLiveStatus, StrategySettings, VaultType, RedemptionInfo, UnwrapLabsCurator, getMainnetConfig } from "@/interfaces";
|
|
5
5
|
import { BlockIdentifier, Call, CallData, Contract, num, uint256 } from "starknet";
|
|
@@ -35,7 +35,7 @@ export interface UniversalStrategySettings {
|
|
|
35
35
|
|
|
36
36
|
// Useful for returning adapter class objects that can compute
|
|
37
37
|
// certain things for us (e.g. positions, hfs)
|
|
38
|
-
adapters: {id: string, adapter: BaseAdapter<DepositParams, WithdrawParams>}[]
|
|
38
|
+
adapters: { id: string, adapter: BaseAdapter<DepositParams, WithdrawParams> }[]
|
|
39
39
|
|
|
40
40
|
targetHealthFactor: number,
|
|
41
41
|
minHealthFactor: number
|
|
@@ -57,15 +57,15 @@ export class UniversalStrategy<
|
|
|
57
57
|
> extends SVKStrategy<S> {
|
|
58
58
|
|
|
59
59
|
constructor(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
config: IConfig,
|
|
61
|
+
pricer: PricerBase,
|
|
62
|
+
metadata: IStrategyMetadata<S>
|
|
63
|
+
) {
|
|
64
|
+
super(config, pricer, metadata);
|
|
65
|
+
assert(
|
|
66
|
+
metadata.depositTokens.length === 1,
|
|
67
|
+
"VesuRebalance only supports 1 deposit token",
|
|
68
|
+
);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
getMerkleTree() {
|
|
@@ -155,35 +155,6 @@ export class UniversalStrategy<
|
|
|
155
155
|
return [call];
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
async getUserTVL(user: ContractAddr, blockIdentifier: BlockIdentifier = "latest") {
|
|
159
|
-
const shares: any = await this.contract.call("balanceOf", [user.address], { blockIdentifier });
|
|
160
|
-
const assets: any = await this.contract.call(
|
|
161
|
-
"convert_to_assets",
|
|
162
|
-
[uint256.bnToUint256(shares)],
|
|
163
|
-
{ blockIdentifier }
|
|
164
|
-
);
|
|
165
|
-
const amount = Web3Number.fromWei(
|
|
166
|
-
assets.toString(),
|
|
167
|
-
this.metadata.depositTokens[0].decimals
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
// Convert blockIdentifier to block number for pricer if it's a number
|
|
171
|
-
const blockNumber = typeof blockIdentifier === 'number' || typeof blockIdentifier === 'bigint'
|
|
172
|
-
? Number(blockIdentifier)
|
|
173
|
-
: undefined;
|
|
174
|
-
|
|
175
|
-
let price = await this.pricer.getPrice(
|
|
176
|
-
this.metadata.depositTokens[0].symbol,
|
|
177
|
-
blockNumber
|
|
178
|
-
);
|
|
179
|
-
const usdValue = Number(amount.toFixed(6)) * price.price;
|
|
180
|
-
return {
|
|
181
|
-
tokenInfo: this.asset(),
|
|
182
|
-
amount,
|
|
183
|
-
usdValue
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
158
|
async getVesuAPYs() {
|
|
188
159
|
// get Vesu pools, positions and APYs
|
|
189
160
|
const vesuAdapters = this.getVesuAdapters();
|
|
@@ -233,11 +204,13 @@ export class UniversalStrategy<
|
|
|
233
204
|
*/
|
|
234
205
|
async netAPY(): Promise<{ net: number, splits: { apy: number, id: string }[] }> {
|
|
235
206
|
if (this.metadata.isPreview) {
|
|
236
|
-
return {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
207
|
+
return {
|
|
208
|
+
net: 0, splits: [{
|
|
209
|
+
apy: 0, id: 'base'
|
|
210
|
+
}, {
|
|
211
|
+
apy: 0, id: 'defispring'
|
|
212
|
+
}]
|
|
213
|
+
};
|
|
241
214
|
}
|
|
242
215
|
|
|
243
216
|
const { positions, baseAPYs, rewardAPYs } = await this.getVesuAPYs();
|
|
@@ -259,22 +232,26 @@ export class UniversalStrategy<
|
|
|
259
232
|
protected async returnNetAPY(baseAPYs: number[], rewardAPYs: number[], weights: number[], prevAUMUSD: Web3Number) {
|
|
260
233
|
// If no positions, return 0
|
|
261
234
|
if (weights.every(p => p == 0)) {
|
|
262
|
-
return {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
235
|
+
return {
|
|
236
|
+
net: 0, splits: [{
|
|
237
|
+
apy: 0, id: 'base'
|
|
238
|
+
}, {
|
|
239
|
+
apy: 0, id: 'defispring'
|
|
240
|
+
}]
|
|
241
|
+
};
|
|
267
242
|
}
|
|
268
243
|
|
|
269
244
|
const baseAPY = this.computeAPY(baseAPYs, weights, prevAUMUSD);
|
|
270
245
|
const rewardAPY = this.computeAPY(rewardAPYs, weights, prevAUMUSD);
|
|
271
246
|
const netAPY = baseAPY + rewardAPY;
|
|
272
247
|
logger.verbose(`${this.metadata.name}::netAPY: net: ${netAPY}, baseAPY: ${baseAPY}, rewardAPY: ${rewardAPY}`);
|
|
273
|
-
return {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
248
|
+
return {
|
|
249
|
+
net: netAPY, splits: [{
|
|
250
|
+
apy: baseAPY, id: 'base'
|
|
251
|
+
}, {
|
|
252
|
+
apy: rewardAPY, id: 'defispring'
|
|
253
|
+
}]
|
|
254
|
+
};
|
|
278
255
|
}
|
|
279
256
|
|
|
280
257
|
protected async getUnusedBalanceAPY() {
|
|
@@ -290,144 +267,6 @@ export class UniversalStrategy<
|
|
|
290
267
|
return weightedSum / currentAUM.toNumber();
|
|
291
268
|
}
|
|
292
269
|
|
|
293
|
-
/**
|
|
294
|
-
* Calculates user realized APY based on trueSharesBasedAPY method.
|
|
295
|
-
* Returns the APY as a number.
|
|
296
|
-
*/
|
|
297
|
-
async getUserRealizedAPY(
|
|
298
|
-
blockIdentifier: BlockIdentifier = "latest",
|
|
299
|
-
sinceBlocks = 600000
|
|
300
|
-
): Promise<number> {
|
|
301
|
-
logger.verbose(
|
|
302
|
-
`${this.getTag()}: getUserRealizedAPY => starting with blockIdentifier=${blockIdentifier}, sinceBlocks=${sinceBlocks}`
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
// Determine current block number and timestamp
|
|
306
|
-
let blockNow =
|
|
307
|
-
typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint"
|
|
308
|
-
? Number(blockIdentifier)
|
|
309
|
-
: (await this.config.provider.getBlockLatestAccepted()).block_number;
|
|
310
|
-
const blockNowTime =
|
|
311
|
-
typeof blockIdentifier === "number" || typeof blockIdentifier === "bigint"
|
|
312
|
-
? (await this.config.provider.getBlockWithTxs(blockIdentifier)).timestamp
|
|
313
|
-
: new Date().getTime() / 1000;
|
|
314
|
-
|
|
315
|
-
// Look back window, but never before launch block
|
|
316
|
-
const blockBefore = Math.max(
|
|
317
|
-
blockNow - sinceBlocks,
|
|
318
|
-
this.metadata.launchBlock
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
// TVL amounts (in underlying token units) and supply at current reference block
|
|
322
|
-
const assetsNowRaw: bigint = await this.contract.call("total_assets", [], {
|
|
323
|
-
blockIdentifier,
|
|
324
|
-
}) as bigint;
|
|
325
|
-
const amountNow = Web3Number.fromWei(
|
|
326
|
-
assetsNowRaw.toString(),
|
|
327
|
-
this.metadata.depositTokens[0].decimals
|
|
328
|
-
);
|
|
329
|
-
|
|
330
|
-
const supplyNowRaw: bigint = await this.contract.call("total_supply", [], {
|
|
331
|
-
blockIdentifier,
|
|
332
|
-
}) as bigint;
|
|
333
|
-
const supplyNow = Web3Number.fromWei(supplyNowRaw.toString(), 18);
|
|
334
|
-
|
|
335
|
-
// Historical TVL and supply
|
|
336
|
-
const assetsBeforeRaw: bigint = await this.contract.call(
|
|
337
|
-
"total_assets",
|
|
338
|
-
[],
|
|
339
|
-
{ blockIdentifier: blockBefore }
|
|
340
|
-
) as bigint;
|
|
341
|
-
const amountBefore = Web3Number.fromWei(
|
|
342
|
-
assetsBeforeRaw.toString(),
|
|
343
|
-
this.metadata.depositTokens[0].decimals
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
const supplyBeforeRaw: bigint = await this.contract.call(
|
|
347
|
-
"total_supply",
|
|
348
|
-
[],
|
|
349
|
-
{ blockIdentifier: blockBefore }
|
|
350
|
-
) as bigint;
|
|
351
|
-
const supplyBefore = Web3Number.fromWei(supplyBeforeRaw.toString(), 18);
|
|
352
|
-
|
|
353
|
-
const blockBeforeInfo = await this.config.provider.getBlockWithTxs(
|
|
354
|
-
blockBefore
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
// Calculate assets per share
|
|
358
|
-
const assetsPerShareNow = amountNow
|
|
359
|
-
.multipliedBy(1e18)
|
|
360
|
-
.dividedBy(supplyNow.toString());
|
|
361
|
-
|
|
362
|
-
const assetsPerShareBf = amountBefore
|
|
363
|
-
.multipliedBy(1e18)
|
|
364
|
-
.dividedBy(supplyBefore.toString());
|
|
365
|
-
|
|
366
|
-
const timeDiffSeconds = blockNowTime - blockBeforeInfo.timestamp;
|
|
367
|
-
|
|
368
|
-
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsNow: ${amountNow.toString()}`);
|
|
369
|
-
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsBefore: ${amountBefore.toString()}`);
|
|
370
|
-
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsPerShareNow: ${assetsPerShareNow.toString()}`);
|
|
371
|
-
logger.verbose(`${this.getTag()} [getUserRealizedAPY] assetsPerShareBf: ${assetsPerShareBf.toString()}`);
|
|
372
|
-
logger.verbose(`${this.getTag()} [getUserRealizedAPY] Supply before: ${supplyBefore.toString()}`);
|
|
373
|
-
logger.verbose(`${this.getTag()} [getUserRealizedAPY] Supply now: ${supplyNow.toString()}`);
|
|
374
|
-
logger.verbose(`${this.getTag()} [getUserRealizedAPY] Time diff in seconds: ${timeDiffSeconds}`);
|
|
375
|
-
|
|
376
|
-
const apyForGivenBlocks =
|
|
377
|
-
Number(
|
|
378
|
-
assetsPerShareNow
|
|
379
|
-
.minus(assetsPerShareBf)
|
|
380
|
-
.multipliedBy(10000)
|
|
381
|
-
.dividedBy(assetsPerShareBf)
|
|
382
|
-
) / 10000;
|
|
383
|
-
|
|
384
|
-
return (apyForGivenBlocks * (365 * 24 * 3600)) / timeDiffSeconds;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
async getUserPositionCards(input: UserPositionCardsInput): Promise<UserPositionCard[]> {
|
|
388
|
-
const { user, investmentFlows = [] } = input;
|
|
389
|
-
const [userTVL] = await Promise.all([
|
|
390
|
-
this.getUserTVL(user),
|
|
391
|
-
]);
|
|
392
|
-
const cards: UserPositionCard[] = [
|
|
393
|
-
{
|
|
394
|
-
title: "Your Holdings",
|
|
395
|
-
tooltip: "Your Holdings",
|
|
396
|
-
value: this.formatTokenAmountForCard(userTVL.amount, userTVL.tokenInfo),
|
|
397
|
-
subValue: `≈ ${this.formatUSDForCard(userTVL.usdValue)}`,
|
|
398
|
-
subValueColor: "positive",
|
|
399
|
-
},
|
|
400
|
-
];
|
|
401
|
-
|
|
402
|
-
let lifetimeAmount = userTVL.amount.multipliedBy(0);
|
|
403
|
-
let lifetimeTokenInfo = userTVL.tokenInfo;
|
|
404
|
-
let lifetimeUsdValue = 0;
|
|
405
|
-
if (investmentFlows.length > 0) {
|
|
406
|
-
try {
|
|
407
|
-
const earningsResult = this.getLifetimeEarnings(userTVL, investmentFlows);
|
|
408
|
-
lifetimeAmount = earningsResult.lifetimeEarnings;
|
|
409
|
-
lifetimeTokenInfo = earningsResult.tokenInfo.tokenInfo;
|
|
410
|
-
const userAmount = userTVL.amount.toNumber();
|
|
411
|
-
if (Number.isFinite(userAmount) && userAmount > 0) {
|
|
412
|
-
const pricePerToken = userTVL.usdValue / userAmount;
|
|
413
|
-
lifetimeUsdValue = lifetimeAmount.toNumber() * pricePerToken;
|
|
414
|
-
}
|
|
415
|
-
} catch (error) {
|
|
416
|
-
logger.warn(`${this.getTag()}::getUserPositionCards lifetime earnings fallback`, error);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
cards.push({
|
|
421
|
-
title: "Lifetime Earnings",
|
|
422
|
-
tooltip: "Lifetime Earnings",
|
|
423
|
-
value: this.formatTokenAmountForCard(lifetimeAmount, lifetimeTokenInfo),
|
|
424
|
-
subValue: `≈ ${this.formatUSDForCard(lifetimeUsdValue)}`,
|
|
425
|
-
subValueColor: this.getSubValueColorFromSignedNumber(lifetimeUsdValue),
|
|
426
|
-
});
|
|
427
|
-
|
|
428
|
-
return cards;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
270
|
/**
|
|
432
271
|
* Calculates the total TVL of the strategy.
|
|
433
272
|
* @returns Object containing the total amount in token units and USD value
|
|
@@ -493,7 +332,7 @@ export class UniversalStrategy<
|
|
|
493
332
|
return prevAum;
|
|
494
333
|
}
|
|
495
334
|
|
|
496
|
-
async getAUM(unrealizedAUM?: boolean): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
|
|
335
|
+
async getAUM(unrealizedAUM?: boolean): Promise<{ net: SingleTokenInfo, prevAum: Web3Number, splits: { id: string, aum: Web3Number }[] }> {
|
|
497
336
|
const prevAum = await this.getPrevAUM();
|
|
498
337
|
const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
499
338
|
|
|
@@ -519,11 +358,13 @@ export class UniversalStrategy<
|
|
|
519
358
|
};
|
|
520
359
|
const aumToken = vesuAum.plus(balance.amount);
|
|
521
360
|
if (aumToken.isZero()) {
|
|
522
|
-
return {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
361
|
+
return {
|
|
362
|
+
net, splits: [{
|
|
363
|
+
aum: zeroAmt, id: AUMTypes.FINALISED
|
|
364
|
+
}, {
|
|
365
|
+
aum: zeroAmt, id: AUMTypes.DEFISPRING
|
|
366
|
+
}], prevAum
|
|
367
|
+
};
|
|
527
368
|
}
|
|
528
369
|
logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
|
|
529
370
|
|
|
@@ -638,39 +479,39 @@ export class UniversalStrategy<
|
|
|
638
479
|
depositAmount: Web3Number,
|
|
639
480
|
debtAmount: Web3Number
|
|
640
481
|
}): UniversalManageCall[] {
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
482
|
+
assert(params.depositAmount.gt(0) || params.debtAmount.gt(0), 'Either deposit or debt amount must be greater than 0');
|
|
483
|
+
// approve token
|
|
484
|
+
const isToken1 = params.isLeg1 == params.isDeposit; // XOR
|
|
485
|
+
const STEP1_ID = isToken1 ? UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1 : UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2;
|
|
486
|
+
const manage4Info = this.getProofs<ApproveCallParams>(STEP1_ID);
|
|
487
|
+
const approveAmount = params.isDeposit ? params.depositAmount : params.debtAmount;
|
|
488
|
+
const manageCall4 = manage4Info.callConstructor({
|
|
489
|
+
amount: approveAmount
|
|
490
|
+
})
|
|
650
491
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
492
|
+
// deposit and borrow or repay and withdraw
|
|
493
|
+
const STEP2_ID = params.isLeg1 ? UNIVERSAL_MANAGE_IDS.VESU_LEG1 : UNIVERSAL_MANAGE_IDS.VESU_LEG2;
|
|
494
|
+
const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP2_ID);
|
|
495
|
+
const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
|
|
496
|
+
collateralAmount: params.depositAmount,
|
|
497
|
+
isAddCollateral: params.isDeposit,
|
|
498
|
+
debtAmount: params.debtAmount,
|
|
499
|
+
isBorrow: params.isDeposit
|
|
500
|
+
}))
|
|
501
|
+
|
|
502
|
+
const output: UniversalManageCall[] = [{
|
|
503
|
+
proofs: manage5Info.proofs,
|
|
504
|
+
manageCall: manageCall5 as unknown as ManageCall,
|
|
505
|
+
step: STEP2_ID
|
|
506
|
+
}];
|
|
507
|
+
if (approveAmount.gt(0)) {
|
|
508
|
+
output.unshift({
|
|
509
|
+
proofs: manage4Info.proofs,
|
|
510
|
+
manageCall: manageCall4 as unknown as ManageCall,
|
|
511
|
+
step: STEP1_ID
|
|
512
|
+
})
|
|
513
|
+
}
|
|
514
|
+
return output;
|
|
674
515
|
}
|
|
675
516
|
|
|
676
517
|
getTag() {
|
|
@@ -764,7 +605,7 @@ export class UniversalStrategy<
|
|
|
764
605
|
} = await vesuAdapter.getAssetPrices();
|
|
765
606
|
|
|
766
607
|
// debt is zero, nothing to rebalance
|
|
767
|
-
if(debtTokenAmount.isZero()) {
|
|
608
|
+
if (debtTokenAmount.isZero()) {
|
|
768
609
|
return Web3Number.fromWei(0, 0);
|
|
769
610
|
}
|
|
770
611
|
|
|
@@ -782,7 +623,7 @@ export class UniversalStrategy<
|
|
|
782
623
|
return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
|
|
783
624
|
} else {
|
|
784
625
|
// TargetHF = collUSD * ltv / (debtAmount - newAmount) * debtPrice
|
|
785
|
-
const newAmount =
|
|
626
|
+
const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
|
|
786
627
|
logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: repayDebt, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
|
|
787
628
|
return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
|
|
788
629
|
}
|
|
@@ -805,7 +646,7 @@ export class UniversalStrategy<
|
|
|
805
646
|
|
|
806
647
|
const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
|
|
807
648
|
|
|
808
|
-
const k1 = token1Price.price * leg1LTV
|
|
649
|
+
const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
|
|
809
650
|
const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
|
|
810
651
|
|
|
811
652
|
const borrow2Amount = new Web3Number(
|
|
@@ -841,19 +682,19 @@ export class UniversalStrategy<
|
|
|
841
682
|
}
|
|
842
683
|
const allActions = [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)];
|
|
843
684
|
const flashloanCalldata = CallData.compile([
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
685
|
+
[...callSet1.map(i => i.proofs), ...callSet2.map(i => i.proofs)],
|
|
686
|
+
allActions.map(i => i.sanitizer.address),
|
|
687
|
+
allActions.map(i => i.call.contractAddress.address),
|
|
688
|
+
allActions.map(i => i.call.selector),
|
|
689
|
+
allActions.map(i => i.call.calldata)
|
|
849
690
|
])
|
|
850
691
|
|
|
851
692
|
// flash loan
|
|
852
693
|
const STEP1_ID = UNIVERSAL_MANAGE_IDS.FLASH_LOAN;
|
|
853
694
|
const manage1Info = this.getProofs<FlashloanCallParams>(STEP1_ID);
|
|
854
695
|
const manageCall1 = manage1Info.callConstructor({
|
|
855
|
-
|
|
856
|
-
|
|
696
|
+
amount: borrow2Amount,
|
|
697
|
+
data: flashloanCalldata.map(i => BigInt(i))
|
|
857
698
|
})
|
|
858
699
|
const manageCall = this.getManageCallFromManageCalls([
|
|
859
700
|
manageCall1 as unknown as ManageCall,
|
|
@@ -884,8 +725,8 @@ export class UniversalStrategy<
|
|
|
884
725
|
|
|
885
726
|
const manage1Info = this.getProofs<VesuDefiSpringRewardsCallParams>(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS);
|
|
886
727
|
const manageCall1 = manage1Info.callConstructor({
|
|
887
|
-
|
|
888
|
-
|
|
728
|
+
amount,
|
|
729
|
+
proofs
|
|
889
730
|
});
|
|
890
731
|
const manageCalls: ManageCall[] = [manageCall1 as unknown as ManageCall];
|
|
891
732
|
|
|
@@ -895,21 +736,21 @@ export class UniversalStrategy<
|
|
|
895
736
|
// approve
|
|
896
737
|
const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1);
|
|
897
738
|
const manageCall2 = manage2Info.callConstructor({
|
|
898
|
-
|
|
739
|
+
amount: actualReward
|
|
899
740
|
});
|
|
900
741
|
|
|
901
742
|
// swap
|
|
902
743
|
const avnuModule = new AvnuWrapper();
|
|
903
744
|
const quote = await avnuModule.getQuotes(
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
745
|
+
STRK.address.address,
|
|
746
|
+
this.asset().address.address,
|
|
747
|
+
actualReward.toWei(),
|
|
748
|
+
this.address.address
|
|
908
749
|
);
|
|
909
750
|
const swapInfo = await avnuModule.getSwapInfo(quote, this.address.address, 0, this.address.address);
|
|
910
751
|
const manage3Info = this.getProofs<AvnuSwapCallParams>(UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS);
|
|
911
752
|
const manageCall3 = manage3Info.callConstructor({
|
|
912
|
-
|
|
753
|
+
props: swapInfo
|
|
913
754
|
});
|
|
914
755
|
manageCalls.push(manageCall2 as unknown as ManageCall);
|
|
915
756
|
manageCalls.push(manageCall3 as unknown as ManageCall);
|
|
@@ -1016,7 +857,7 @@ function getLooperSettings(
|
|
|
1016
857
|
quoteAmountToFetchPrice: new Web3Number(0.1, 18),
|
|
1017
858
|
minimumVesuMovementAmount: 5,
|
|
1018
859
|
...baseAdapterConfig,
|
|
1019
|
-
supportedPositions: [{asset: ETHToken, isDebt: false}, {asset: USDCToken, isDebt: true}],
|
|
860
|
+
supportedPositions: [{ asset: ETHToken, isDebt: false }, { asset: USDCToken, isDebt: true }],
|
|
1020
861
|
})
|
|
1021
862
|
const vesuModifyPositionAdapter = new VesuModifyPositionAdapter({
|
|
1022
863
|
poolId: pool1,
|
|
@@ -1025,7 +866,7 @@ function getLooperSettings(
|
|
|
1025
866
|
targetLtv: 0.75,
|
|
1026
867
|
maxLtv: 0.9,
|
|
1027
868
|
...baseAdapterConfig,
|
|
1028
|
-
supportedPositions: [{asset: ETHToken, isDebt: false}, {asset: USDCToken, isDebt: true}],
|
|
869
|
+
supportedPositions: [{ asset: ETHToken, isDebt: false }, { asset: USDCToken, isDebt: true }],
|
|
1029
870
|
})
|
|
1030
871
|
|
|
1031
872
|
const avnuAdapter = new AvnuAdapter({
|
|
@@ -1035,7 +876,7 @@ function getLooperSettings(
|
|
|
1035
876
|
minimumExtendedPriceDifferenceForSwapOpen: 0,
|
|
1036
877
|
maximumExtendedPriceDifferenceForSwapClosing: 0,
|
|
1037
878
|
...baseAdapterConfig,
|
|
1038
|
-
supportedPositions: [{asset: ETHToken, isDebt: false}, {asset: USDCToken, isDebt: false}],
|
|
879
|
+
supportedPositions: [{ asset: ETHToken, isDebt: false }, { asset: USDCToken, isDebt: false }],
|
|
1039
880
|
})
|
|
1040
881
|
// vaultSettings.adapters.push(...[{
|
|
1041
882
|
// id: UNIVERSAL_ADAPTERS.COMMON,
|
|
@@ -1295,7 +1136,7 @@ function getFAQs(): FAQ[] {
|
|
|
1295
1136
|
];
|
|
1296
1137
|
}
|
|
1297
1138
|
|
|
1298
|
-
export function getContractDetails(settings: UniversalStrategySettings & { aumOracle?: ContractAddr }): {address: ContractAddr, name: string}[] {
|
|
1139
|
+
export function getContractDetails(settings: UniversalStrategySettings & { aumOracle?: ContractAddr }): { address: ContractAddr, name: string }[] {
|
|
1299
1140
|
const contracts = [
|
|
1300
1141
|
{ address: settings.vaultAddress, name: "Vault" },
|
|
1301
1142
|
{ address: settings.manager, name: "Vault Manager" },
|
|
@@ -1319,38 +1160,38 @@ const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
|
|
|
1319
1160
|
|
|
1320
1161
|
// Helper to create common risk object
|
|
1321
1162
|
const getUniversalRisk = () => ({
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1163
|
+
riskFactor: _riskFactor,
|
|
1164
|
+
netRisk:
|
|
1165
|
+
_riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1166
|
+
_riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1167
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
1327
1168
|
});
|
|
1328
1169
|
|
|
1329
1170
|
// Helper to create Universal strategy settings
|
|
1330
1171
|
const createUniversalSettings = (
|
|
1331
|
-
|
|
1332
|
-
|
|
1172
|
+
tokenSymbol: string,
|
|
1173
|
+
maxTVLDecimals: number
|
|
1333
1174
|
): StrategySettings => {
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1175
|
+
const isUSDT = tokenSymbol === "USDT";
|
|
1176
|
+
return {
|
|
1177
|
+
maxTVL: Web3Number.fromWei(0, maxTVLDecimals),
|
|
1178
|
+
isAudited: true,
|
|
1179
|
+
liveStatus: isUSDT ? StrategyLiveStatus.RETIRED : StrategyLiveStatus.ACTIVE,
|
|
1180
|
+
isPaused: isUSDT,
|
|
1181
|
+
isInstantWithdrawal: false,
|
|
1182
|
+
hideHarvestInfo: true,
|
|
1183
|
+
quoteToken: Global.getDefaultTokens().find(
|
|
1184
|
+
(token) => token.symbol === tokenSymbol
|
|
1185
|
+
)!,
|
|
1186
|
+
alerts: [
|
|
1187
|
+
{
|
|
1188
|
+
tab: "withdraw" as const,
|
|
1189
|
+
text: "On withdrawal, you will receive an NFT representing your withdrawal request. The funds will be automatically sent to your wallet (NFT owner) in 1-2 hours. You can monitor the status in transactions tab.",
|
|
1190
|
+
type: "info" as const
|
|
1191
|
+
}
|
|
1192
|
+
],
|
|
1193
|
+
showWithdrawalWarningModal: true
|
|
1194
|
+
};
|
|
1354
1195
|
};
|
|
1355
1196
|
|
|
1356
1197
|
const EVERGREEN_SECURITY = {
|
|
@@ -1369,8 +1210,8 @@ const EVERGREEN_SECURITY = {
|
|
|
1369
1210
|
const EVERGREEN_REDEMPTION_INFO: RedemptionInfo = {
|
|
1370
1211
|
instantWithdrawalVault: InstantWithdrawalVault.NO,
|
|
1371
1212
|
redemptionsInfo: [{
|
|
1372
|
-
|
|
1373
|
-
|
|
1213
|
+
title: "Typical Duration",
|
|
1214
|
+
description: "1-2 hours"
|
|
1374
1215
|
}],
|
|
1375
1216
|
alerts: [{
|
|
1376
1217
|
type: 'info',
|
|
@@ -1381,107 +1222,110 @@ const EVERGREEN_REDEMPTION_INFO: RedemptionInfo = {
|
|
|
1381
1222
|
|
|
1382
1223
|
// Helper to create a Universal strategy
|
|
1383
1224
|
const createUniversalStrategy = (params: {
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1225
|
+
tokenSymbol: string;
|
|
1226
|
+
address: string;
|
|
1227
|
+
vaultSettings: UniversalStrategySettings;
|
|
1228
|
+
token1Symbol: string;
|
|
1229
|
+
token2Symbol: string;
|
|
1230
|
+
maxTVLDecimals: number;
|
|
1231
|
+
allowedSources: AllowedSources[];
|
|
1232
|
+
tags: StrategyTag[];
|
|
1392
1233
|
}): IStrategyMetadata<UniversalStrategySettings> => {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
}
|
|
1234
|
+
const isUSDT = params.tokenSymbol === "USDT";
|
|
1235
|
+
return {
|
|
1236
|
+
id: `evergreen_${params.tokenSymbol.toLowerCase()}`,
|
|
1237
|
+
name: `${params.tokenSymbol} Evergreen`,
|
|
1238
|
+
description: getDescription(params.tokenSymbol, params.allowedSources),
|
|
1239
|
+
address: ContractAddr.from(params.address),
|
|
1240
|
+
launchBlock: 0,
|
|
1241
|
+
type: "ERC4626" as const,
|
|
1242
|
+
vaultType: {
|
|
1243
|
+
type: VaultType.META_VAULT,
|
|
1244
|
+
description: "Automatically allocates funds to the best available yield source in the ecosystem"
|
|
1245
|
+
},
|
|
1246
|
+
depositTokens: [
|
|
1247
|
+
Global.getDefaultTokens().find((token) => token.symbol === params.tokenSymbol)!
|
|
1248
|
+
],
|
|
1249
|
+
additionalInfo: getLooperSettings(
|
|
1250
|
+
params.token1Symbol,
|
|
1251
|
+
params.token2Symbol,
|
|
1252
|
+
params.vaultSettings,
|
|
1253
|
+
VesuPools.Genesis,
|
|
1254
|
+
VesuPools.Genesis
|
|
1255
|
+
),
|
|
1256
|
+
risk: getUniversalRisk(),
|
|
1257
|
+
auditUrl: AUDIT_URL,
|
|
1258
|
+
protocols: [Protocols.VESU],
|
|
1259
|
+
realizedApyMethodology: "The realizedAPY is based on past 14 days performance by the vault",
|
|
1260
|
+
feeBps: {
|
|
1261
|
+
performanceFeeBps: 1000,
|
|
1262
|
+
},
|
|
1263
|
+
curator: UnwrapLabsCurator,
|
|
1264
|
+
settings: createUniversalSettings(params.tokenSymbol, params.maxTVLDecimals),
|
|
1265
|
+
contractDetails: getContractDetails(params.vaultSettings),
|
|
1266
|
+
faqs: getFAQs(),
|
|
1267
|
+
investmentSteps: investmentSteps,
|
|
1268
|
+
tags: params.tags,
|
|
1269
|
+
security: EVERGREEN_SECURITY,
|
|
1270
|
+
redemptionInfo: EVERGREEN_REDEMPTION_INFO,
|
|
1271
|
+
discontinuationInfo: isUSDT ? {
|
|
1272
|
+
info: "This strategy has been retired and is no longer accepting new deposits."
|
|
1273
|
+
} : undefined,
|
|
1274
|
+
usualTimeToEarnings: null,
|
|
1275
|
+
usualTimeToEarningsDescription: null,
|
|
1276
|
+
};
|
|
1433
1277
|
};
|
|
1434
1278
|
|
|
1435
1279
|
export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
|
|
1436
|
-
[
|
|
1280
|
+
[
|
|
1437
1281
|
createUniversalStrategy({
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1282
|
+
tokenSymbol: "USDC.e",
|
|
1283
|
+
address: "0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e",
|
|
1284
|
+
vaultSettings: usdcVaultSettings,
|
|
1285
|
+
token1Symbol: "USDC.e",
|
|
1286
|
+
token2Symbol: "ETH",
|
|
1287
|
+
maxTVLDecimals: 6,
|
|
1288
|
+
allowedSources: ["vesu", "extended"],
|
|
1289
|
+
tags: [StrategyTag.META_VAULT]
|
|
1446
1290
|
}),
|
|
1447
1291
|
createUniversalStrategy({
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1292
|
+
tokenSymbol: "WBTC",
|
|
1293
|
+
address: "0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c",
|
|
1294
|
+
vaultSettings: wbtcVaultSettings,
|
|
1295
|
+
token1Symbol: "WBTC",
|
|
1296
|
+
token2Symbol: "ETH",
|
|
1297
|
+
maxTVLDecimals: 8,
|
|
1298
|
+
allowedSources: ["vesu", "endur", "extended"],
|
|
1299
|
+
tags: [StrategyTag.BTC, StrategyTag.META_VAULT]
|
|
1456
1300
|
}),
|
|
1457
1301
|
createUniversalStrategy({
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1302
|
+
tokenSymbol: "ETH",
|
|
1303
|
+
address: "0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8",
|
|
1304
|
+
vaultSettings: ethVaultSettings,
|
|
1305
|
+
token1Symbol: "ETH",
|
|
1306
|
+
token2Symbol: "WBTC",
|
|
1307
|
+
maxTVLDecimals: 18,
|
|
1308
|
+
allowedSources: ["vesu", "extended"],
|
|
1309
|
+
tags: [StrategyTag.META_VAULT]
|
|
1466
1310
|
}),
|
|
1467
1311
|
createUniversalStrategy({
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1312
|
+
tokenSymbol: "STRK",
|
|
1313
|
+
address: "0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21",
|
|
1314
|
+
vaultSettings: strkVaultSettings,
|
|
1315
|
+
token1Symbol: "STRK",
|
|
1316
|
+
token2Symbol: "ETH",
|
|
1317
|
+
maxTVLDecimals: 18,
|
|
1318
|
+
allowedSources: ["vesu", "endur", "extended"],
|
|
1319
|
+
tags: [StrategyTag.META_VAULT]
|
|
1476
1320
|
}),
|
|
1477
1321
|
createUniversalStrategy({
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1322
|
+
tokenSymbol: "USDT",
|
|
1323
|
+
address: "0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3",
|
|
1324
|
+
vaultSettings: usdtVaultSettings,
|
|
1325
|
+
token1Symbol: "USDT",
|
|
1326
|
+
token2Symbol: "ETH",
|
|
1327
|
+
maxTVLDecimals: 6,
|
|
1328
|
+
allowedSources: ["vesu"],
|
|
1329
|
+
tags: [StrategyTag.META_VAULT]
|
|
1486
1330
|
})
|
|
1487
|
-
];
|
|
1331
|
+
];
|