@strkfarm/sdk 1.0.58 → 1.0.60
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 +0 -0
- package/dist/cli.mjs +0 -0
- package/dist/index.browser.global.js +6168 -5881
- package/dist/index.browser.mjs +399 -2110
- package/dist/index.d.ts +27 -2
- package/dist/index.js +413 -2118
- package/dist/index.mjs +412 -2124
- package/package.json +3 -2
- package/src/interfaces/common.tsx +18 -4
- package/src/node/deployer.ts +1 -1
- package/src/strategies/universal-adapters/adapter-utils.ts +1 -1
- package/src/strategies/universal-adapters/common-adapter.ts +31 -0
- package/src/strategies/{universal-strategy.ts → universal-strategy.tsx} +371 -28
- package/src/utils/cacheClass.ts +28 -28
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ContractAddr, Web3Number } from "@/dataTypes";
|
|
2
2
|
import { BaseStrategy, SingleActionAmount, SingleTokenInfo } from "./base-strategy";
|
|
3
3
|
import { PricerBase } from "@/modules/pricerBase";
|
|
4
|
-
import { getNoRiskTags, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, VaultPosition } from "@/interfaces";
|
|
4
|
+
import { FAQ, getNoRiskTags, IConfig, IStrategyMetadata, Protocols, RiskFactor, RiskType, VaultPosition } from "@/interfaces";
|
|
5
5
|
import { Call, CallData, Contract, num, uint256 } from "starknet";
|
|
6
6
|
import { VesuRebalanceSettings } from "./vesu-rebalance";
|
|
7
7
|
import { assert, LeafData, logger, StandardMerkleTree } from "@/utils";
|
|
@@ -12,6 +12,7 @@ import { Global } from "@/global";
|
|
|
12
12
|
import { ERC20 } from "@/modules";
|
|
13
13
|
|
|
14
14
|
export interface UniversalStrategySettings {
|
|
15
|
+
vaultAddress: ContractAddr,
|
|
15
16
|
manager: ContractAddr,
|
|
16
17
|
vaultAllocator: ContractAddr,
|
|
17
18
|
redeemRequestNFT: ContractAddr,
|
|
@@ -22,6 +23,10 @@ export interface UniversalStrategySettings {
|
|
|
22
23
|
minHealthFactor: number
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
export enum AUMTypes {
|
|
27
|
+
FINALISED = 'finalised',
|
|
28
|
+
DEFISPRING = 'defispring'
|
|
29
|
+
}
|
|
25
30
|
|
|
26
31
|
export class UniversalStrategy<
|
|
27
32
|
S extends UniversalStrategySettings
|
|
@@ -141,6 +146,20 @@ export class UniversalStrategy<
|
|
|
141
146
|
return [call1, call2];
|
|
142
147
|
}
|
|
143
148
|
|
|
149
|
+
async withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
|
|
150
|
+
assert(
|
|
151
|
+
amountInfo.tokenInfo.address.eq(this.asset().address),
|
|
152
|
+
"Withdraw token mismatch"
|
|
153
|
+
);
|
|
154
|
+
const shares = await this.contract.call('convert_to_shares', [uint256.bnToUint256(amountInfo.amount.toWei())]);
|
|
155
|
+
const call = this.contract.populate("request_redeem", [
|
|
156
|
+
uint256.bnToUint256(shares.toString()),
|
|
157
|
+
receiver.address,
|
|
158
|
+
owner.address
|
|
159
|
+
]);
|
|
160
|
+
return [call];
|
|
161
|
+
}
|
|
162
|
+
|
|
144
163
|
/**
|
|
145
164
|
* Calculates the Total Value Locked (TVL) for a specific user.
|
|
146
165
|
* @param user - Address of the user
|
|
@@ -192,14 +211,22 @@ export class UniversalStrategy<
|
|
|
192
211
|
const debt2APY = Number(debtAsset2.borrowApr.value) / 1e18;
|
|
193
212
|
|
|
194
213
|
const positions = await this.getVaultPositions();
|
|
214
|
+
logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
|
|
215
|
+
if (positions.every(p => p.amount.isZero())) {
|
|
216
|
+
return { net: 0, splits: [{
|
|
217
|
+
apy: 0, id: 'base'
|
|
218
|
+
}, {
|
|
219
|
+
apy: 0, id: 'defispring'
|
|
220
|
+
}]};
|
|
221
|
+
}
|
|
195
222
|
const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
|
|
196
223
|
const baseAPYs = [collateral1APY, debt1APY, collateral2APY, debt2APY];
|
|
197
224
|
assert(positions.length == baseAPYs.length, "Positions and APYs length mismatch");
|
|
198
225
|
const rewardAPYs = [Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18, 0, Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18, 0];
|
|
199
226
|
const baseAPY = this.computeAPY(baseAPYs, weights);
|
|
200
227
|
const rewardAPY = this.computeAPY(rewardAPYs, weights);
|
|
201
|
-
const apys = [...baseAPYs, ...rewardAPYs];
|
|
202
228
|
const netAPY = baseAPY + rewardAPY;
|
|
229
|
+
logger.verbose(`${this.metadata.name}::netAPY: net: ${netAPY}, baseAPY: ${baseAPY}, rewardAPY: ${rewardAPY}`);
|
|
203
230
|
return { net: netAPY, splits: [{
|
|
204
231
|
apy: baseAPY, id: 'base'
|
|
205
232
|
}, {
|
|
@@ -235,6 +262,17 @@ export class UniversalStrategy<
|
|
|
235
262
|
};
|
|
236
263
|
}
|
|
237
264
|
|
|
265
|
+
async getUnusedBalance(): Promise<SingleTokenInfo> {
|
|
266
|
+
const balance = await (new ERC20(this.config)).balanceOf(this.asset().address, this.metadata.additionalInfo.vaultAllocator, this.asset().decimals);
|
|
267
|
+
const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
|
|
268
|
+
const usdValue = Number(balance.toFixed(6)) * price.price;
|
|
269
|
+
return {
|
|
270
|
+
tokenInfo: this.asset(),
|
|
271
|
+
amount: balance,
|
|
272
|
+
usdValue
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
238
276
|
async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
|
|
239
277
|
const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
|
|
240
278
|
const lastReportTime = await this.contract.call('last_report_timestamp', []);
|
|
@@ -246,13 +284,30 @@ export class UniversalStrategy<
|
|
|
246
284
|
const leg1AUM = await vesuAdapter1.getPositions(this.config);
|
|
247
285
|
const leg2AUM = await vesuAdapter2.getPositions(this.config);
|
|
248
286
|
|
|
249
|
-
const balance = await
|
|
250
|
-
logger.verbose(`${this.getTag()} unused balance: ${balance}`);
|
|
287
|
+
const balance = await this.getUnusedBalance();
|
|
288
|
+
logger.verbose(`${this.getTag()} unused balance: ${balance.amount.toNumber()}`);
|
|
251
289
|
|
|
252
|
-
const
|
|
290
|
+
const vesuAum = leg1AUM[0].amount
|
|
253
291
|
.plus(leg2AUM[0].usdValue / token1Price.price)
|
|
254
292
|
.minus(leg1AUM[1].usdValue / token1Price.price)
|
|
255
|
-
.minus(leg2AUM[1].amount)
|
|
293
|
+
.minus(leg2AUM[1].amount);
|
|
294
|
+
logger.verbose(`${this.getTag()} Vesu AUM: leg1: ${leg1AUM[0].amount.toNumber()}, ${leg1AUM[1].amount.toNumber()}, leg2: ${leg2AUM[0].amount.toNumber()}, ${leg2AUM[1].amount.toNumber()}`);
|
|
295
|
+
|
|
296
|
+
const zeroAmt = Web3Number.fromWei('0', this.asset().decimals);
|
|
297
|
+
const net = {
|
|
298
|
+
tokenInfo: this.asset(),
|
|
299
|
+
amount: zeroAmt,
|
|
300
|
+
usdValue: 0
|
|
301
|
+
};
|
|
302
|
+
const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
|
|
303
|
+
if (vesuAum.isZero()) {
|
|
304
|
+
return { net, splits: [{
|
|
305
|
+
aum: zeroAmt, id: AUMTypes.FINALISED
|
|
306
|
+
}, {
|
|
307
|
+
aum: zeroAmt, id: AUMTypes.DEFISPRING
|
|
308
|
+
}], prevAum};
|
|
309
|
+
}
|
|
310
|
+
const aumToken = vesuAum.plus(balance.amount);
|
|
256
311
|
logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
|
|
257
312
|
|
|
258
313
|
// calculate estimated growth from strk rewards
|
|
@@ -262,7 +317,6 @@ export class UniversalStrategy<
|
|
|
262
317
|
|
|
263
318
|
const timeDiff = (Math.round(Date.now() / 1000) - Number(lastReportTime));
|
|
264
319
|
const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
|
|
265
|
-
const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
|
|
266
320
|
const rewardAssets = prevAum.multipliedBy(growthRate);
|
|
267
321
|
logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
|
|
268
322
|
logger.verbose(`${this.getTag()} Current AUM: ${currentAUM}`);
|
|
@@ -272,16 +326,13 @@ export class UniversalStrategy<
|
|
|
272
326
|
const newAUM = aumToken.plus(rewardAssets);
|
|
273
327
|
logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
|
|
274
328
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
amount: newAUM,
|
|
278
|
-
usdValue: newAUM.multipliedBy(token1Price.price).toNumber()
|
|
279
|
-
};
|
|
329
|
+
net.amount = newAUM;
|
|
330
|
+
net.usdValue = newAUM.multipliedBy(token1Price.price).toNumber();
|
|
280
331
|
const splits = [{
|
|
281
|
-
id:
|
|
332
|
+
id: AUMTypes.FINALISED,
|
|
282
333
|
aum: aumToken
|
|
283
334
|
}, {
|
|
284
|
-
id:
|
|
335
|
+
id: AUMTypes.DEFISPRING,
|
|
285
336
|
aum: rewardAssets
|
|
286
337
|
}];
|
|
287
338
|
return { net, splits, prevAum };
|
|
@@ -500,20 +551,25 @@ export class UniversalStrategy<
|
|
|
500
551
|
logger.verbose(`${this.getTag()}:: borrow1Amount: ${borrow1Amount.toString()} ${vesuAdapter1.config.debt.symbol}`);
|
|
501
552
|
logger.verbose(`${this.getTag()}:: borrow2Amount: ${borrow2Amount.toString()} ${vesuAdapter2.config.debt.symbol}`);
|
|
502
553
|
|
|
503
|
-
|
|
554
|
+
let callSet1 = this.getVesuModifyPositionCalls({
|
|
504
555
|
isLeg1: true,
|
|
505
556
|
isDeposit: params.isDeposit,
|
|
506
557
|
depositAmount: params.leg1DepositAmount.plus(borrow2Amount),
|
|
507
558
|
debtAmount: borrow1Amount
|
|
508
559
|
});
|
|
509
560
|
|
|
510
|
-
|
|
561
|
+
let callSet2 = this.getVesuModifyPositionCalls({
|
|
511
562
|
isLeg1: false,
|
|
512
563
|
isDeposit: params.isDeposit,
|
|
513
564
|
depositAmount: borrow1Amount,
|
|
514
565
|
debtAmount: borrow2Amount
|
|
515
566
|
});
|
|
516
567
|
|
|
568
|
+
if (!params.isDeposit) {
|
|
569
|
+
let temp = callSet2;
|
|
570
|
+
callSet2 = [...callSet1];
|
|
571
|
+
callSet1 = [...temp];
|
|
572
|
+
}
|
|
517
573
|
const allActions = [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)];
|
|
518
574
|
const flashloanCalldata = CallData.compile([
|
|
519
575
|
[...callSet1.map(i => i.proofs), ...callSet2.map(i => i.proofs)],
|
|
@@ -534,6 +590,21 @@ export class UniversalStrategy<
|
|
|
534
590
|
return manageCall;
|
|
535
591
|
}
|
|
536
592
|
|
|
593
|
+
async getBringLiquidityCall(params: {
|
|
594
|
+
amount: Web3Number
|
|
595
|
+
}) {
|
|
596
|
+
const manage1Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY);
|
|
597
|
+
const manageCall1 = manage1Info.callConstructor({
|
|
598
|
+
amount: params.amount
|
|
599
|
+
});
|
|
600
|
+
const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY);
|
|
601
|
+
const manageCall2 = manage2Info.callConstructor({
|
|
602
|
+
amount: params.amount
|
|
603
|
+
});
|
|
604
|
+
const manageCall = this.getManageCall([UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY, UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY], [manageCall1, manageCall2]);
|
|
605
|
+
return manageCall;
|
|
606
|
+
}
|
|
607
|
+
|
|
537
608
|
async getRebalanceCall(params: {
|
|
538
609
|
isLeg1toLeg2: boolean,
|
|
539
610
|
amount: Web3Number
|
|
@@ -567,12 +638,15 @@ export class UniversalStrategy<
|
|
|
567
638
|
}
|
|
568
639
|
|
|
569
640
|
|
|
641
|
+
// useful to map readble names to proofs and calls
|
|
570
642
|
export enum UNIVERSAL_MANAGE_IDS {
|
|
571
643
|
FLASH_LOAN = 'flash_loan_init',
|
|
572
644
|
VESU_LEG1 = 'vesu_leg1',
|
|
573
645
|
VESU_LEG2 = 'vesu_leg2',
|
|
574
646
|
APPROVE_TOKEN1 = 'approve_token1',
|
|
575
|
-
APPROVE_TOKEN2 = 'approve_token2'
|
|
647
|
+
APPROVE_TOKEN2 = 'approve_token2',
|
|
648
|
+
APPROVE_BRING_LIQUIDITY = 'approve_bring_liquidity',
|
|
649
|
+
BRING_LIQUIDITY = 'bring_liquidity'
|
|
576
650
|
}
|
|
577
651
|
|
|
578
652
|
export enum UNIVERSAL_ADAPTERS {
|
|
@@ -586,7 +660,7 @@ function getLooperSettings(
|
|
|
586
660
|
token2Symbol: string,
|
|
587
661
|
vaultSettings: UniversalStrategySettings,
|
|
588
662
|
pool1: ContractAddr,
|
|
589
|
-
pool2: ContractAddr
|
|
663
|
+
pool2: ContractAddr,
|
|
590
664
|
) {
|
|
591
665
|
const USDCToken = Global.getDefaultTokens().find(token => token.symbol === token1Symbol)!;
|
|
592
666
|
const ETHToken = Global.getDefaultTokens().find(token => token.symbol === token2Symbol)!;
|
|
@@ -594,7 +668,9 @@ function getLooperSettings(
|
|
|
594
668
|
const commonAdapter = new CommonAdapter({
|
|
595
669
|
manager: vaultSettings.manager,
|
|
596
670
|
asset: USDCToken.address,
|
|
597
|
-
id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN
|
|
671
|
+
id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
|
|
672
|
+
vaultAddress: vaultSettings.vaultAddress,
|
|
673
|
+
vaultAllocator: vaultSettings.vaultAllocator,
|
|
598
674
|
})
|
|
599
675
|
const vesuAdapterUSDCETH = new VesuAdapter({
|
|
600
676
|
poolId: pool1,
|
|
@@ -620,20 +696,28 @@ function getLooperSettings(
|
|
|
620
696
|
id: UNIVERSAL_ADAPTERS.VESU_LEG2,
|
|
621
697
|
adapter: vesuAdapterETHUSDC
|
|
622
698
|
}])
|
|
699
|
+
|
|
700
|
+
// vesu looping
|
|
623
701
|
vaultSettings.leafAdapters.push(commonAdapter.getFlashloanAdapter.bind(commonAdapter));
|
|
624
702
|
vaultSettings.leafAdapters.push(vesuAdapterUSDCETH.getModifyPosition.bind(vesuAdapterUSDCETH));
|
|
625
703
|
vaultSettings.leafAdapters.push(vesuAdapterETHUSDC.getModifyPosition.bind(vesuAdapterETHUSDC));
|
|
626
704
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, vesuAdapterUSDCETH.VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1).bind(commonAdapter));
|
|
627
705
|
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(ETHToken.address, vesuAdapterETHUSDC.VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2).bind(commonAdapter));
|
|
706
|
+
|
|
707
|
+
// to bridge liquidity back to vault (used by bring_liquidity)
|
|
708
|
+
vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
|
|
709
|
+
vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
|
|
628
710
|
return vaultSettings;
|
|
629
711
|
}
|
|
630
712
|
|
|
631
713
|
const _riskFactor: RiskFactor[] = [
|
|
632
714
|
{ type: RiskType.SMART_CONTRACT_RISK, value: 0.5, weight: 25, reason: "Audited by Zellic" },
|
|
633
|
-
{ type: RiskType.LIQUIDATION_RISK, value: 1, weight: 50, reason: "Liquidation risk is mitigated
|
|
715
|
+
{ type: RiskType.LIQUIDATION_RISK, value: 1.5, weight: 50, reason: "Liquidation risk is mitigated by stable price feed on Starknet" },
|
|
716
|
+
{ type: RiskType.TECHNICAL_RISK, value: 1, weight: 50, reason: "Technical failures like risk monitoring failures" }
|
|
634
717
|
];
|
|
635
718
|
|
|
636
719
|
const usdcVaultSettings: UniversalStrategySettings = {
|
|
720
|
+
vaultAddress: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
|
|
637
721
|
manager: ContractAddr.from('0xf41a2b1f498a7f9629db0b8519259e66e964260a23d20003f3e42bb1997a07'),
|
|
638
722
|
vaultAllocator: ContractAddr.from('0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba'),
|
|
639
723
|
redeemRequestNFT: ContractAddr.from('0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda'),
|
|
@@ -645,6 +729,7 @@ const usdcVaultSettings: UniversalStrategySettings = {
|
|
|
645
729
|
}
|
|
646
730
|
|
|
647
731
|
const wbtcVaultSettings: UniversalStrategySettings = {
|
|
732
|
+
vaultAddress: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
|
|
648
733
|
manager: ContractAddr.from('0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34'),
|
|
649
734
|
vaultAllocator: ContractAddr.from('0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735'),
|
|
650
735
|
redeemRequestNFT: ContractAddr.from('0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2'),
|
|
@@ -655,11 +740,206 @@ const wbtcVaultSettings: UniversalStrategySettings = {
|
|
|
655
740
|
minHealthFactor: 1.25
|
|
656
741
|
}
|
|
657
742
|
|
|
743
|
+
const ethVaultSettings: UniversalStrategySettings = {
|
|
744
|
+
vaultAddress: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
|
|
745
|
+
manager: ContractAddr.from('0x494888b37206616bd09d759dcda61e5118470b9aa7f58fb84f21c778a7b8f97'),
|
|
746
|
+
vaultAllocator: ContractAddr.from('0x4acc0ad6bea58cb578d60ff7c31f06f44369a7a9a7bbfffe4701f143e427bd'),
|
|
747
|
+
redeemRequestNFT: ContractAddr.from('0x2e6cd71e5060a254d4db00655e420db7bf89da7755bb0d5f922e2f00c76ac49'),
|
|
748
|
+
aumOracle: ContractAddr.from("0x4b747f2e75c057bed9aa2ce46fbdc2159dc684c15bd32d4f95983a6ecf39a05"),
|
|
749
|
+
leafAdapters: [],
|
|
750
|
+
adapters: [],
|
|
751
|
+
targetHealthFactor: 1.3,
|
|
752
|
+
minHealthFactor: 1.25
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
const strkVaultSettings: UniversalStrategySettings = {
|
|
756
|
+
vaultAddress: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
|
|
757
|
+
manager: ContractAddr.from('0xcc6a5153ca56293405506eb20826a379d982cd738008ef7e808454d318fb81'),
|
|
758
|
+
vaultAllocator: ContractAddr.from('0xf29d2f82e896c0ed74c9eff220af34ac148e8b99846d1ace9fbb02c9191d01'),
|
|
759
|
+
redeemRequestNFT: ContractAddr.from('0x46902423bd632c428376b84fcee9cac5dbe016214e93a8103bcbde6e1de656b'),
|
|
760
|
+
aumOracle: ContractAddr.from("0x6d7dbfad4bb51715da211468389a623da00c0625f8f6efbea822ee5ac5231f4"),
|
|
761
|
+
leafAdapters: [],
|
|
762
|
+
adapters: [],
|
|
763
|
+
targetHealthFactor: 1.3,
|
|
764
|
+
minHealthFactor: 1.25
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
const usdtVaultSettings: UniversalStrategySettings = {
|
|
768
|
+
vaultAddress: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
|
|
769
|
+
manager: ContractAddr.from('0x39bb9843503799b552b7ed84b31c06e4ff10c0537edcddfbf01fe944b864029'),
|
|
770
|
+
vaultAllocator: ContractAddr.from('0x56437d18c43727ac971f6c7086031cad7d9d6ccb340f4f3785a74cc791c931a'),
|
|
771
|
+
redeemRequestNFT: ContractAddr.from('0x5af0c2a657eaa8e23ed78e855dac0c51e4f69e2cf91a18c472041a1f75bb41f'),
|
|
772
|
+
aumOracle: ContractAddr.from("0x7018f8040c8066a4ab929e6760ae52dd43b6a3a289172f514750a61fcc565cc"),
|
|
773
|
+
leafAdapters: [],
|
|
774
|
+
adapters: [],
|
|
775
|
+
targetHealthFactor: 1.3,
|
|
776
|
+
minHealthFactor: 1.25
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
export default function MetaVaultDescription() {
|
|
780
|
+
const logos: any = {
|
|
781
|
+
vesu: Protocols.VESU.logo,
|
|
782
|
+
endur: Protocols.ENDUR.logo,
|
|
783
|
+
extended: Protocols.EXTENDED.logo,
|
|
784
|
+
ekubo: "https://dummyimage.com/64x64/ffffff/000000&text=K",
|
|
785
|
+
};
|
|
786
|
+
const sources = [
|
|
787
|
+
{ key: "vesu", name: "Vesu", status: "Live", description: "Integrated liquidity venue used for automated routing to capture the best available yield." },
|
|
788
|
+
{ key: "endur", name: "Endur", status: "Coming soon", description: "Planned integration to tap into STRK staking–backed yields via our LST pipeline." },
|
|
789
|
+
{ key: "extended", name: "Extended", status: "Coming soon", description: "Expanding coverage to additional money markets and vaults across the ecosystem." },
|
|
790
|
+
// { key: "ekubo", name: "Ekubo", status: "Coming soon", description: "Concentrated liquidity strategies targeted for optimized fee APR harvesting." },
|
|
791
|
+
];
|
|
792
|
+
|
|
793
|
+
const containerStyle = {
|
|
794
|
+
maxWidth: "800px",
|
|
795
|
+
margin: "0 auto",
|
|
796
|
+
backgroundColor: "#111",
|
|
797
|
+
color: "#eee",
|
|
798
|
+
fontFamily: "Arial, sans-serif",
|
|
799
|
+
borderRadius: "12px",
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
const cardStyle = {
|
|
803
|
+
border: "1px solid #333",
|
|
804
|
+
borderRadius: "10px",
|
|
805
|
+
padding: "12px",
|
|
806
|
+
marginBottom: "12px",
|
|
807
|
+
backgroundColor: "#1a1a1a",
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
const logoStyle = {
|
|
811
|
+
width: "24px",
|
|
812
|
+
height: "24px",
|
|
813
|
+
borderRadius: "8px",
|
|
814
|
+
border: "1px solid #444",
|
|
815
|
+
backgroundColor: "#222",
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
return (
|
|
819
|
+
<div style={containerStyle}>
|
|
820
|
+
<h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Meta Vault — Automated Yield Router</h1>
|
|
821
|
+
<p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
|
|
822
|
+
This Evergreen vault is a tokenized Meta Vault, auto-compounding strategy that continuously allocates your deposited
|
|
823
|
+
asset to the best available yield source in the ecosystem. Depositors receive vault shares that
|
|
824
|
+
represent a proportional claim on the underlying assets and accrued yield. Allocation shifts are
|
|
825
|
+
handled programmatically based on on-chain signals and risk filters, minimizing idle capital and
|
|
826
|
+
maximizing net APY.
|
|
827
|
+
</p>
|
|
828
|
+
|
|
829
|
+
<div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
|
|
830
|
+
<p style={{ fontSize: "13px", color: "#ccc" }}>
|
|
831
|
+
<strong>Withdrawals:</strong> Requests can take up to <strong>1-2 hours</strong> to process as the vault unwinds and settles routing.
|
|
832
|
+
</p>
|
|
833
|
+
</div>
|
|
834
|
+
|
|
835
|
+
<h2 style={{ fontSize: "18px", marginBottom: "10px" }}>Supported Yield Sources</h2>
|
|
836
|
+
{sources.map((s) => (
|
|
837
|
+
<div key={s.key} style={cardStyle}>
|
|
838
|
+
<div style={{ display: "flex", gap: "10px", alignItems: "flex-start" }}>
|
|
839
|
+
<img src={logos[s.key]} alt={`${s.name} logo`} style={logoStyle} />
|
|
840
|
+
<div style={{ flex: 1 }}>
|
|
841
|
+
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
|
842
|
+
<h3 style={{ fontSize: "15px", margin: 0 }}>{s.name}</h3>
|
|
843
|
+
<StatusBadge status={s.status} />
|
|
844
|
+
</div>
|
|
845
|
+
{/* <p style={{ fontSize: "13px", color: "#ccc", marginTop: "4px" }}>{s.description}</p> */}
|
|
846
|
+
</div>
|
|
847
|
+
</div>
|
|
848
|
+
</div>
|
|
849
|
+
))}
|
|
850
|
+
</div>
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
function StatusBadge({ status }: { status: string }) {
|
|
855
|
+
const isSoon = String(status).toLowerCase() !== "live";
|
|
856
|
+
const badgeStyle = {
|
|
857
|
+
fontSize: "12px",
|
|
858
|
+
padding: "2px 6px",
|
|
859
|
+
borderRadius: "12px",
|
|
860
|
+
border: "1px solid",
|
|
861
|
+
color: isSoon ? "rgb(196 196 195)" : "#6aff7d",
|
|
862
|
+
borderColor: isSoon ? "#484848" : "#6aff7d",
|
|
863
|
+
backgroundColor: isSoon ? "#424242" : "#002b1a",
|
|
864
|
+
};
|
|
865
|
+
return <span style={badgeStyle}>{status}</span>;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
function getDescription(tokenSymbol: string) {
|
|
869
|
+
return MetaVaultDescription();
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
function getFAQs(): FAQ[] {
|
|
873
|
+
return [
|
|
874
|
+
{
|
|
875
|
+
question: "What is the Meta Vault?",
|
|
876
|
+
answer:
|
|
877
|
+
"The Meta Vault is a tokenized strategy that automatically allocates your deposited assets to the best available yield source in the ecosystem. It optimizes returns while minimizing idle capital.",
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
question: "How does yield allocation work?",
|
|
881
|
+
answer:
|
|
882
|
+
"The vault continuously monitors supported protocols and routes liquidity to the source offering the highest net yield after accounting for fees, slippage, and gas costs. Reallocations are performed automatically.",
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
question: "Which yield sources are supported?",
|
|
886
|
+
answer: (
|
|
887
|
+
<span>
|
|
888
|
+
Currently, <strong>Vesu</strong> is live. Future integrations include{" "}
|
|
889
|
+
<strong>Endur</strong>, <strong>Extended</strong>, and{" "}
|
|
890
|
+
<strong>Ekubo</strong> (all coming soon).
|
|
891
|
+
</span>
|
|
892
|
+
),
|
|
893
|
+
},
|
|
894
|
+
{
|
|
895
|
+
question: "What do I receive when I deposit?",
|
|
896
|
+
answer:
|
|
897
|
+
"Depositors receive vault tokens representing their proportional share of the vault. These tokens entitle holders to both the principal and accrued yield.",
|
|
898
|
+
},
|
|
899
|
+
{
|
|
900
|
+
question: "How long do withdrawals take?",
|
|
901
|
+
answer:
|
|
902
|
+
"Withdrawals may take up to 1-2 hours to process, as the vault unwinds and settles liquidity routing across integrated protocols.",
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
question: "Is the Meta Vault non-custodial?",
|
|
906
|
+
answer:
|
|
907
|
+
"Yes. The Meta Vault operates entirely on-chain. Users always maintain control of their vault tokens, and the strategy is fully transparent.",
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
question: "How is risk managed?",
|
|
911
|
+
answer:
|
|
912
|
+
"Integrations are supported with active risk monitoring like liquidation risk. Only vetted protocols are included to balance yield with safety. However, usual Defi risks like smart contract risk, extreme volatile market risk, etc. are still present.",
|
|
913
|
+
},
|
|
914
|
+
{
|
|
915
|
+
question: "Are there any fees?",
|
|
916
|
+
answer:
|
|
917
|
+
"Troves charges a performance of 10% on the yield generated. The APY shown is net of this fee. This fee is only applied to the profits earned, ensuring that users retain their initial capital.",
|
|
918
|
+
},
|
|
919
|
+
];
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function getContractDetails(settings: UniversalStrategySettings): {address: ContractAddr, name: string}[] {
|
|
923
|
+
return [
|
|
924
|
+
{ address: settings.vaultAddress, name: "Vault" },
|
|
925
|
+
{ address: settings.manager, name: "Vault Manager" },
|
|
926
|
+
{ address: settings.vaultAllocator, name: "Vault Allocator" },
|
|
927
|
+
{ address: settings.redeemRequestNFT, name: "Redeem Request NFT" },
|
|
928
|
+
{ address: settings.aumOracle, name: "AUM Oracle" },
|
|
929
|
+
];
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const investmentSteps: string[] = [
|
|
933
|
+
"Deposit funds into the vault",
|
|
934
|
+
"Vault manager allocates funds to optimal yield sources",
|
|
935
|
+
"Vault manager reports asset under management (AUM) regularly to the vault",
|
|
936
|
+
"Request withdrawal and vault manager processes it in 1-2 hours"
|
|
937
|
+
]
|
|
658
938
|
export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
|
|
659
939
|
[
|
|
660
940
|
{
|
|
661
941
|
name: "USDC Evergreen",
|
|
662
|
-
description:
|
|
942
|
+
description: getDescription('USDC'),
|
|
663
943
|
address: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
|
|
664
944
|
launchBlock: 0,
|
|
665
945
|
type: 'ERC4626',
|
|
@@ -674,13 +954,13 @@ export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[]
|
|
|
674
954
|
},
|
|
675
955
|
protocols: [Protocols.VESU],
|
|
676
956
|
maxTVL: Web3Number.fromWei(0, 6),
|
|
677
|
-
contractDetails:
|
|
678
|
-
faqs:
|
|
679
|
-
investmentSteps:
|
|
957
|
+
contractDetails: getContractDetails(usdcVaultSettings),
|
|
958
|
+
faqs: getFAQs(),
|
|
959
|
+
investmentSteps: investmentSteps,
|
|
680
960
|
},
|
|
681
961
|
{
|
|
682
962
|
name: "WBTC Evergreen",
|
|
683
|
-
description:
|
|
963
|
+
description: getDescription('WBTC'),
|
|
684
964
|
address: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
|
|
685
965
|
launchBlock: 0,
|
|
686
966
|
type: 'ERC4626',
|
|
@@ -695,8 +975,71 @@ export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[]
|
|
|
695
975
|
},
|
|
696
976
|
protocols: [Protocols.VESU],
|
|
697
977
|
maxTVL: Web3Number.fromWei(0, 8),
|
|
698
|
-
contractDetails:
|
|
699
|
-
faqs:
|
|
700
|
-
investmentSteps:
|
|
978
|
+
contractDetails: getContractDetails(wbtcVaultSettings),
|
|
979
|
+
faqs: getFAQs(),
|
|
980
|
+
investmentSteps: investmentSteps,
|
|
701
981
|
},
|
|
982
|
+
{
|
|
983
|
+
name: "ETH Evergreen",
|
|
984
|
+
description: getDescription('ETH'),
|
|
985
|
+
address: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
|
|
986
|
+
launchBlock: 0,
|
|
987
|
+
type: 'ERC4626',
|
|
988
|
+
depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'ETH')!],
|
|
989
|
+
additionalInfo: getLooperSettings('ETH', 'WBTC', ethVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
990
|
+
risk: {
|
|
991
|
+
riskFactor: _riskFactor,
|
|
992
|
+
netRisk:
|
|
993
|
+
_riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
994
|
+
_riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
995
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
996
|
+
},
|
|
997
|
+
protocols: [Protocols.VESU],
|
|
998
|
+
maxTVL: Web3Number.fromWei(0, 18),
|
|
999
|
+
contractDetails: getContractDetails(ethVaultSettings),
|
|
1000
|
+
faqs: getFAQs(),
|
|
1001
|
+
investmentSteps: investmentSteps,
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
name: "STRK Evergreen",
|
|
1005
|
+
description: getDescription('STRK'),
|
|
1006
|
+
address: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
|
|
1007
|
+
launchBlock: 0,
|
|
1008
|
+
type: 'ERC4626',
|
|
1009
|
+
depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'STRK')!],
|
|
1010
|
+
additionalInfo: getLooperSettings('STRK', 'ETH', strkVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
1011
|
+
risk: {
|
|
1012
|
+
riskFactor: _riskFactor,
|
|
1013
|
+
netRisk:
|
|
1014
|
+
_riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1015
|
+
_riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1016
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
1017
|
+
},
|
|
1018
|
+
protocols: [Protocols.VESU],
|
|
1019
|
+
maxTVL: Web3Number.fromWei(0, 18),
|
|
1020
|
+
contractDetails: getContractDetails(strkVaultSettings),
|
|
1021
|
+
faqs: getFAQs(),
|
|
1022
|
+
investmentSteps: investmentSteps,
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
name: "USDT Evergreen",
|
|
1026
|
+
description: getDescription('USDT'),
|
|
1027
|
+
address: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
|
|
1028
|
+
launchBlock: 0,
|
|
1029
|
+
type: 'ERC4626',
|
|
1030
|
+
depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDT')!],
|
|
1031
|
+
additionalInfo: getLooperSettings('USDT', 'ETH', usdtVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
|
|
1032
|
+
risk: {
|
|
1033
|
+
riskFactor: _riskFactor,
|
|
1034
|
+
netRisk:
|
|
1035
|
+
_riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
|
|
1036
|
+
_riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
|
|
1037
|
+
notARisks: getNoRiskTags(_riskFactor)
|
|
1038
|
+
},
|
|
1039
|
+
protocols: [Protocols.VESU],
|
|
1040
|
+
maxTVL: Web3Number.fromWei(0, 6),
|
|
1041
|
+
contractDetails: getContractDetails(usdtVaultSettings),
|
|
1042
|
+
faqs: getFAQs(),
|
|
1043
|
+
investmentSteps: investmentSteps,
|
|
1044
|
+
}
|
|
702
1045
|
]
|
package/src/utils/cacheClass.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
interface CacheData {
|
|
2
|
-
timestamp: number;
|
|
3
|
-
ttl: number;
|
|
4
|
-
data: any;
|
|
5
|
-
}
|
|
6
|
-
export class CacheClass {
|
|
7
|
-
readonly cache: Map<string, CacheData> = new Map();
|
|
8
|
-
|
|
9
|
-
setCache(key: string, data: any, ttl: number = 60000): void {
|
|
10
|
-
const timestamp = Date.now();
|
|
11
|
-
this.cache.set(key, { timestamp, ttl, data });
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
getCache<T>(key: string): T | null {
|
|
15
|
-
const cachedData = this.cache.get(key);
|
|
16
|
-
if (!cachedData || !this.isCacheValid(key)) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
return cachedData.data;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
isCacheValid(key: string): boolean {
|
|
23
|
-
const cachedData = this.cache.get(key);
|
|
24
|
-
if (!cachedData) return false;
|
|
25
|
-
|
|
26
|
-
const { timestamp, ttl } = cachedData;
|
|
27
|
-
return Date.now() - timestamp <= ttl;
|
|
28
|
-
}
|
|
1
|
+
interface CacheData {
|
|
2
|
+
timestamp: number;
|
|
3
|
+
ttl: number;
|
|
4
|
+
data: any;
|
|
5
|
+
}
|
|
6
|
+
export class CacheClass {
|
|
7
|
+
readonly cache: Map<string, CacheData> = new Map();
|
|
8
|
+
|
|
9
|
+
setCache(key: string, data: any, ttl: number = 60000): void {
|
|
10
|
+
const timestamp = Date.now();
|
|
11
|
+
this.cache.set(key, { timestamp, ttl, data });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getCache<T>(key: string): T | null {
|
|
15
|
+
const cachedData = this.cache.get(key);
|
|
16
|
+
if (!cachedData || !this.isCacheValid(key)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return cachedData.data;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
isCacheValid(key: string): boolean {
|
|
23
|
+
const cachedData = this.cache.get(key);
|
|
24
|
+
if (!cachedData) return false;
|
|
25
|
+
|
|
26
|
+
const { timestamp, ttl } = cachedData;
|
|
27
|
+
return Date.now() - timestamp <= ttl;
|
|
28
|
+
}
|
|
29
29
|
}
|