@strkfarm/sdk 1.2.0 → 2.0.0-dev-strategy2.1

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.
Files changed (60) hide show
  1. package/dist/index.browser.global.js +76556 -66640
  2. package/dist/index.browser.mjs +34235 -24392
  3. package/dist/index.d.ts +2372 -793
  4. package/dist/index.js +31967 -22084
  5. package/dist/index.mjs +25545 -15719
  6. package/package.json +86 -76
  7. package/readme.md +56 -1
  8. package/src/data/extended-deposit.abi.json +3613 -0
  9. package/src/data/universal-vault.abi.json +135 -20
  10. package/src/dataTypes/_bignumber.ts +11 -0
  11. package/src/dataTypes/address.ts +7 -0
  12. package/src/global.ts +240 -193
  13. package/src/interfaces/common.tsx +26 -2
  14. package/src/modules/ExtendedWrapperSDk/index.ts +62 -0
  15. package/src/modules/ExtendedWrapperSDk/types.ts +311 -0
  16. package/src/modules/ExtendedWrapperSDk/wrapper.ts +448 -0
  17. package/src/modules/avnu.ts +17 -4
  18. package/src/modules/ekubo-quoter.ts +89 -10
  19. package/src/modules/erc20.ts +67 -21
  20. package/src/modules/harvests.ts +29 -43
  21. package/src/modules/index.ts +5 -1
  22. package/src/modules/lst-apr.ts +36 -0
  23. package/src/modules/midas.ts +159 -0
  24. package/src/modules/pricer-from-api.ts +2 -2
  25. package/src/modules/pricer-lst.ts +1 -1
  26. package/src/modules/pricer.ts +3 -38
  27. package/src/modules/token-market-data.ts +202 -0
  28. package/src/node/deployer.ts +1 -36
  29. package/src/strategies/autoCompounderStrk.ts +1 -1
  30. package/src/strategies/base-strategy.ts +20 -3
  31. package/src/strategies/btc-vesu-extended-strategy/core-strategy.tsx +1486 -0
  32. package/src/strategies/btc-vesu-extended-strategy/services/operationService.ts +32 -0
  33. package/src/strategies/btc-vesu-extended-strategy/utils/constants.ts +3 -0
  34. package/src/strategies/btc-vesu-extended-strategy/utils/helper.ts +396 -0
  35. package/src/strategies/btc-vesu-extended-strategy/utils/types.ts +5 -0
  36. package/src/strategies/ekubo-cl-vault.tsx +123 -306
  37. package/src/strategies/index.ts +7 -1
  38. package/src/strategies/svk-strategy.ts +247 -0
  39. package/src/strategies/universal-adapters/adapter-optimizer.ts +65 -0
  40. package/src/strategies/universal-adapters/adapter-utils.ts +5 -1
  41. package/src/strategies/universal-adapters/avnu-adapter.ts +432 -0
  42. package/src/strategies/universal-adapters/baseAdapter.ts +181 -153
  43. package/src/strategies/universal-adapters/common-adapter.ts +98 -77
  44. package/src/strategies/universal-adapters/extended-adapter.ts +976 -0
  45. package/src/strategies/universal-adapters/index.ts +7 -1
  46. package/src/strategies/universal-adapters/unused-balance-adapter.ts +109 -0
  47. package/src/strategies/universal-adapters/vesu-adapter.ts +230 -230
  48. package/src/strategies/universal-adapters/vesu-borrow-adapter.ts +1247 -0
  49. package/src/strategies/universal-adapters/vesu-multiply-adapter.ts +1306 -0
  50. package/src/strategies/universal-adapters/vesu-supply-only-adapter.ts +58 -51
  51. package/src/strategies/universal-lst-muliplier-strategy.tsx +716 -844
  52. package/src/strategies/universal-strategy.tsx +1103 -1181
  53. package/src/strategies/vesu-extended-strategy/services/operationService.ts +34 -0
  54. package/src/strategies/vesu-extended-strategy/types/transaction-metadata.ts +25 -0
  55. package/src/strategies/vesu-extended-strategy/utils/config.runtime.ts +77 -0
  56. package/src/strategies/vesu-extended-strategy/utils/constants.ts +50 -0
  57. package/src/strategies/vesu-extended-strategy/utils/helper.ts +367 -0
  58. package/src/strategies/vesu-extended-strategy/vesu-extended-strategy.tsx +1420 -0
  59. package/src/strategies/vesu-rebalance.tsx +16 -20
  60. package/src/utils/health-factor-math.ts +11 -5
@@ -7,11 +7,11 @@ import { VesuRebalanceSettings } from "./vesu-rebalance";
7
7
  import { assert, LeafData, logger, StandardMerkleTree } from "@/utils";
8
8
  import UniversalVaultAbi from '../data/universal-vault.abi.json';
9
9
  import ManagerAbi from '../data/vault-manager.abi.json';
10
- import { ApproveCallParams, AvnuSwapCallParams, BaseAdapter, CommonAdapter, FlashloanCallParams, GenerateCallFn, LeafAdapterFn, ManageCall, VesuAdapter, VesuDefiSpringRewardsCallParams, VesuModifyPositionCallParams, VesuPools } from "./universal-adapters";
10
+ import { ApproveCallParams, AvnuSwapCallParams, BaseAdapter, CommonAdapter, DepositParams, FlashloanCallParams, GenerateCallFn, LeafAdapterFn, ManageCall, WithdrawParams } from "./universal-adapters";
11
11
  import { Global } from "@/global";
12
12
  import { AvnuWrapper, ERC20 } from "@/modules";
13
13
  import { AVNU_MIDDLEWARE, VESU_SINGLETON } from "./universal-adapters/adapter-utils";
14
- import { HarvestInfo, VesuHarvests } from "@/modules/harvests";
14
+ import { VesuHarvests } from "@/modules/harvests";
15
15
 
16
16
  export interface UniversalManageCall {
17
17
  proofs: string[];
@@ -24,17 +24,13 @@ export interface UniversalStrategySettings {
24
24
  manager: ContractAddr,
25
25
  vaultAllocator: ContractAddr,
26
26
  redeemRequestNFT: ContractAddr,
27
- aumOracle: ContractAddr,
28
- redemptionRouter?: ContractAddr, // optional router to redeem in different tokens
29
27
 
30
28
  // Individual merkle tree leaves
31
29
  leafAdapters: LeafAdapterFn<any>[],
32
30
 
33
31
  // Useful for returning adapter class objects that can compute
34
32
  // certain things for us (e.g. positions, hfs)
35
- adapters: {id: string, adapter: BaseAdapter}[],
36
- targetHealthFactor: number,
37
- minHealthFactor: number
33
+ adapters: {id: string, adapter: BaseAdapter<DepositParams, WithdrawParams>}[]
38
34
  }
39
35
 
40
36
  export enum AUMTypes {
@@ -42,787 +38,710 @@ export enum AUMTypes {
42
38
  DEFISPRING = 'defispring'
43
39
  }
44
40
 
45
- export class UniversalStrategy<
46
- S extends UniversalStrategySettings
47
- > extends BaseStrategy<
48
- SingleTokenInfo,
49
- SingleActionAmount
50
- > {
51
-
52
- /** Contract address of the strategy */
53
- readonly address: ContractAddr;
54
- /** Pricer instance for token price calculations */
55
- readonly pricer: PricerBase;
56
- /** Metadata containing strategy information */
57
- readonly metadata: IStrategyMetadata<S>;
58
- /** Contract instance for interacting with the strategy */
59
- readonly contract: Contract;
60
- readonly managerContract: Contract;
61
- merkleTree: StandardMerkleTree | undefined;
62
-
63
- constructor(
64
- config: IConfig,
65
- pricer: PricerBase,
66
- metadata: IStrategyMetadata<S>
67
- ) {
68
- super(config);
69
- this.pricer = pricer;
41
+ export enum PositionTypeAvnuExtended {
42
+ OPEN = 'open',
43
+ CLOSE = 'close'
44
+ }
45
+
46
+ // export class UniversalStrategy<
47
+ // S extends UniversalStrategySettings
48
+ // > extends BaseStrategy<
49
+ // SingleTokenInfo,
50
+ // SingleActionAmount
51
+ // > {
52
+
53
+ // /** Contract address of the strategy */
54
+ // readonly address: ContractAddr;
55
+ // /** Pricer instance for token price calculations */
56
+ // readonly pricer: PricerBase;
57
+ // /** Metadata containing strategy information */
58
+ // readonly metadata: IStrategyMetadata<S>;
59
+ // /** Contract instance for interacting with the strategy */
60
+ // readonly contract: Contract;
61
+ // readonly managerContract: Contract;
62
+ // merkleTree: StandardMerkleTree | undefined;
63
+
64
+ // constructor(
65
+ // config: IConfig,
66
+ // pricer: PricerBase,
67
+ // metadata: IStrategyMetadata<S>
68
+ // ) {
69
+ // super(config);
70
+ // this.pricer = pricer;
70
71
 
71
- assert(
72
- metadata.depositTokens.length === 1,
73
- "VesuRebalance only supports 1 deposit token"
74
- );
75
- this.metadata = metadata;
76
- this.address = metadata.address;
72
+ // assert(
73
+ // metadata.depositTokens.length === 1,
74
+ // "VesuRebalance only supports 1 deposit token"
75
+ // );
76
+ // this.metadata = metadata;
77
+ // this.address = metadata.address;
77
78
 
78
- this.contract = new Contract({
79
- abi: UniversalVaultAbi,
80
- address: this.address.address,
81
- providerOrAccount: this.config.provider
82
- });
83
- this.managerContract = new Contract({
84
- abi: ManagerAbi,
85
- address: this.metadata.additionalInfo.manager.address,
86
- providerOrAccount: this.config.provider
87
- });
88
- }
89
-
90
- getMerkleTree() {
91
- if (this.merkleTree) return this.merkleTree;
92
- const leaves = this.metadata.additionalInfo.leafAdapters.map((adapter, index) => {
93
- return adapter()
94
- });
95
- const standardTree = StandardMerkleTree.of(leaves.map(l => l.leaf));
96
- this.merkleTree = standardTree;
97
- return standardTree;
98
- }
99
-
100
- getMerkleRoot() {
101
- return this.getMerkleTree().root;
102
- }
103
-
104
- getProofs<T>(id: string): { proofs: string[], callConstructor: GenerateCallFn<T> } {
105
- const tree = this.getMerkleTree();
106
- let proofs: string[] = [];
107
- for (const [i, v] of tree.entries()) {
108
- if (v.readableId == id) {
109
- proofs = tree.getProof(i);
110
- }
111
- }
112
- if (proofs.length === 0) {
113
- throw new Error(`Proof not found for ID: ${id}`);
114
- }
115
-
116
- // find leaf adapter
117
- const leafAdapter = this.metadata.additionalInfo.leafAdapters.find(adapter => adapter().leaf.readableId === id);
118
- if (!leafAdapter) {
119
- throw new Error(`Leaf adapter not found for ID: ${id}`);
120
- }
121
- const leafInfo = leafAdapter();
122
- return {
123
- proofs,
124
- callConstructor: leafInfo.callConstructor.bind(leafInfo),
125
- };
126
- }
127
-
128
- getAdapter(id: string): BaseAdapter {
129
- const adapter = this.metadata.additionalInfo.adapters.find(adapter => adapter.id === id);
130
- if (!adapter) {
131
- throw new Error(`Adapter not found for ID: ${id}`);
132
- }
133
- return adapter.adapter;
134
- }
135
-
136
- asset() {
137
- return this.metadata.depositTokens[0];
138
- }
139
-
140
- async depositCall(amountInfo: SingleActionAmount, receiver: ContractAddr): Promise<Call[]> {
141
- // Technically its not erc4626 abi, but we just need approve call
142
- // so, its ok to use it
143
- assert(
144
- amountInfo.tokenInfo.address.eq(this.asset().address),
145
- "Deposit token mismatch"
146
- );
147
- const assetContract = new Contract({
148
- abi: UniversalVaultAbi,
149
- address: this.asset().address.address,
150
- providerOrAccount: this.config.provider
151
- });
152
- const call1 = assetContract.populate("approve", [
153
- this.address.address,
154
- uint256.bnToUint256(amountInfo.amount.toWei())
155
- ]);
156
- const call2 = this.contract.populate("deposit", [
157
- uint256.bnToUint256(amountInfo.amount.toWei()),
158
- receiver.address
159
- ]);
160
- return [call1, call2];
161
- }
162
-
163
- async withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
164
- assert(
165
- amountInfo.tokenInfo.address.eq(this.asset().address),
166
- "Withdraw token mismatch"
167
- );
168
- const shares = await this.contract.call('convert_to_shares', [uint256.bnToUint256(amountInfo.amount.toWei())]);
169
- const call = this.contract.populate("request_redeem", [
170
- uint256.bnToUint256(shares.toString()),
171
- receiver.address,
172
- owner.address
173
- ]);
174
- return [call];
175
- }
176
-
177
- /**
178
- * Calculates the Total Value Locked (TVL) for a specific user.
179
- * @param user - Address of the user
180
- * @returns Object containing the amount in token units and USD value
181
- */
182
- async getUserTVL(user: ContractAddr) {
183
- const shares = await this.contract.balanceOf(user.address);
184
- const assets = await this.contract.convert_to_assets(
185
- uint256.bnToUint256(shares)
186
- );
187
- const amount = Web3Number.fromWei(
188
- assets.toString(),
189
- this.metadata.depositTokens[0].decimals
190
- );
191
- let price = await this.pricer.getPrice(
192
- this.metadata.depositTokens[0].symbol
193
- );
194
- const usdValue = Number(amount.toFixed(6)) * price.price;
195
- return {
196
- tokenInfo: this.asset(),
197
- amount,
198
- usdValue
199
- };
200
- }
201
-
202
- async getVesuAPYs() {
203
- // get Vesu pools, positions and APYs
204
- const vesuAdapters = this.getVesuAdapters();
205
- const allVesuPools = await VesuAdapter.getVesuPools();
206
- const pools = vesuAdapters.map((vesuAdapter) => {
207
- return allVesuPools.pools.find(p => vesuAdapter.config.poolId.eqString(num.getHexString(p.id)));
208
- });
209
- logger.verbose(`${this.metadata.name}::netAPY: vesu-pools: ${JSON.stringify(pools)}`);
210
- if (pools.some(p => !p)) {
211
- throw new Error('Pool not found');
212
- };
213
- const positions = await this.getVesuPositions();
214
- logger.verbose(`${this.metadata.name}::netAPY: positions: ${JSON.stringify(positions)}`);
215
- const baseAPYs: number[] = [];
216
- const rewardAPYs: number[] = [];
79
+ // this.contract = new Contract({
80
+ // abi: UniversalVaultAbi,
81
+ // address: this.address.address,
82
+ // providerOrAccount: this.config.provider
83
+ // });
84
+ // this.managerContract = new Contract({
85
+ // abi: ManagerAbi,
86
+ // address: this.metadata.additionalInfo.manager.address,
87
+ // providerOrAccount: this.config.provider
88
+ // });
89
+ // }
90
+
91
+ // getAllLeaves() {
92
+ // const leaves = this.metadata.additionalInfo.leafAdapters.map((adapter, index) => {
93
+ // return adapter()
94
+ // });
95
+ // const _leaves: LeafData[] = [];
96
+ // leaves.forEach((_l) => {
97
+ // _leaves.push(..._l.leaves);
98
+ // })
99
+ // return _leaves;
100
+
101
+ // }
102
+ // getMerkleTree() {
103
+ // if (this.merkleTree) return this.merkleTree;
104
+ // const _leaves = this.getAllLeaves();
105
+
106
+ // const standardTree = StandardMerkleTree.of(_leaves);
107
+ // this.merkleTree = standardTree;
108
+ // return standardTree;
109
+ // }
110
+
111
+ // getMerkleRoot() {
112
+ // return this.getMerkleTree().root;
113
+ // }
114
+
115
+ // getAdapter(id: string): BaseAdapter<DepositParams, WithdrawParams> {
116
+ // const adapter = this.metadata.additionalInfo.adapters.find(adapter => adapter.id === id);
117
+ // if (!adapter) {
118
+ // throw new Error(`Adapter not found for ID: ${id}`);
119
+ // }
120
+ // return adapter.adapter;
121
+ // }
122
+
123
+ // asset() {
124
+ // return this.metadata.depositTokens[0];
125
+ // }
126
+
127
+ // async depositCall(amountInfo: SingleActionAmount, receiver: ContractAddr): Promise<Call[]> {
128
+ // // Technically its not erc4626 abi, but we just need approve call
129
+ // // so, its ok to use it
130
+ // assert(
131
+ // amountInfo.tokenInfo.address.eq(this.asset().address),
132
+ // "Deposit token mismatch"
133
+ // );
134
+ // const assetContract = new Contract({
135
+ // abi: UniversalVaultAbi,
136
+ // address: this.asset().address.address,
137
+ // providerOrAccount: this.config.provider
138
+ // });
139
+ // const call1 = assetContract.populate("approve", [
140
+ // this.address.address,
141
+ // uint256.bnToUint256(amountInfo.amount.toWei())
142
+ // ]);
143
+ // const call2 = this.contract.populate("deposit", [
144
+ // uint256.bnToUint256(amountInfo.amount.toWei()),
145
+ // receiver.address
146
+ // ]);
147
+ // return [call1, call2];
148
+ // }
149
+
150
+ // async withdrawCall(amountInfo: SingleActionAmount, receiver: ContractAddr, owner: ContractAddr): Promise<Call[]> {
151
+ // assert(
152
+ // amountInfo.tokenInfo.address.eq(this.asset().address),
153
+ // "Withdraw token mismatch"
154
+ // );
155
+ // const shares = await this.contract.call('convert_to_shares', [uint256.bnToUint256(amountInfo.amount.toWei())]);
156
+ // const call = this.contract.populate("request_redeem", [
157
+ // uint256.bnToUint256(shares.toString()),
158
+ // receiver.address,
159
+ // owner.address
160
+ // ]);
161
+ // return [call];
162
+ // }
163
+
164
+ // /**
165
+ // * Calculates the Total Value Locked (TVL) for a specific user.
166
+ // * @param user - Address of the user
167
+ // * @returns Object containing the amount in token units and USD value
168
+ // */
169
+ // async getUserTVL(user: ContractAddr) {
170
+ // const shares = await this.contract.balance_of(user.address);
171
+ // const assets = await this.contract.convert_to_assets(
172
+ // uint256.bnToUint256(shares)
173
+ // );
174
+ // const amount = Web3Number.fromWei(
175
+ // assets.toString(),
176
+ // this.metadata.depositTokens[0].decimals
177
+ // );
178
+ // let price = await this.pricer.getPrice(
179
+ // this.metadata.depositTokens[0].symbol
180
+ // );
181
+ // const usdValue = Number(amount.toFixed(6)) * price.price;
182
+ // return {
183
+ // tokenInfo: this.asset(),
184
+ // amount,
185
+ // usdValue
186
+ // };
187
+ // }
188
+
189
+ // /**
190
+ // * Calculates the weighted average APY across all pools based on USD value.
191
+ // * @returns {Promise<number>} The weighted average APY across all pools
192
+ // */
193
+ // async netAPY(): Promise<{ net: number, splits: { apy: number, id: string }[] }> {
194
+ // if (this.metadata.isPreview) {
195
+ // return { net: 0, splits: [{
196
+ // apy: 0, id: 'base'
197
+ // }, {
198
+ // apy: 0, id: 'defispring'
199
+ // }] };
200
+ // }
217
201
 
202
+ // const { positions, baseAPYs, rewardAPYs } = await this.getVesuAPYs();
203
+
204
+ // const unusedBalanceAPY = await this.getUnusedBalanceAPY();
205
+ // baseAPYs.push(...[unusedBalanceAPY.apy]);
206
+ // rewardAPYs.push(0);
207
+
208
+ // // Compute APy using weights
209
+ // const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
210
+ // weights.push(unusedBalanceAPY.weight);
211
+
212
+ // const prevAUM = await this.getPrevAUM();
213
+ // const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
214
+ // const prevAUMUSD = prevAUM.multipliedBy(price.price);
215
+ // return this.returnNetAPY(baseAPYs, rewardAPYs, weights, prevAUMUSD);
216
+ // }
217
+
218
+ // protected async returnNetAPY(baseAPYs: number[], rewardAPYs: number[], weights: number[], prevAUMUSD: Web3Number) {
219
+ // // If no positions, return 0
220
+ // if (weights.every(p => p == 0)) {
221
+ // return { net: 0, splits: [{
222
+ // apy: 0, id: 'base'
223
+ // }, {
224
+ // apy: 0, id: 'defispring'
225
+ // }]};
226
+ // }
227
+
228
+ // const baseAPY = this.computeAPY(baseAPYs, weights, prevAUMUSD);
229
+ // const rewardAPY = this.computeAPY(rewardAPYs, weights, prevAUMUSD);
230
+ // const netAPY = baseAPY + rewardAPY;
231
+ // logger.verbose(`${this.metadata.name}::netAPY: net: ${netAPY}, baseAPY: ${baseAPY}, rewardAPY: ${rewardAPY}`);
232
+ // return { net: netAPY, splits: [{
233
+ // apy: baseAPY, id: 'base'
234
+ // }, {
235
+ // apy: rewardAPY, id: 'defispring'
236
+ // }] };
237
+ // }
238
+
239
+ // protected async getUnusedBalanceAPY() {
240
+ // return {
241
+ // apy: 0, weight: 0
242
+ // }
243
+ // }
244
+
245
+ // private computeAPY(apys: number[], weights: number[], currentAUM: Web3Number) {
246
+ // assert(apys.length === weights.length, "APYs and weights length mismatch");
247
+ // const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
248
+ // logger.verbose(`${this.getTag()} computeAPY: apys: ${JSON.stringify(apys)}, weights: ${JSON.stringify(weights)}, weightedSum: ${weightedSum}, currentAUM: ${currentAUM}`);
249
+ // return weightedSum / currentAUM.toNumber();
250
+ // }
251
+
252
+ // /**
253
+ // * Calculates the total TVL of the strategy.
254
+ // * @returns Object containing the total amount in token units and USD value
255
+ // */
256
+ // async getTVL() {
257
+ // const assets = await this.contract.total_assets();
258
+ // const amount = Web3Number.fromWei(
259
+ // assets.toString(),
260
+ // this.metadata.depositTokens[0].decimals
261
+ // );
262
+ // let price = await this.pricer.getPrice(
263
+ // this.metadata.depositTokens[0].symbol
264
+ // );
265
+ // const usdValue = Number(amount.toFixed(6)) * price.price;
266
+ // return {
267
+ // tokenInfo: this.asset(),
268
+ // amount,
269
+ // usdValue
270
+ // };
271
+ // }
272
+
273
+ // async getUnusedBalance(): Promise<SingleTokenInfo> {
274
+ // const balance = await (new ERC20(this.config)).balanceOf(this.asset().address, this.metadata.additionalInfo.vaultAllocator, this.asset().decimals);
275
+ // const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
276
+ // const usdValue = Number(balance.toFixed(6)) * price.price;
277
+ // return {
278
+ // tokenInfo: this.asset(),
279
+ // amount: balance,
280
+ // usdValue
281
+ // };
282
+ // }
283
+
284
+ // protected async getVesuAUM(adapter: VesuAdapter) {
285
+ // const legAUM = await adapter.getPositions(this.config);
286
+ // const underlying = this.asset();
287
+ // let vesuAum = Web3Number.fromWei("0", underlying.decimals);
218
288
 
219
- for (const [index, pool] of pools.entries()) {
220
- const vesuAdapter = vesuAdapters[index];
221
- const collateralAsset = pool.assets.find((a: any) => a.symbol.toLowerCase() === vesuAdapter.config.collateral.symbol.toLowerCase())?.stats!;
222
- const debtAsset = pool.assets.find((a: any) => a.symbol.toLowerCase() === vesuAdapter.config.debt.symbol.toLowerCase())?.stats!;
223
- const supplyApy = Number(collateralAsset.supplyApy.value || 0) / 1e18;
224
-
225
- // Use LST APR from Endur API instead of Vesu's lstApr
226
- const lstAPY = await this.getLSTAPR(vesuAdapter.config.collateral.address);
227
- logger.verbose(`${this.metadata.name}::netAPY: ${vesuAdapter.config.collateral.symbol} LST APR from Endur: ${lstAPY}`);
228
-
229
- baseAPYs.push(...[supplyApy + lstAPY, Number(debtAsset.borrowApr.value) / 1e18]);
230
- rewardAPYs.push(...[Number(collateralAsset.defiSpringSupplyApr?.value || "0") / 1e18, 0]);
231
- }
232
- logger.verbose(`${this.metadata.name}::netAPY: baseAPYs: ${JSON.stringify(baseAPYs)}`);
233
- logger.verbose(`${this.metadata.name}::netAPY: rewardAPYs: ${JSON.stringify(rewardAPYs)}`);
234
-
235
- // Else further compute will fail
236
- assert(baseAPYs.length == positions.length, 'APYs and positions length mismatch');
289
+ // let tokenUnderlyingPrice = await this.pricer.getPrice(this.asset().symbol);
290
+ // logger.verbose(`${this.getTag()} tokenUnderlyingPrice: ${tokenUnderlyingPrice.price}`);
237
291
 
238
- return {
239
- baseAPYs,
240
- rewardAPYs,
241
- positions
242
- }
243
- }
244
-
245
- /**
246
- * Calculates the weighted average APY across all pools based on USD value.
247
- * @returns {Promise<number>} The weighted average APY across all pools
248
- */
249
- async netAPY(): Promise<{ net: number, splits: { apy: number, id: string }[] }> {
250
- if (this.metadata.isPreview) {
251
- return { net: 0, splits: [{
252
- apy: 0, id: 'base'
253
- }, {
254
- apy: 0, id: 'defispring'
255
- }] };
256
- }
292
+ // // handle collateral
293
+ // if (legAUM[0].token.address.eq(underlying.address)) {
294
+ // vesuAum = vesuAum.plus(legAUM[0].amount);
295
+ // } else {
296
+ // vesuAum = vesuAum.plus(legAUM[0].usdValue / tokenUnderlyingPrice.price);
297
+ // }
298
+
299
+ // // handle debt
300
+ // if (legAUM[1].token.address.eq(underlying.address)) {
301
+ // vesuAum = vesuAum.minus(legAUM[1].amount);
302
+ // } else {
303
+ // vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
304
+ // };
305
+
306
+ // logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
307
+ // return vesuAum;
308
+ // }
309
+
310
+ // async getPrevAUM() {
311
+ // const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
312
+ // const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
313
+ // logger.verbose(`${this.getTag()} Prev AUM: ${prevAum}`);
314
+ // return prevAum;
315
+ // }
316
+
317
+ // async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
318
+ // const prevAum = await this.getPrevAUM();
319
+ // const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
320
+
321
+ // // calculate vesu aum
322
+ // const vesuAdapters = this.getVesuAdapters();
323
+ // let vesuAum = Web3Number.fromWei("0", this.asset().decimals);
324
+ // for (const adapter of vesuAdapters) {
325
+ // vesuAum = vesuAum.plus(await this.getVesuAUM(adapter));
326
+ // }
327
+
328
+ // // account unused balance as aum as well (from vault allocator)
329
+ // const balance = await this.getUnusedBalance();
330
+ // logger.verbose(`${this.getTag()} unused balance: ${balance.amount.toNumber()}`);
331
+
332
+ // // Initiate return values
333
+ // const zeroAmt = Web3Number.fromWei('0', this.asset().decimals);
334
+ // const net = {
335
+ // tokenInfo: this.asset(),
336
+ // amount: zeroAmt,
337
+ // usdValue: 0
338
+ // };
339
+ // const aumToken = vesuAum.plus(balance.amount);
340
+ // if (aumToken.isZero()) {
341
+ // return { net, splits: [{
342
+ // aum: zeroAmt, id: AUMTypes.FINALISED
343
+ // }, {
344
+ // aum: zeroAmt, id: AUMTypes.DEFISPRING
345
+ // }], prevAum};
346
+ // }
347
+ // logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
348
+
349
+ // // compute rewards contribution to AUM
350
+ // const rewardAssets = await this.getRewardsAUM(prevAum);
351
+
352
+ // // Sum up and return
353
+ // const newAUM = aumToken.plus(rewardAssets);
354
+ // logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
257
355
 
258
- const { positions, baseAPYs, rewardAPYs } = await this.getVesuAPYs();
259
-
260
- const unusedBalanceAPY = await this.getUnusedBalanceAPY();
261
- baseAPYs.push(...[unusedBalanceAPY.apy]);
262
- rewardAPYs.push(0);
263
-
264
- // Compute APy using weights
265
- const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
266
- weights.push(unusedBalanceAPY.weight);
267
-
268
- const prevAUM = await this.getPrevAUM();
269
- const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
270
- const prevAUMUSD = prevAUM.multipliedBy(price.price);
271
- return this.returnNetAPY(baseAPYs, rewardAPYs, weights, prevAUMUSD);
272
- }
273
-
274
- protected async returnNetAPY(baseAPYs: number[], rewardAPYs: number[], weights: number[], prevAUMUSD: Web3Number) {
275
- // If no positions, return 0
276
- if (weights.every(p => p == 0)) {
277
- return { net: 0, splits: [{
278
- apy: 0, id: 'base'
279
- }, {
280
- apy: 0, id: 'defispring'
281
- }]};
282
- }
283
-
284
- const baseAPY = this.computeAPY(baseAPYs, weights, prevAUMUSD);
285
- const rewardAPY = this.computeAPY(rewardAPYs, weights, prevAUMUSD);
286
- const netAPY = baseAPY + rewardAPY;
287
- logger.verbose(`${this.metadata.name}::netAPY: net: ${netAPY}, baseAPY: ${baseAPY}, rewardAPY: ${rewardAPY}`);
288
- return { net: netAPY, splits: [{
289
- apy: baseAPY, id: 'base'
290
- }, {
291
- apy: rewardAPY, id: 'defispring'
292
- }] };
293
- }
294
-
295
- protected async getUnusedBalanceAPY() {
296
- return {
297
- apy: 0, weight: 0
298
- }
299
- }
300
-
301
- private computeAPY(apys: number[], weights: number[], currentAUM: Web3Number) {
302
- assert(apys.length === weights.length, "APYs and weights length mismatch");
303
- const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
304
- logger.verbose(`${this.getTag()} computeAPY: apys: ${JSON.stringify(apys)}, weights: ${JSON.stringify(weights)}, weightedSum: ${weightedSum}, currentAUM: ${currentAUM}`);
305
- return weightedSum / currentAUM.toNumber();
306
- }
307
-
308
- /**
309
- * Calculates the total TVL of the strategy.
310
- * @returns Object containing the total amount in token units and USD value
311
- */
312
- async getTVL() {
313
- const assets = await this.contract.total_assets();
314
- const amount = Web3Number.fromWei(
315
- assets.toString(),
316
- this.metadata.depositTokens[0].decimals
317
- );
318
- let price = await this.pricer.getPrice(
319
- this.metadata.depositTokens[0].symbol
320
- );
321
- const usdValue = Number(amount.toFixed(6)) * price.price;
322
- return {
323
- tokenInfo: this.asset(),
324
- amount,
325
- usdValue
326
- };
327
- }
328
-
329
- async getUnusedBalance(): Promise<SingleTokenInfo> {
330
- const balance = await (new ERC20(this.config)).balanceOf(this.asset().address, this.metadata.additionalInfo.vaultAllocator, this.asset().decimals);
331
- const price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
332
- const usdValue = Number(balance.toFixed(6)) * price.price;
333
- return {
334
- tokenInfo: this.asset(),
335
- amount: balance,
336
- usdValue
337
- };
338
- }
339
-
340
- protected async getVesuAUM(adapter: VesuAdapter) {
341
- const legAUM = await adapter.getPositions(this.config);
342
- const underlying = this.asset();
343
- let vesuAum = Web3Number.fromWei("0", underlying.decimals);
344
-
345
- let tokenUnderlyingPrice = await this.pricer.getPrice(this.asset().symbol);
346
- logger.verbose(`${this.getTag()} tokenUnderlyingPrice: ${tokenUnderlyingPrice.price}`);
347
-
348
- // handle collateral
349
- if (legAUM[0].token.address.eq(underlying.address)) {
350
- vesuAum = vesuAum.plus(legAUM[0].amount);
351
- } else {
352
- vesuAum = vesuAum.plus(legAUM[0].usdValue / tokenUnderlyingPrice.price);
353
- }
354
-
355
- // handle debt
356
- if (legAUM[1].token.address.eq(underlying.address)) {
357
- vesuAum = vesuAum.minus(legAUM[1].amount);
358
- } else {
359
- vesuAum = vesuAum.minus(legAUM[1].usdValue / tokenUnderlyingPrice.price);
360
- };
361
-
362
- logger.verbose(`${this.getTag()} Vesu AUM: ${vesuAum}, legCollateral: ${legAUM[0].amount.toNumber()}, legDebt: ${legAUM[1].amount.toNumber()}`);
363
- return vesuAum;
364
- }
365
-
366
- async getPrevAUM() {
367
- const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
368
- const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
369
- logger.verbose(`${this.getTag()} Prev AUM: ${prevAum}`);
370
- return prevAum;
371
- }
372
-
373
- async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
374
- const prevAum = await this.getPrevAUM();
375
- const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
376
-
377
- // calculate vesu aum
378
- const vesuAdapters = this.getVesuAdapters();
379
- let vesuAum = Web3Number.fromWei("0", this.asset().decimals);
380
- for (const adapter of vesuAdapters) {
381
- vesuAum = vesuAum.plus(await this.getVesuAUM(adapter));
382
- }
383
-
384
- // account unused balance as aum as well (from vault allocator)
385
- const balance = await this.getUnusedBalance();
386
- logger.verbose(`${this.getTag()} unused balance: ${balance.amount.toNumber()}`);
387
-
388
- // Initiate return values
389
- const zeroAmt = Web3Number.fromWei('0', this.asset().decimals);
390
- const net = {
391
- tokenInfo: this.asset(),
392
- amount: zeroAmt,
393
- usdValue: 0
394
- };
395
- const aumToken = vesuAum.plus(balance.amount);
396
- if (aumToken.isZero()) {
397
- return { net, splits: [{
398
- aum: zeroAmt, id: AUMTypes.FINALISED
399
- }, {
400
- aum: zeroAmt, id: AUMTypes.DEFISPRING
401
- }], prevAum};
402
- }
403
- logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
404
-
405
- // compute rewards contribution to AUM
406
- const rewardAssets = await this.getRewardsAUM(prevAum);
407
-
408
- // Sum up and return
409
- const newAUM = aumToken.plus(rewardAssets);
410
- logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
411
-
412
- net.amount = newAUM;
413
- net.usdValue = newAUM.multipliedBy(token1Price.price).toNumber();
414
- const splits = [{
415
- id: AUMTypes.FINALISED,
416
- aum: aumToken
417
- }, {
418
- id: AUMTypes.DEFISPRING,
419
- aum: rewardAssets
420
- }];
421
- return { net, splits, prevAum };
422
- }
423
-
424
- // account for future rewards (e.g. defispring rewards)
425
- protected async getRewardsAUM(prevAum: Web3Number) {
426
- const lastReportTime = await this.contract.call('last_report_timestamp', []);
427
- // - calculate estimated growth from strk rewards
428
- const netAPY = await this.netAPY();
429
- // account only 80% of value
430
- const defispringAPY = (netAPY.splits.find(s => s.id === 'defispring')?.apy || 0) * 0.8;
431
- // if (!defispringAPY) throw new Error('DefiSpring APY not found');
432
-
433
- // compute rewards contribution to AUM
434
- const timeDiff = (Math.round(Date.now() / 1000) - Number(lastReportTime));
435
- const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
436
- const rewardAssets = prevAum.multipliedBy(growthRate);
437
- logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
438
- logger.verbose(`${this.getTag()} Current AUM: ${prevAum.toString()}`);
439
- logger.verbose(`${this.getTag()} Net APY: ${JSON.stringify(netAPY)}`);
440
- logger.verbose(`${this.getTag()} rewards AUM: ${rewardAssets}`);
441
-
442
- return rewardAssets;
443
- }
444
-
445
- getVesuAdapters() {
446
- const vesuAdapter1 = this.getAdapter(UNIVERSAL_ADAPTERS.VESU_LEG1) as VesuAdapter;
447
- const vesuAdapter2 = this.getAdapter(UNIVERSAL_ADAPTERS.VESU_LEG2) as VesuAdapter;
448
- vesuAdapter1.pricer = this.pricer;
449
- vesuAdapter2.pricer = this.pricer;
450
- vesuAdapter1.networkConfig = this.config;
451
- vesuAdapter2.networkConfig = this.config;
452
-
453
- return [vesuAdapter1, vesuAdapter2];
454
- }
455
-
456
- async getVesuPositions(blockNumber: BlockIdentifier = 'latest'): Promise<VaultPosition[]> {
457
- const adapters = this.getVesuAdapters();
458
- const positions: VaultPosition[] = [];
459
- for (const adapter of adapters) {
460
- positions.push(...await adapter.getPositions(this.config, blockNumber));
461
- }
462
- return positions;
463
- }
464
-
465
- async getVaultPositions(): Promise<VaultPosition[]> {
466
- const vesuPositions = await this.getVesuPositions();
467
- const unusedBalance = await this.getUnusedBalance();
468
- return [...vesuPositions, {
469
- amount: unusedBalance.amount,
470
- usdValue: unusedBalance.usdValue,
471
- token: this.asset(),
472
- remarks: "Unused Balance (may not include recent deposits)"
473
- }];
474
- }
475
-
476
- getSetManagerCall(strategist: ContractAddr, root = this.getMerkleRoot()) {
477
- return this.managerContract.populate('set_manage_root', [strategist.address, num.getHexString(root)]);
478
- }
356
+ // net.amount = newAUM;
357
+ // net.usdValue = newAUM.multipliedBy(token1Price.price).toNumber();
358
+ // const splits = [{
359
+ // id: AUMTypes.FINALISED,
360
+ // aum: aumToken
361
+ // }, {
362
+ // id: AUMTypes.DEFISPRING,
363
+ // aum: rewardAssets
364
+ // }];
365
+ // return { net, splits, prevAum };
366
+ // }
367
+
368
+ // // account for future rewards (e.g. defispring rewards)
369
+ // protected async getRewardsAUM(prevAum: Web3Number) {
370
+ // const lastReportTime = await this.contract.call('last_report_timestamp', []);
371
+ // // - calculate estimated growth from strk rewards
372
+ // const netAPY = await this.netAPY();
373
+ // // account only 80% of value
374
+ // const defispringAPY = (netAPY.splits.find(s => s.id === 'defispring')?.apy || 0) * 0.8;
375
+ // if (!defispringAPY) throw new Error('DefiSpring APY not found');
376
+
377
+ // // compute rewards contribution to AUM
378
+ // const timeDiff = (Math.round(Date.now() / 1000) - Number(lastReportTime));
379
+ // const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
380
+ // const rewardAssets = prevAum.multipliedBy(growthRate);
381
+ // logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
382
+ // logger.verbose(`${this.getTag()} Current AUM: ${prevAum.toString()}`);
383
+ // logger.verbose(`${this.getTag()} Net APY: ${JSON.stringify(netAPY)}`);
384
+ // logger.verbose(`${this.getTag()} rewards AUM: ${rewardAssets}`);
385
+
386
+ // return rewardAssets;
387
+ // }
388
+
389
+
390
+
391
+ // async getVaultPositions(): Promise<VaultPosition[]> {
392
+ // const vesuPositions = await this.getVesuPositions();
393
+ // const unusedBalance = await this.getUnusedBalance();
394
+ // return [...vesuPositions, {
395
+ // amount: unusedBalance.amount,
396
+ // usdValue: unusedBalance.usdValue,
397
+ // token: this.asset(),
398
+ // remarks: "Unused Balance (may not include recent deposits)"
399
+ // }];
400
+ // }
401
+
402
+ // getSetManagerCall(strategist: ContractAddr, root = this.getMerkleRoot()) {
403
+ // return this.managerContract.populate('set_manage_root', [strategist.address, num.getHexString(root)]);
404
+ // }
479
405
 
480
- getManageCall(proofIds: string[], manageCalls: ManageCall[]) {
481
- assert(proofIds.length == manageCalls.length, 'Proof IDs and Manage Calls length mismatch');
482
- return this.managerContract.populate('manage_vault_with_merkle_verification', {
483
- proofs: proofIds.map(id => this.getProofs(id).proofs),
484
- decoder_and_sanitizers: manageCalls.map(call => call.sanitizer.address),
485
- targets: manageCalls.map(call => call.call.contractAddress.address),
486
- selectors: manageCalls.map(call => call.call.selector),
487
- calldatas: manageCalls.map(call => call.call.calldata), // Calldata[]
488
- });
489
- }
406
+ // getManageCall(proofIds: string[], manageCalls: ManageCall[]) {
407
+ // assert(proofIds.length == manageCalls.length, 'Proof IDs and Manage Calls length mismatch');
408
+ // return this.managerContract.populate('manage_vault_with_merkle_verification', {
409
+ // proofs: proofIds.map(id => this.getProofs(id).proofs),
410
+ // decoder_and_sanitizers: manageCalls.map(call => call.sanitizer.address),
411
+ // targets: manageCalls.map(call => call.call.contractAddress.address),
412
+ // selectors: manageCalls.map(call => call.call.selector),
413
+ // calldatas: manageCalls.map(call => call.call.calldata), // Calldata[]
414
+ // });
415
+ // }
490
416
 
491
- getVesuModifyPositionCalls(params: {
492
- isLeg1: boolean,
493
- isDeposit: boolean,
494
- depositAmount: Web3Number,
495
- debtAmount: Web3Number
496
- }): UniversalManageCall[] {
497
- assert(params.depositAmount.gt(0) || params.debtAmount.gt(0), 'Either deposit or debt amount must be greater than 0');
498
- // approve token
499
- const isToken1 = params.isLeg1 == params.isDeposit; // XOR
500
- const STEP1_ID = isToken1 ? UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1 :UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2;
501
- const manage4Info = this.getProofs<ApproveCallParams>(STEP1_ID);
502
- const approveAmount = params.isDeposit ? params.depositAmount : params.debtAmount;
503
- const manageCall4 = manage4Info.callConstructor({
504
- amount: approveAmount
505
- })
506
-
507
- // deposit and borrow or repay and withdraw
508
- const STEP2_ID = params.isLeg1 ? UNIVERSAL_MANAGE_IDS.VESU_LEG1 : UNIVERSAL_MANAGE_IDS.VESU_LEG2;
509
- const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP2_ID);
510
- const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
511
- collateralAmount: params.depositAmount,
512
- isAddCollateral: params.isDeposit,
513
- debtAmount: params.debtAmount,
514
- isBorrow: params.isDeposit
515
- }))
516
-
517
- const output = [{
518
- proofs: manage5Info.proofs,
519
- manageCall: manageCall5,
520
- step: STEP2_ID
521
- }];
522
- if (approveAmount.gt(0)) {
523
- output.unshift({
524
- proofs: manage4Info.proofs,
525
- manageCall: manageCall4,
526
- step: STEP1_ID
527
- })
528
- }
529
- return output;
530
- }
531
-
532
- getTag() {
533
- return `${UniversalStrategy.name}:${this.metadata.name}`;
534
- }
535
-
536
- /**
537
- * Gets LST APR for the strategy's underlying asset from Endur API
538
- * @returns Promise<number> The LST APR (not divided by 1e18)
539
- */
540
- async getLSTAPR(address: ContractAddr): Promise<number> {
541
- return 0;
542
- }
543
-
544
- async getVesuHealthFactors(blockNumber: BlockIdentifier = 'latest') {
545
- return await Promise.all(this.getVesuAdapters().map(v => v.getHealthFactor(blockNumber)));
546
- }
547
-
548
- async computeRebalanceConditionAndReturnCalls(): Promise<Call[]> {
549
- const vesuAdapters = this.getVesuAdapters();
550
- const healthFactors = await this.getVesuHealthFactors();
551
- const leg1HealthFactor = healthFactors[0];
552
- const leg2HealthFactor = healthFactors[1];
553
- logger.verbose(`${this.getTag()}: HealthFactorLeg1: ${leg1HealthFactor}`);
554
- logger.verbose(`${this.getTag()}: HealthFactorLeg2: ${leg2HealthFactor}`);
555
-
556
- const minHf = this.metadata.additionalInfo.minHealthFactor;
557
- const isRebalanceNeeded1 = leg1HealthFactor < minHf;
558
- const isRebalanceNeeded2 = leg2HealthFactor < minHf;
559
- if (!isRebalanceNeeded1 && !isRebalanceNeeded2) {
560
- return [];
561
- }
417
+ // getVesuModifyPositionCalls(params: {
418
+ // isLeg1: boolean,
419
+ // isDeposit: boolean,
420
+ // depositAmount: Web3Number,
421
+ // debtAmount: Web3Number
422
+ // }): UniversalManageCall[] {
423
+ // assert(params.depositAmount.gt(0) || params.debtAmount.gt(0), 'Either deposit or debt amount must be greater than 0');
424
+ // // approve token
425
+ // const isToken1 = params.isLeg1 == params.isDeposit; // XOR
426
+ // const STEP1_ID = isToken1 ? UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1 :UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2;
427
+ // const manage4Info = this.getProofs<ApproveCallParams>(STEP1_ID);
428
+ // const approveAmount = params.isDeposit ? params.depositAmount : params.debtAmount;
429
+ // const manageCall4 = manage4Info.callConstructor({
430
+ // amount: approveAmount
431
+ // })
432
+
433
+ // // deposit and borrow or repay and withdraw
434
+ // const STEP2_ID = params.isLeg1 ? UNIVERSAL_MANAGE_IDS.VESU_LEG1 : UNIVERSAL_MANAGE_IDS.VESU_LEG2;
435
+ // const manage5Info = this.getProofs<VesuModifyPositionCallParams>(STEP2_ID);
436
+ // const manageCall5 = manage5Info.callConstructor(VesuAdapter.getDefaultModifyPositionCallParams({
437
+ // collateralAmount: params.depositAmount,
438
+ // isAddCollateral: params.isDeposit,
439
+ // debtAmount: params.debtAmount,
440
+ // isBorrow: params.isDeposit
441
+ // }))
442
+
443
+ // const output = [{
444
+ // proofs: manage5Info.proofs,
445
+ // manageCall: manageCall5,
446
+ // step: STEP2_ID
447
+ // }];
448
+ // if (approveAmount.gt(0)) {
449
+ // output.unshift({
450
+ // proofs: manage4Info.proofs,
451
+ // manageCall: manageCall4,
452
+ // step: STEP1_ID
453
+ // })
454
+ // }
455
+ // return output;
456
+ // }
457
+
458
+ // getTag() {
459
+ // return `${UniversalStrategy.name}:${this.metadata.name}`;
460
+ // }
461
+
462
+ // /**
463
+ // * Gets LST APR for the strategy's underlying asset from Endur API
464
+ // * @returns Promise<number> The LST APR (not divided by 1e18)
465
+ // */
466
+ // async getLSTAPR(address: ContractAddr): Promise<number> {
467
+ // return 0;
468
+ // }
469
+
470
+ // async getVesuHealthFactors(blockNumber: BlockIdentifier = 'latest') {
471
+ // return await Promise.all(this.getVesuAdapters().map(v => v.getHealthFactor(blockNumber)));
472
+ // }
473
+
474
+ // async computeRebalanceConditionAndReturnCalls(): Promise<Call[]> {
475
+ // const vesuAdapters = this.getVesuAdapters();
476
+ // const healthFactors = await this.getVesuHealthFactors();
477
+ // const leg1HealthFactor = healthFactors[0];
478
+ // const leg2HealthFactor = healthFactors[1];
479
+ // logger.verbose(`${this.getTag()}: HealthFactorLeg1: ${leg1HealthFactor}`);
480
+ // logger.verbose(`${this.getTag()}: HealthFactorLeg2: ${leg2HealthFactor}`);
481
+
482
+ // const minHf = this.metadata.additionalInfo.minHealthFactor;
483
+ // const isRebalanceNeeded1 = leg1HealthFactor < minHf;
484
+ // const isRebalanceNeeded2 = leg2HealthFactor < minHf;
485
+ // if (!isRebalanceNeeded1 && !isRebalanceNeeded2) {
486
+ // return [];
487
+ // }
562
488
 
563
- if (isRebalanceNeeded1) {
564
- const amount = await this.getLegRebalanceAmount(vesuAdapters[0], leg1HealthFactor, false);
565
- const leg2HF = await this.getNewHealthFactor(vesuAdapters[1], amount, true);
566
- assert(leg2HF > minHf, `Rebalance Leg1 failed: Leg2 HF after rebalance would be too low: ${leg2HF}`);
567
- return [await this.getRebalanceCall({
568
- isLeg1toLeg2: false,
569
- amount: amount
570
- })];
571
- } else {
572
- const amount = await this.getLegRebalanceAmount(vesuAdapters[1], leg2HealthFactor, true);
573
- const leg1HF = await this.getNewHealthFactor(vesuAdapters[0], amount, false);
574
- assert(leg1HF > minHf, `Rebalance Leg2 failed: Leg1 HF after rebalance would be too low: ${leg1HF}`);
575
- return [await this.getRebalanceCall({
576
- isLeg1toLeg2: true,
577
- amount: amount
578
- })];
579
- }
580
- }
581
-
582
- private async getNewHealthFactor(vesuAdapter: VesuAdapter, newAmount: Web3Number, isWithdraw: boolean) {
583
- const {
584
- collateralTokenAmount,
585
- collateralUSDAmount,
586
- collateralPrice,
587
- debtTokenAmount,
588
- debtUSDAmount,
589
- debtPrice,
590
- ltv
591
- } = await vesuAdapter.getAssetPrices();
592
-
593
- if (isWithdraw) {
594
- const newHF = ((collateralTokenAmount.toNumber() - newAmount.toNumber()) * collateralPrice * ltv) / debtUSDAmount;
595
- logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isDeposit`);
596
- return newHF;
597
- } else { // is borrow
598
- const newHF = (collateralUSDAmount * ltv) / ((debtTokenAmount.toNumber() + newAmount.toNumber()) * debtPrice);
599
- logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isRepay`);
600
- return newHF;
601
- }
602
- }
603
-
604
- /**
605
- *
606
- * @param vesuAdapter
607
- * @param currentHf
608
- * @param isDeposit if true, attempt by adding collateral, else by repaying
609
- * @returns
610
- */
611
- private async getLegRebalanceAmount(vesuAdapter: VesuAdapter, currentHf: number, isDeposit: boolean) {
612
- const {
613
- collateralTokenAmount,
614
- collateralUSDAmount,
615
- collateralPrice,
616
- debtTokenAmount,
617
- debtUSDAmount,
618
- debtPrice,
619
- ltv
620
- } = await vesuAdapter.getAssetPrices();
621
-
622
- // debt is zero, nothing to rebalance
623
- if(debtTokenAmount.isZero()) {
624
- return Web3Number.fromWei(0, 0);
625
- }
626
-
627
- assert(collateralPrice > 0 && debtPrice > 0, "getRebalanceAmount: Invalid price");
628
-
629
- // avoid calculating for too close
630
- const targetHF = this.metadata.additionalInfo.targetHealthFactor;
631
- if (currentHf > targetHF - 0.01)
632
- throw new Error("getLegRebalanceAmount: Current health factor is healthy");
633
-
634
- if (isDeposit) {
635
- // TargetHF = (collAmount + newAmount) * price * ltv / debtUSD
636
- const newAmount = targetHF * debtUSDAmount / (collateralPrice * ltv) - collateralTokenAmount.toNumber();
637
- logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: addCollateral, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
638
- return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
639
- } else {
640
- // TargetHF = collUSD * ltv / (debtAmount - newAmount) * debtPrice
641
- const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
642
- 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}`);
643
- return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
644
- }
645
- }
646
-
647
- async getVesuModifyPositionCall(params: {
648
- isDeposit: boolean,
649
- leg1DepositAmount: Web3Number
650
- }) {
651
- const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
652
- const leg1LTV = await vesuAdapter1.getLTVConfig(this.config);
653
- const leg2LTV = await vesuAdapter2.getLTVConfig(this.config);
654
- logger.verbose(`${this.getTag()}: LTVLeg1: ${leg1LTV}`);
655
- logger.verbose(`${this.getTag()}: LTVLeg2: ${leg2LTV}`);
656
-
657
- const token1Price = await this.pricer.getPrice(vesuAdapter1.config.collateral.symbol);
658
- const token2Price = await this.pricer.getPrice(vesuAdapter2.config.collateral.symbol);
659
- logger.verbose(`${this.getTag()}: Price${vesuAdapter1.config.collateral.symbol}: ${token1Price.price}`);
660
- logger.verbose(`${this.getTag()}: Price${vesuAdapter2.config.collateral.symbol}: ${token2Price.price}`);
661
-
662
- const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
663
-
664
- const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
665
- const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
666
-
667
- const borrow2Amount = new Web3Number(
668
- params.leg1DepositAmount.multipliedBy(k1.toFixed(6)).dividedBy(k2 - k1).toFixed(6),
669
- vesuAdapter2.config.debt.decimals
670
- );
671
- const borrow1Amount = new Web3Number(
672
- borrow2Amount.multipliedBy(k2).toFixed(6),
673
- vesuAdapter1.config.debt.decimals
674
- );
675
- logger.verbose(`${this.getTag()}:: leg1DepositAmount: ${params.leg1DepositAmount.toString()} ${vesuAdapter1.config.collateral.symbol}`);
676
- logger.verbose(`${this.getTag()}:: borrow1Amount: ${borrow1Amount.toString()} ${vesuAdapter1.config.debt.symbol}`);
677
- logger.verbose(`${this.getTag()}:: borrow2Amount: ${borrow2Amount.toString()} ${vesuAdapter2.config.debt.symbol}`);
678
-
679
- let callSet1 = this.getVesuModifyPositionCalls({
680
- isLeg1: true,
681
- isDeposit: params.isDeposit,
682
- depositAmount: params.leg1DepositAmount.plus(borrow2Amount),
683
- debtAmount: borrow1Amount
684
- });
685
-
686
- let callSet2 = this.getVesuModifyPositionCalls({
687
- isLeg1: false,
688
- isDeposit: params.isDeposit,
689
- depositAmount: borrow1Amount,
690
- debtAmount: borrow2Amount
691
- });
692
-
693
- if (!params.isDeposit) {
694
- let temp = callSet2;
695
- callSet2 = [...callSet1];
696
- callSet1 = [...temp];
697
- }
698
- const allActions = [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)];
699
- const flashloanCalldata = CallData.compile([
700
- [...callSet1.map(i => i.proofs), ...callSet2.map(i => i.proofs)],
701
- allActions.map(i => i.sanitizer.address),
702
- allActions.map(i => i.call.contractAddress.address),
703
- allActions.map(i => i.call.selector),
704
- allActions.map(i => i.call.calldata)
705
- ])
706
-
707
- // flash loan
708
- const STEP1_ID = UNIVERSAL_MANAGE_IDS.FLASH_LOAN;
709
- const manage1Info = this.getProofs<FlashloanCallParams>(STEP1_ID);
710
- const manageCall1 = manage1Info.callConstructor({
711
- amount: borrow2Amount,
712
- data: flashloanCalldata.map(i => BigInt(i))
713
- })
714
- const manageCall = this.getManageCall([UNIVERSAL_MANAGE_IDS.FLASH_LOAN], [manageCall1]);
715
- return manageCall;
716
- }
717
-
718
- async getBringLiquidityCall(params: {
719
- amount: Web3Number
720
- }) {
721
- const manage1Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY);
722
- const manageCall1 = manage1Info.callConstructor({
723
- amount: params.amount
724
- });
725
- const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY);
726
- const manageCall2 = manage2Info.callConstructor({
727
- amount: params.amount
728
- });
729
- const manageCall = this.getManageCall([UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY, UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY], [manageCall1, manageCall2]);
730
- return manageCall;
731
- }
732
-
733
- async getPendingRewards(): Promise<HarvestInfo[]> {
734
- const vesuHarvest = new VesuHarvests(this.config);
735
- return await vesuHarvest.getUnHarvestedRewards(this.metadata.additionalInfo.vaultAllocator);
736
- }
737
-
738
- async getHarvestCall() {
739
- const harvestInfo = await this.getPendingRewards();
740
- if (harvestInfo.length == 0) {
741
- throw new Error(`No pending rewards found`);
742
- }
743
- if (harvestInfo.length != 1) {
744
- throw new Error(`Expected 1 harvest info, got ${harvestInfo.length}`);
745
- }
746
-
747
- const amount = harvestInfo[0].claim.amount;
748
- const actualReward = harvestInfo[0].actualReward;
749
- const proofs = harvestInfo[0].proof;
750
- if (actualReward.isZero()) {
751
- throw new Error(`Expected non-zero actual reward, got ${harvestInfo[0].actualReward}`);
752
- }
753
-
754
- const manage1Info = this.getProofs<VesuDefiSpringRewardsCallParams>(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS);
755
- const manageCall1 = manage1Info.callConstructor({
756
- amount,
757
- proofs
758
- });
759
- const proofIds: string[] = [UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS];
760
- const manageCalls: ManageCall[] = [manageCall1];
761
-
762
- // swap rewards for underlying
763
- const STRK = Global.getDefaultTokens().find(t => t.symbol === 'STRK')!;
764
- if (this.asset().symbol != 'STRK') {
765
- // approve
766
- const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1);
767
- const manageCall2 = manage2Info.callConstructor({
768
- amount: actualReward
769
- });
770
-
771
- // swap
772
- const avnuModule = new AvnuWrapper();
773
- const quote = await avnuModule.getQuotes(
774
- STRK.address.address,
775
- this.asset().address.address,
776
- actualReward.toWei(),
777
- this.address.address
778
- );
779
- const swapInfo = await avnuModule.getSwapInfo(quote, this.address.address, 0, this.address.address);
780
- const manage3Info = this.getProofs<AvnuSwapCallParams>(UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS);
781
- const manageCall3 = manage3Info.callConstructor({
782
- props: swapInfo
783
- });
784
- proofIds.push(UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1);
785
- proofIds.push(UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS);
786
-
787
- manageCalls.push(manageCall2);
788
- manageCalls.push(manageCall3);
789
- }
790
-
791
- const manageCall = this.getManageCall(proofIds, manageCalls);
792
- return { call: manageCall, reward: actualReward, tokenInfo: STRK };
793
- }
794
-
795
- async getRebalanceCall(params: {
796
- isLeg1toLeg2: boolean,
797
- amount: Web3Number
798
- }) {
799
- let callSet1 = this.getVesuModifyPositionCalls({
800
- isLeg1: true,
801
- isDeposit: params.isLeg1toLeg2,
802
- depositAmount: Web3Number.fromWei(0, 0),
803
- debtAmount: params.amount
804
- });
805
-
806
- let callSet2 = this.getVesuModifyPositionCalls({
807
- isLeg1: false,
808
- isDeposit: params.isLeg1toLeg2,
809
- depositAmount: params.amount,
810
- debtAmount: Web3Number.fromWei(0, 0)
811
- });
812
-
813
- if (params.isLeg1toLeg2) {
814
- const manageCall = this.getManageCall([
815
- ...callSet1.map(i => i.step), ...callSet2.map(i => i.step)
816
- ], [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)]);
817
- return manageCall;
818
- } else {
819
- const manageCall = this.getManageCall([
820
- ...callSet2.map(i => i.step), ...callSet1.map(i => i.step)
821
- ], [...callSet2.map(i => i.manageCall), ...callSet1.map(i => i.manageCall)]);
822
- return manageCall;
823
- }
824
- }
825
- }
489
+ // if (isRebalanceNeeded1) {
490
+ // const amount = await this.getLegRebalanceAmount(vesuAdapters[0], leg1HealthFactor, false);
491
+ // const leg2HF = await this.getNewHealthFactor(vesuAdapters[1], amount, true);
492
+ // assert(leg2HF > minHf, `Rebalance Leg1 failed: Leg2 HF after rebalance would be too low: ${leg2HF}`);
493
+ // return [await this.getRebalanceCall({
494
+ // isLeg1toLeg2: false,
495
+ // amount: amount
496
+ // })];
497
+ // } else {
498
+ // const amount = await this.getLegRebalanceAmount(vesuAdapters[1], leg2HealthFactor, true);
499
+ // const leg1HF = await this.getNewHealthFactor(vesuAdapters[0], amount, false);
500
+ // assert(leg1HF > minHf, `Rebalance Leg2 failed: Leg1 HF after rebalance would be too low: ${leg1HF}`);
501
+ // return [await this.getRebalanceCall({
502
+ // isLeg1toLeg2: true,
503
+ // amount: amount
504
+ // })];
505
+ // }
506
+ // }
507
+
508
+ // private async getNewHealthFactor(vesuAdapter: VesuAdapter, newAmount: Web3Number, isWithdraw: boolean) {
509
+ // const {
510
+ // collateralTokenAmount,
511
+ // collateralUSDAmount,
512
+ // collateralPrice,
513
+ // debtTokenAmount,
514
+ // debtUSDAmount,
515
+ // debtPrice,
516
+ // ltv
517
+ // } = await vesuAdapter.getAssetPrices();
518
+
519
+ // if (isWithdraw) {
520
+ // const newHF = ((collateralTokenAmount.toNumber() - newAmount.toNumber()) * collateralPrice * ltv) / debtUSDAmount;
521
+ // logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isDeposit`);
522
+ // return newHF;
523
+ // } else { // is borrow
524
+ // const newHF = (collateralUSDAmount * ltv) / ((debtTokenAmount.toNumber() + newAmount.toNumber()) * debtPrice);
525
+ // logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isRepay`);
526
+ // return newHF;
527
+ // }
528
+ // }
529
+
530
+ // /**
531
+ // *
532
+ // * @param vesuAdapter
533
+ // * @param currentHf
534
+ // * @param isDeposit if true, attempt by adding collateral, else by repaying
535
+ // * @returns
536
+ // */
537
+ // private async getLegRebalanceAmount(vesuAdapter: VesuAdapter, currentHf: number, isDeposit: boolean) {
538
+ // const {
539
+ // collateralTokenAmount,
540
+ // collateralUSDAmount,
541
+ // collateralPrice,
542
+ // debtTokenAmount,
543
+ // debtUSDAmount,
544
+ // debtPrice,
545
+ // ltv
546
+ // } = await vesuAdapter.getAssetPrices();
547
+
548
+ // // debt is zero, nothing to rebalance
549
+ // if(debtTokenAmount.isZero()) {
550
+ // return Web3Number.fromWei(0, 0);
551
+ // }
552
+
553
+ // assert(collateralPrice > 0 && debtPrice > 0, "getRebalanceAmount: Invalid price");
554
+
555
+ // // avoid calculating for too close
556
+ // const targetHF = this.metadata.additionalInfo.targetHealthFactor;
557
+ // if (currentHf > targetHF - 0.01)
558
+ // throw new Error("getLegRebalanceAmount: Current health factor is healthy");
559
+
560
+ // if (isDeposit) {
561
+ // // TargetHF = (collAmount + newAmount) * price * ltv / debtUSD
562
+ // const newAmount = targetHF * debtUSDAmount / (collateralPrice * ltv) - collateralTokenAmount.toNumber();
563
+ // logger.verbose(`${this.getTag()}:: getLegRebalanceAmount: addCollateral, currentHf: ${currentHf}, targetHF: ${targetHF}, collAmount: ${collateralTokenAmount.toString()}, collUSD: ${collateralUSDAmount}, collPrice: ${collateralPrice}, debtAmount: ${debtTokenAmount.toString()}, debtUSD: ${debtUSDAmount}, debtPrice: ${debtPrice}, ltv: ${ltv}, newAmount: ${newAmount}`);
564
+ // return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
565
+ // } else {
566
+ // // TargetHF = collUSD * ltv / (debtAmount - newAmount) * debtPrice
567
+ // const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
568
+ // 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}`);
569
+ // return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
570
+ // }
571
+ // }
572
+
573
+ // async getVesuModifyPositionCall(params: {
574
+ // isDeposit: boolean,
575
+ // leg1DepositAmount: Web3Number
576
+ // }) {
577
+ // const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
578
+ // const leg1LTV = await vesuAdapter1.getLTVConfig(this.config);
579
+ // const leg2LTV = await vesuAdapter2.getLTVConfig(this.config);
580
+ // logger.verbose(`${this.getTag()}: LTVLeg1: ${leg1LTV}`);
581
+ // logger.verbose(`${this.getTag()}: LTVLeg2: ${leg2LTV}`);
582
+
583
+ // const token1Price = await this.pricer.getPrice(vesuAdapter1.config.collateral.symbol);
584
+ // const token2Price = await this.pricer.getPrice(vesuAdapter2.config.collateral.symbol);
585
+ // logger.verbose(`${this.getTag()}: Price${vesuAdapter1.config.collateral.symbol}: ${token1Price.price}`);
586
+ // logger.verbose(`${this.getTag()}: Price${vesuAdapter2.config.collateral.symbol}: ${token2Price.price}`);
587
+
588
+ // const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
589
+
590
+ // const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
591
+ // const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
592
+
593
+ // const borrow2Amount = new Web3Number(
594
+ // params.leg1DepositAmount.multipliedBy(k1.toFixed(6)).dividedBy(k2 - k1).toFixed(6),
595
+ // vesuAdapter2.config.debt.decimals
596
+ // );
597
+ // const borrow1Amount = new Web3Number(
598
+ // borrow2Amount.multipliedBy(k2).toFixed(6),
599
+ // vesuAdapter1.config.debt.decimals
600
+ // );
601
+ // logger.verbose(`${this.getTag()}:: leg1DepositAmount: ${params.leg1DepositAmount.toString()} ${vesuAdapter1.config.collateral.symbol}`);
602
+ // logger.verbose(`${this.getTag()}:: borrow1Amount: ${borrow1Amount.toString()} ${vesuAdapter1.config.debt.symbol}`);
603
+ // logger.verbose(`${this.getTag()}:: borrow2Amount: ${borrow2Amount.toString()} ${vesuAdapter2.config.debt.symbol}`);
604
+
605
+ // let callSet1 = this.getVesuModifyPositionCalls({
606
+ // isLeg1: true,
607
+ // isDeposit: params.isDeposit,
608
+ // depositAmount: params.leg1DepositAmount.plus(borrow2Amount),
609
+ // debtAmount: borrow1Amount
610
+ // });
611
+
612
+ // let callSet2 = this.getVesuModifyPositionCalls({
613
+ // isLeg1: false,
614
+ // isDeposit: params.isDeposit,
615
+ // depositAmount: borrow1Amount,
616
+ // debtAmount: borrow2Amount
617
+ // });
618
+
619
+ // if (!params.isDeposit) {
620
+ // let temp = callSet2;
621
+ // callSet2 = [...callSet1];
622
+ // callSet1 = [...temp];
623
+ // }
624
+ // const allActions = [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)];
625
+ // const flashloanCalldata = CallData.compile([
626
+ // [...callSet1.map(i => i.proofs), ...callSet2.map(i => i.proofs)],
627
+ // allActions.map(i => i.sanitizer.address),
628
+ // allActions.map(i => i.call.contractAddress.address),
629
+ // allActions.map(i => i.call.selector),
630
+ // allActions.map(i => i.call.calldata)
631
+ // ])
632
+
633
+ // // flash loan
634
+ // const STEP1_ID = UNIVERSAL_MANAGE_IDS.FLASH_LOAN;
635
+ // const manage1Info = this.getProofs<FlashloanCallParams>(STEP1_ID);
636
+ // const manageCall1 = manage1Info.callConstructor({
637
+ // amount: borrow2Amount,
638
+ // data: flashloanCalldata.map(i => BigInt(i))
639
+ // })
640
+ // const manageCall = this.getManageCall([UNIVERSAL_MANAGE_IDS.FLASH_LOAN], [manageCall1]);
641
+ // return manageCall;
642
+ // }
643
+
644
+ // async getBringLiquidityCall(params: {
645
+ // amount: Web3Number
646
+ // }) {
647
+ // const manage1Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY);
648
+ // const manageCall1 = manage1Info.callConstructor({
649
+ // amount: params.amount
650
+ // });
651
+ // const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY);
652
+ // const manageCall2 = manage2Info.callConstructor({
653
+ // amount: params.amount
654
+ // });
655
+ // const manageCall = this.getManageCall([UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY, UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY], [manageCall1, manageCall2]);
656
+ // return manageCall;
657
+ // }
658
+
659
+ // async getHarvestCall() {
660
+ // const vesuHarvest = new VesuHarvests(this.config);
661
+ // const harvestInfo = await vesuHarvest.getUnHarvestedRewards(this.metadata.additionalInfo.vaultAllocator);
662
+ // if (harvestInfo.length != 1) {
663
+ // throw new Error(`Expected 1 harvest info, got ${harvestInfo.length}`);
664
+ // }
665
+
666
+ // const amount = harvestInfo[0].claim.amount;
667
+ // const actualReward = harvestInfo[0].actualReward;
668
+ // const proofs = harvestInfo[0].proof;
669
+ // if (actualReward.isZero()) {
670
+ // throw new Error(`Expected non-zero actual reward, got ${harvestInfo[0].actualReward}`);
671
+ // }
672
+
673
+ // const manage1Info = this.getProofs<VesuDefiSpringRewardsCallParams>(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS);
674
+ // const manageCall1 = manage1Info.callConstructor({
675
+ // amount,
676
+ // proofs
677
+ // });
678
+ // const proofIds: string[] = [UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS];
679
+ // const manageCalls: ManageCall[] = [manageCall1];
680
+
681
+ // // swap rewards for underlying
682
+ // const STRK = Global.getDefaultTokens().find(t => t.symbol === 'STRK')!;
683
+ // if (this.asset().symbol != 'STRK') {
684
+ // // approve
685
+ // const manage2Info = this.getProofs<ApproveCallParams>(UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1);
686
+ // const manageCall2 = manage2Info.callConstructor({
687
+ // amount: actualReward
688
+ // });
689
+
690
+ // // swap
691
+ // const avnuModule = new AvnuWrapper();
692
+ // const quote = await avnuModule.getQuotes(
693
+ // STRK.address.address,
694
+ // this.asset().address.address,
695
+ // actualReward.toWei(),
696
+ // this.address.address
697
+ // );
698
+ // const swapInfo = await avnuModule.getSwapInfo(quote, this.address.address, 0, this.address.address);
699
+ // const manage3Info = this.getProofs<AvnuSwapCallParams>(UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS);
700
+ // const manageCall3 = manage3Info.callConstructor({
701
+ // props: swapInfo
702
+ // });
703
+ // proofIds.push(UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1);
704
+ // proofIds.push(UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS);
705
+
706
+ // manageCalls.push(manageCall2);
707
+ // manageCalls.push(manageCall3);
708
+ // }
709
+
710
+ // const manageCall = this.getManageCall(proofIds, manageCalls);
711
+ // return { call: manageCall, reward: actualReward, tokenInfo: STRK };
712
+ // }
713
+
714
+ // async getRebalanceCall(params: {
715
+ // isLeg1toLeg2: boolean,
716
+ // amount: Web3Number
717
+ // }) {
718
+ // let callSet1 = this.getVesuModifyPositionCalls({
719
+ // isLeg1: true,
720
+ // isDeposit: params.isLeg1toLeg2,
721
+ // depositAmount: Web3Number.fromWei(0, 0),
722
+ // debtAmount: params.amount
723
+ // });
724
+
725
+ // let callSet2 = this.getVesuModifyPositionCalls({
726
+ // isLeg1: false,
727
+ // isDeposit: params.isLeg1toLeg2,
728
+ // depositAmount: params.amount,
729
+ // debtAmount: Web3Number.fromWei(0, 0)
730
+ // });
731
+
732
+ // if (params.isLeg1toLeg2) {
733
+ // const manageCall = this.getManageCall([
734
+ // ...callSet1.map(i => i.step), ...callSet2.map(i => i.step)
735
+ // ], [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)]);
736
+ // return manageCall;
737
+ // } else {
738
+ // const manageCall = this.getManageCall([
739
+ // ...callSet2.map(i => i.step), ...callSet1.map(i => i.step)
740
+ // ], [...callSet2.map(i => i.manageCall), ...callSet1.map(i => i.manageCall)]);
741
+ // return manageCall;
742
+ // }
743
+ // }
744
+ // }
826
745
 
827
746
 
828
747
  // useful to map readble names to proofs and calls
@@ -843,414 +762,417 @@ export enum UNIVERSAL_MANAGE_IDS {
843
762
  AVNU_SWAP_REWARDS = 'avnu_swap_rewards'
844
763
  }
845
764
 
846
- export enum UNIVERSAL_ADAPTERS {
847
- COMMON = 'common_adapter',
848
- VESU_LEG1 = 'vesu_leg1_adapter',
849
- VESU_LEG2 = 'vesu_leg2_adapter'
850
- }
851
-
852
- function getLooperSettings(
853
- token1Symbol: string,
854
- token2Symbol: string,
855
- vaultSettings: UniversalStrategySettings,
856
- pool1: ContractAddr,
857
- pool2: ContractAddr,
858
- ) {
859
- const USDCToken = Global.getDefaultTokens().find(token => token.symbol === token1Symbol)!;
860
- const ETHToken = Global.getDefaultTokens().find(token => token.symbol === token2Symbol)!;
861
-
862
- const commonAdapter = new CommonAdapter({
863
- manager: vaultSettings.manager,
864
- asset: USDCToken.address,
865
- id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
866
- vaultAddress: vaultSettings.vaultAddress,
867
- vaultAllocator: vaultSettings.vaultAllocator,
868
- })
869
- const vesuAdapterUSDCETH = new VesuAdapter({
870
- poolId: pool1,
871
- collateral: USDCToken,
872
- debt: ETHToken,
873
- vaultAllocator: vaultSettings.vaultAllocator,
874
- id: UNIVERSAL_MANAGE_IDS.VESU_LEG1
875
- })
876
- const vesuAdapterETHUSDC = new VesuAdapter({
877
- poolId: pool2,
878
- collateral: ETHToken,
879
- debt: USDCToken,
880
- vaultAllocator: vaultSettings.vaultAllocator,
881
- id: UNIVERSAL_MANAGE_IDS.VESU_LEG2
882
- })
883
- vaultSettings.adapters.push(...[{
884
- id: UNIVERSAL_ADAPTERS.COMMON,
885
- adapter: commonAdapter
886
- }, {
887
- id: UNIVERSAL_ADAPTERS.VESU_LEG1,
888
- adapter: vesuAdapterUSDCETH
889
- }, {
890
- id: UNIVERSAL_ADAPTERS.VESU_LEG2,
891
- adapter: vesuAdapterETHUSDC
892
- }])
893
-
894
- // vesu looping
895
- vaultSettings.leafAdapters.push(commonAdapter.getFlashloanAdapter.bind(commonAdapter));
896
- vaultSettings.leafAdapters.push(vesuAdapterUSDCETH.getModifyPosition.bind(vesuAdapterUSDCETH));
897
- vaultSettings.leafAdapters.push(vesuAdapterETHUSDC.getModifyPosition.bind(vesuAdapterETHUSDC));
898
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1).bind(commonAdapter));
899
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(ETHToken.address, VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2).bind(commonAdapter));
765
+ // export enum UNIVERSAL_ADAPTERS {
766
+ // COMMON = 'common_adapter',
767
+ // VESU_LEG1 = 'vesu_leg1_adapter',
768
+ // VESU_LEG2 = 'vesu_leg2_adapter'
769
+ // }
770
+
771
+ // function getLooperSettings(
772
+ // token1Symbol: string,
773
+ // token2Symbol: string,
774
+ // vaultSettings: UniversalStrategySettings,
775
+ // pool1: ContractAddr,
776
+ // pool2: ContractAddr,
777
+ // ) {
778
+ // const USDCToken = Global.getDefaultTokens().find(token => token.symbol === token1Symbol)!;
779
+ // const ETHToken = Global.getDefaultTokens().find(token => token.symbol === token2Symbol)!;
780
+
781
+ // const commonAdapter = new CommonAdapter({
782
+ // manager: vaultSettings.manager,
783
+ // asset: USDCToken.address,
784
+ // id: UNIVERSAL_MANAGE_IDS.FLASH_LOAN,
785
+ // vaultAddress: vaultSettings.vaultAddress,
786
+ // vaultAllocator: vaultSettings.vaultAllocator,
787
+ // })
788
+ // const vesuAdapterUSDCETH = new VesuAdapter({
789
+ // poolId: pool1,
790
+ // collateral: USDCToken,
791
+ // debt: ETHToken,
792
+ // vaultAllocator: vaultSettings.vaultAllocator,
793
+ // id: UNIVERSAL_MANAGE_IDS.VESU_LEG1
794
+ // })
795
+ // const vesuAdapterETHUSDC = new VesuAdapter({
796
+ // poolId: pool2,
797
+ // collateral: ETHToken,
798
+ // debt: USDCToken,
799
+ // vaultAllocator: vaultSettings.vaultAllocator,
800
+ // id: UNIVERSAL_MANAGE_IDS.VESU_LEG2
801
+ // })
802
+ // vaultSettings.adapters.push(...[{
803
+ // id: UNIVERSAL_ADAPTERS.COMMON,
804
+ // adapter: commonAdapter
805
+ // }, {
806
+ // id: UNIVERSAL_ADAPTERS.VESU_LEG1,
807
+ // adapter: vesuAdapterUSDCETH
808
+ // }, {
809
+ // id: UNIVERSAL_ADAPTERS.VESU_LEG2,
810
+ // adapter: vesuAdapterETHUSDC
811
+ // }])
812
+
813
+ // // vesu looping
814
+ // vaultSettings.leafAdapters.push(commonAdapter.getFlashloanAdapter.bind(commonAdapter));
815
+ // vaultSettings.leafAdapters.push(vesuAdapterUSDCETH.getModifyPosition.bind(vesuAdapterUSDCETH));
816
+ // vaultSettings.leafAdapters.push(vesuAdapterETHUSDC.getModifyPosition.bind(vesuAdapterETHUSDC));
817
+ // vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN1).bind(commonAdapter));
818
+ // vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(ETHToken.address, VESU_SINGLETON, UNIVERSAL_MANAGE_IDS.APPROVE_TOKEN2).bind(commonAdapter));
900
819
 
901
- // to bridge liquidity back to vault (used by bring_liquidity)
902
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
903
- vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
820
+ // // to bridge liquidity back to vault (used by bring_liquidity)
821
+ // vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(USDCToken.address, vaultSettings.vaultAddress, UNIVERSAL_MANAGE_IDS.APPROVE_BRING_LIQUIDITY).bind(commonAdapter));
822
+ // vaultSettings.leafAdapters.push(commonAdapter.getBringLiquidityAdapter(UNIVERSAL_MANAGE_IDS.BRING_LIQUIDITY).bind(commonAdapter));
904
823
 
905
- // claim rewards
906
- vaultSettings.leafAdapters.push(vesuAdapterUSDCETH.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterUSDCETH));
907
-
908
- // avnu swap
909
- const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
910
- vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_MIDDLEWARE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
911
- vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, USDCToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS, true).bind(commonAdapter));
912
- return vaultSettings;
913
- }
914
-
915
- const _riskFactor: RiskFactor[] = [
916
- { type: RiskType.SMART_CONTRACT_RISK, value: 0.5, weight: 25, reason: "Audited by Zellic" },
917
- { type: RiskType.LIQUIDATION_RISK, value: 1.5, weight: 50, reason: "Liquidation risk is mitigated by stable price feed on Starknet" },
918
- { type: RiskType.TECHNICAL_RISK, value: 1, weight: 50, reason: "Technical failures like risk monitoring failures" }
919
- ];
920
-
921
- const usdcVaultSettings: UniversalStrategySettings = {
922
- vaultAddress: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
923
- manager: ContractAddr.from('0xf41a2b1f498a7f9629db0b8519259e66e964260a23d20003f3e42bb1997a07'),
924
- vaultAllocator: ContractAddr.from('0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba'),
925
- redeemRequestNFT: ContractAddr.from('0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda'),
926
- aumOracle: ContractAddr.from("0x6faf45ed185dec13ef723c9ead4266cab98d06f2cb237e331b1fa5c2aa79afe"),
927
- leafAdapters: [],
928
- adapters: [],
929
- targetHealthFactor: 1.25,
930
- minHealthFactor: 1.15
931
- }
932
-
933
- const wbtcVaultSettings: UniversalStrategySettings = {
934
- vaultAddress: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
935
- manager: ContractAddr.from('0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34'),
936
- vaultAllocator: ContractAddr.from('0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735'),
937
- redeemRequestNFT: ContractAddr.from('0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2'),
938
- aumOracle: ContractAddr.from("0x2edf4edbed3f839e7f07dcd913e92299898ff4cf0ba532f8c572c66c5b331b2"),
939
- leafAdapters: [],
940
- adapters: [],
941
- targetHealthFactor: 1.20,
942
- minHealthFactor: 1.15
943
- }
944
-
945
- const ethVaultSettings: UniversalStrategySettings = {
946
- vaultAddress: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
947
- manager: ContractAddr.from('0x494888b37206616bd09d759dcda61e5118470b9aa7f58fb84f21c778a7b8f97'),
948
- vaultAllocator: ContractAddr.from('0x4acc0ad6bea58cb578d60ff7c31f06f44369a7a9a7bbfffe4701f143e427bd'),
949
- redeemRequestNFT: ContractAddr.from('0x2e6cd71e5060a254d4db00655e420db7bf89da7755bb0d5f922e2f00c76ac49'),
950
- aumOracle: ContractAddr.from("0x4b747f2e75c057bed9aa2ce46fbdc2159dc684c15bd32d4f95983a6ecf39a05"),
951
- leafAdapters: [],
952
- adapters: [],
953
- targetHealthFactor: 1.25,
954
- minHealthFactor: 1.21
955
- }
956
-
957
- const strkVaultSettings: UniversalStrategySettings = {
958
- vaultAddress: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
959
- manager: ContractAddr.from('0xcc6a5153ca56293405506eb20826a379d982cd738008ef7e808454d318fb81'),
960
- vaultAllocator: ContractAddr.from('0xf29d2f82e896c0ed74c9eff220af34ac148e8b99846d1ace9fbb02c9191d01'),
961
- redeemRequestNFT: ContractAddr.from('0x46902423bd632c428376b84fcee9cac5dbe016214e93a8103bcbde6e1de656b'),
962
- aumOracle: ContractAddr.from("0x6d7dbfad4bb51715da211468389a623da00c0625f8f6efbea822ee5ac5231f4"),
963
- leafAdapters: [],
964
- adapters: [],
965
- targetHealthFactor: 1.20,
966
- minHealthFactor: 1.15
967
- }
968
-
969
- const usdtVaultSettings: UniversalStrategySettings = {
970
- vaultAddress: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
971
- manager: ContractAddr.from('0x39bb9843503799b552b7ed84b31c06e4ff10c0537edcddfbf01fe944b864029'),
972
- vaultAllocator: ContractAddr.from('0x56437d18c43727ac971f6c7086031cad7d9d6ccb340f4f3785a74cc791c931a'),
973
- redeemRequestNFT: ContractAddr.from('0x5af0c2a657eaa8e23ed78e855dac0c51e4f69e2cf91a18c472041a1f75bb41f'),
974
- aumOracle: ContractAddr.from("0x7018f8040c8066a4ab929e6760ae52dd43b6a3a289172f514750a61fcc565cc"),
975
- leafAdapters: [],
976
- adapters: [],
977
- targetHealthFactor: 1.25,
978
- minHealthFactor: 1.15
979
- }
980
-
981
- type AllowedSources = 'vesu' | 'endur' | 'extended';
982
- export default function MetaVaultDescription(allowedSources: AllowedSources[]) {
983
- const logos: any = {
984
- vesu: Protocols.VESU.logo,
985
- endur: Protocols.ENDUR.logo,
986
- extended: Protocols.EXTENDED.logo,
987
- ekubo: "https://dummyimage.com/64x64/ffffff/000000&text=K",
988
- };
989
- const _sources = [
990
- { key: "vesu", name: "Vesu", status: "Live", description: "Integrated liquidity venue used for automated routing to capture the best available yield." },
991
- { key: "endur", name: "Endur", status: "Coming soon", description: "Planned integration to tap into STRK staking–backed yields via our LST pipeline." },
992
- { key: "extended", name: "Extended", status: "Coming soon", description: "Expanding coverage to additional money markets and vaults across the ecosystem." },
993
- // { key: "ekubo", name: "Ekubo", status: "Coming soon", description: "Concentrated liquidity strategies targeted for optimized fee APR harvesting." },
994
- ];
995
- const sources = _sources.filter(s => allowedSources.includes(s.key as any));
996
-
997
- const containerStyle = {
998
- maxWidth: "800px",
999
- margin: "0 auto",
1000
- backgroundColor: "#111",
1001
- color: "#eee",
1002
- fontFamily: "Arial, sans-serif",
1003
- borderRadius: "12px",
1004
- };
1005
-
1006
- const cardStyle = {
1007
- border: "1px solid #333",
1008
- borderRadius: "10px",
1009
- padding: "12px",
1010
- marginBottom: "12px",
1011
- backgroundColor: "#1a1a1a",
1012
- };
1013
-
1014
- const logoStyle = {
1015
- width: "24px",
1016
- height: "24px",
1017
- borderRadius: "8px",
1018
- border: "1px solid #444",
1019
- backgroundColor: "#222",
1020
- };
1021
-
1022
- return (
1023
- <div style={containerStyle}>
1024
- <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Meta Vault — Automated Yield Router</h1>
1025
- <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
1026
- This Evergreen vault is a tokenized Meta Vault, auto-compounding strategy that continuously allocates your deposited
1027
- asset to the best available yield source in the ecosystem. Depositors receive vault shares that
1028
- represent a proportional claim on the underlying assets and accrued yield. Allocation shifts are
1029
- handled programmatically based on on-chain signals and risk filters, minimizing idle capital and
1030
- maximizing net APY.
1031
- </p>
1032
-
1033
- <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
1034
- <p style={{ fontSize: "13px", color: "#ccc" }}>
1035
- <strong>Withdrawals:</strong> Requests can take up to <strong>1-2 hours</strong> to process as the vault unwinds and settles routing.
1036
- </p>
1037
- </div>
1038
-
1039
- <h2 style={{ fontSize: "18px", marginBottom: "10px" }}>Supported Yield Sources</h2>
1040
- {sources.map((s) => (
1041
- <div key={s.key} style={cardStyle}>
1042
- <div style={{ display: "flex", gap: "10px", alignItems: "flex-start" }}>
1043
- <img src={logos[s.key]} alt={`${s.name} logo`} style={logoStyle} />
1044
- <div style={{ flex: 1 }}>
1045
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
1046
- <h3 style={{ fontSize: "15px", margin: 0 }}>{s.name}</h3>
1047
- <StatusBadge status={s.status} />
1048
- </div>
1049
- {/* <p style={{ fontSize: "13px", color: "#ccc", marginTop: "4px" }}>{s.description}</p> */}
1050
- </div>
1051
- </div>
1052
- </div>
1053
- ))}
1054
- </div>
1055
- );
1056
- }
1057
-
1058
- function StatusBadge({ status }: { status: string }) {
1059
- const isSoon = String(status).toLowerCase() !== "live";
1060
- const badgeStyle = {
1061
- fontSize: "12px",
1062
- padding: "2px 6px",
1063
- borderRadius: "12px",
1064
- border: "1px solid",
1065
- color: isSoon ? "rgb(196 196 195)" : "#6aff7d",
1066
- borderColor: isSoon ? "#484848" : "#6aff7d",
1067
- backgroundColor: isSoon ? "#424242" : "#002b1a",
1068
- };
1069
- return <span style={badgeStyle}>{status}</span>;
1070
- }
1071
-
1072
- function getDescription(tokenSymbol: string, allowedSources: AllowedSources[]) {
1073
- return MetaVaultDescription(allowedSources);
1074
- }
1075
-
1076
- function getFAQs(): FAQ[] {
1077
- return [
1078
- {
1079
- question: "What is the Meta Vault?",
1080
- answer:
1081
- "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.",
1082
- },
1083
- {
1084
- question: "How does yield allocation work?",
1085
- answer:
1086
- "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.",
1087
- },
1088
- {
1089
- question: "Which yield sources are supported?",
1090
- answer: (
1091
- <span>
1092
- Currently, <strong>Vesu</strong> is live. Future integrations may include{" "}
1093
- <strong>Endur</strong>, <strong>Extended</strong>, and{" "}
1094
- <strong>Ekubo</strong> (all coming soon).
1095
- </span>
1096
- ),
1097
- },
1098
- {
1099
- question: "What do I receive when I deposit?",
1100
- answer:
1101
- "Depositors receive vault tokens representing their proportional share of the vault. These tokens entitle holders to both the principal and accrued yield.",
1102
- },
1103
- {
1104
- question: "How long do withdrawals take?",
1105
- answer:
1106
- "Withdrawals may take up to 1-2 hours to process, as the vault unwinds and settles liquidity routing across integrated protocols.",
1107
- },
1108
- {
1109
- question: "Is the Meta Vault non-custodial?",
1110
- answer:
1111
- "Yes. The Meta Vault operates entirely on-chain. Users always maintain control of their vault tokens, and the strategy is fully transparent.",
1112
- },
1113
- {
1114
- question: "How is risk managed?",
1115
- answer:
1116
- "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.",
1117
- },
1118
- {
1119
- question: "Are there any fees?",
1120
- answer:
1121
- "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.",
1122
- },
1123
- ];
1124
- }
1125
-
1126
- export function getContractDetails(settings: UniversalStrategySettings): {address: ContractAddr, name: string}[] {
1127
- return [
824
+ // // claim rewards
825
+ // vaultSettings.leafAdapters.push(vesuAdapterUSDCETH.getDefispringRewardsAdapter(UNIVERSAL_MANAGE_IDS.DEFISPRING_REWARDS).bind(vesuAdapterUSDCETH));
826
+
827
+ // // avnu swap
828
+ // const STRKToken = Global.getDefaultTokens().find(token => token.symbol === 'STRK')!;
829
+ // vaultSettings.leafAdapters.push(commonAdapter.getApproveAdapter(STRKToken.address, AVNU_MIDDLEWARE, UNIVERSAL_MANAGE_IDS.APPROVE_SWAP_TOKEN1).bind(commonAdapter));
830
+ // vaultSettings.leafAdapters.push(commonAdapter.getAvnuAdapter(STRKToken.address, USDCToken.address, UNIVERSAL_MANAGE_IDS.AVNU_SWAP_REWARDS, true).bind(commonAdapter));
831
+ // return vaultSettings;
832
+ // }
833
+
834
+ // const _riskFactor: RiskFactor[] = [
835
+ // { type: RiskType.SMART_CONTRACT_RISK, value: 0.5, weight: 25, reason: "Audited by Zellic" },
836
+ // { type: RiskType.LIQUIDATION_RISK, value: 1.5, weight: 50, reason: "Liquidation risk is mitigated by stable price feed on Starknet" },
837
+ // { type: RiskType.TECHNICAL_RISK, value: 1, weight: 50, reason: "Technical failures like risk monitoring failures" }
838
+ // ];
839
+
840
+ // const usdcVaultSettings: UniversalStrategySettings = {
841
+ // vaultAddress: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
842
+ // manager: ContractAddr.from('0xf41a2b1f498a7f9629db0b8519259e66e964260a23d20003f3e42bb1997a07'),
843
+ // vaultAllocator: ContractAddr.from('0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba'),
844
+ // redeemRequestNFT: ContractAddr.from('0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda'),
845
+ // aumOracle: ContractAddr.from("0x6faf45ed185dec13ef723c9ead4266cab98d06f2cb237e331b1fa5c2aa79afe"),
846
+ // leafAdapters: [],
847
+ // adapters: [],
848
+ // targetHealthFactor: 1.3,
849
+ // minHealthFactor: 1.25
850
+ // }
851
+
852
+ // const wbtcVaultSettings: UniversalStrategySettings = {
853
+ // vaultAddress: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
854
+ // manager: ContractAddr.from('0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34'),
855
+ // vaultAllocator: ContractAddr.from('0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735'),
856
+ // redeemRequestNFT: ContractAddr.from('0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2'),
857
+ // aumOracle: ContractAddr.from("0x2edf4edbed3f839e7f07dcd913e92299898ff4cf0ba532f8c572c66c5b331b2"),
858
+ // leafAdapters: [],
859
+ // adapters: [],
860
+ // targetHealthFactor: 1.3,
861
+ // minHealthFactor: 1.25
862
+ // }
863
+
864
+ // const ethVaultSettings: UniversalStrategySettings = {
865
+ // vaultAddress: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
866
+ // manager: ContractAddr.from('0x494888b37206616bd09d759dcda61e5118470b9aa7f58fb84f21c778a7b8f97'),
867
+ // vaultAllocator: ContractAddr.from('0x4acc0ad6bea58cb578d60ff7c31f06f44369a7a9a7bbfffe4701f143e427bd'),
868
+ // redeemRequestNFT: ContractAddr.from('0x2e6cd71e5060a254d4db00655e420db7bf89da7755bb0d5f922e2f00c76ac49'),
869
+ // aumOracle: ContractAddr.from("0x4b747f2e75c057bed9aa2ce46fbdc2159dc684c15bd32d4f95983a6ecf39a05"),
870
+ // leafAdapters: [],
871
+ // adapters: [],
872
+ // targetHealthFactor: 1.3,
873
+ // minHealthFactor: 1.25
874
+ // }
875
+
876
+ // const strkVaultSettings: UniversalStrategySettings = {
877
+ // vaultAddress: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
878
+ // manager: ContractAddr.from('0xcc6a5153ca56293405506eb20826a379d982cd738008ef7e808454d318fb81'),
879
+ // vaultAllocator: ContractAddr.from('0xf29d2f82e896c0ed74c9eff220af34ac148e8b99846d1ace9fbb02c9191d01'),
880
+ // redeemRequestNFT: ContractAddr.from('0x46902423bd632c428376b84fcee9cac5dbe016214e93a8103bcbde6e1de656b'),
881
+ // aumOracle: ContractAddr.from("0x6d7dbfad4bb51715da211468389a623da00c0625f8f6efbea822ee5ac5231f4"),
882
+ // leafAdapters: [],
883
+ // adapters: [],
884
+ // targetHealthFactor: 1.3,
885
+ // minHealthFactor: 1.25
886
+ // }
887
+
888
+ // const usdtVaultSettings: UniversalStrategySettings = {
889
+ // vaultAddress: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
890
+ // manager: ContractAddr.from('0x39bb9843503799b552b7ed84b31c06e4ff10c0537edcddfbf01fe944b864029'),
891
+ // vaultAllocator: ContractAddr.from('0x56437d18c43727ac971f6c7086031cad7d9d6ccb340f4f3785a74cc791c931a'),
892
+ // redeemRequestNFT: ContractAddr.from('0x5af0c2a657eaa8e23ed78e855dac0c51e4f69e2cf91a18c472041a1f75bb41f'),
893
+ // aumOracle: ContractAddr.from("0x7018f8040c8066a4ab929e6760ae52dd43b6a3a289172f514750a61fcc565cc"),
894
+ // leafAdapters: [],
895
+ // adapters: [],
896
+ // targetHealthFactor: 1.3,
897
+ // minHealthFactor: 1.25
898
+ // }
899
+
900
+ // type AllowedSources = 'vesu' | 'endur' | 'extended';
901
+ // export default function MetaVaultDescription(allowedSources: AllowedSources[]) {
902
+ // const logos: any = {
903
+ // vesu: Protocols.VESU.logo,
904
+ // endur: Protocols.ENDUR.logo,
905
+ // extended: Protocols.EXTENDED.logo,
906
+ // ekubo: "https://dummyimage.com/64x64/ffffff/000000&text=K",
907
+ // };
908
+ // const _sources = [
909
+ // { key: "vesu", name: "Vesu", status: "Live", description: "Integrated liquidity venue used for automated routing to capture the best available yield." },
910
+ // { key: "endur", name: "Endur", status: "Coming soon", description: "Planned integration to tap into STRK staking–backed yields via our LST pipeline." },
911
+ // { key: "extended", name: "Extended", status: "Coming soon", description: "Expanding coverage to additional money markets and vaults across the ecosystem." },
912
+ // // { key: "ekubo", name: "Ekubo", status: "Coming soon", description: "Concentrated liquidity strategies targeted for optimized fee APR harvesting." },
913
+ // ];
914
+ // const sources = _sources.filter(s => allowedSources.includes(s.key as any));
915
+
916
+ // const containerStyle = {
917
+ // maxWidth: "800px",
918
+ // margin: "0 auto",
919
+ // backgroundColor: "#111",
920
+ // color: "#eee",
921
+ // fontFamily: "Arial, sans-serif",
922
+ // borderRadius: "12px",
923
+ // };
924
+
925
+ // const cardStyle = {
926
+ // border: "1px solid #333",
927
+ // borderRadius: "10px",
928
+ // padding: "12px",
929
+ // marginBottom: "12px",
930
+ // backgroundColor: "#1a1a1a",
931
+ // };
932
+
933
+ // const logoStyle = {
934
+ // width: "24px",
935
+ // height: "24px",
936
+ // borderRadius: "8px",
937
+ // border: "1px solid #444",
938
+ // backgroundColor: "#222",
939
+ // };
940
+
941
+ // return (
942
+ // <div style={containerStyle}>
943
+ // <h1 style={{ fontSize: "18px", marginBottom: "10px" }}>Meta Vault — Automated Yield Router</h1>
944
+ // <p style={{ fontSize: "14px", lineHeight: "1.5", marginBottom: "16px" }}>
945
+ // This Evergreen vault is a tokenized Meta Vault, auto-compounding strategy that continuously allocates your deposited
946
+ // asset to the best available yield source in the ecosystem. Depositors receive vault shares that
947
+ // represent a proportional claim on the underlying assets and accrued yield. Allocation shifts are
948
+ // handled programmatically based on on-chain signals and risk filters, minimizing idle capital and
949
+ // maximizing net APY.
950
+ // </p>
951
+
952
+ // <div style={{ backgroundColor: "#222", padding: "10px", borderRadius: "8px", marginBottom: "20px", border: "1px solid #444" }}>
953
+ // <p style={{ fontSize: "13px", color: "#ccc" }}>
954
+ // <strong>Withdrawals:</strong> Requests can take up to <strong>1-2 hours</strong> to process as the vault unwinds and settles routing.
955
+ // </p>
956
+ // </div>
957
+
958
+ // <h2 style={{ fontSize: "18px", marginBottom: "10px" }}>Supported Yield Sources</h2>
959
+ // {sources.map((s) => (
960
+ // <div key={s.key} style={cardStyle}>
961
+ // <div style={{ display: "flex", gap: "10px", alignItems: "flex-start" }}>
962
+ // <img src={logos[s.key]} alt={`${s.name} logo`} style={logoStyle} />
963
+ // <div style={{ flex: 1 }}>
964
+ // <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
965
+ // <h3 style={{ fontSize: "15px", margin: 0 }}>{s.name}</h3>
966
+ // <StatusBadge status={s.status} />
967
+ // </div>
968
+ // {/* <p style={{ fontSize: "13px", color: "#ccc", marginTop: "4px" }}>{s.description}</p> */}
969
+ // </div>
970
+ // </div>
971
+ // </div>
972
+ // ))}
973
+ // </div>
974
+ // );
975
+ // }
976
+
977
+ // function StatusBadge({ status }: { status: string }) {
978
+ // const isSoon = String(status).toLowerCase() !== "live";
979
+ // const badgeStyle = {
980
+ // fontSize: "12px",
981
+ // padding: "2px 6px",
982
+ // borderRadius: "12px",
983
+ // border: "1px solid",
984
+ // color: isSoon ? "rgb(196 196 195)" : "#6aff7d",
985
+ // borderColor: isSoon ? "#484848" : "#6aff7d",
986
+ // backgroundColor: isSoon ? "#424242" : "#002b1a",
987
+ // };
988
+ // return <span style={badgeStyle}>{status}</span>;
989
+ // }
990
+
991
+ // function getDescription(tokenSymbol: string, allowedSources: AllowedSources[]) {
992
+ // return MetaVaultDescription(allowedSources);
993
+ // }
994
+
995
+ // function getFAQs(): FAQ[] {
996
+ // return [
997
+ // {
998
+ // question: "What is the Meta Vault?",
999
+ // answer:
1000
+ // "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.",
1001
+ // },
1002
+ // {
1003
+ // question: "How does yield allocation work?",
1004
+ // answer:
1005
+ // "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.",
1006
+ // },
1007
+ // {
1008
+ // question: "Which yield sources are supported?",
1009
+ // answer: (
1010
+ // <span>
1011
+ // Currently, <strong>Vesu</strong> is live. Future integrations may include{" "}
1012
+ // <strong>Endur</strong>, <strong>Extended</strong>, and{" "}
1013
+ // <strong>Ekubo</strong> (all coming soon).
1014
+ // </span>
1015
+ // ),
1016
+ // },
1017
+ // {
1018
+ // question: "What do I receive when I deposit?",
1019
+ // answer:
1020
+ // "Depositors receive vault tokens representing their proportional share of the vault. These tokens entitle holders to both the principal and accrued yield.",
1021
+ // },
1022
+ // {
1023
+ // question: "How long do withdrawals take?",
1024
+ // answer:
1025
+ // "Withdrawals may take up to 1-2 hours to process, as the vault unwinds and settles liquidity routing across integrated protocols.",
1026
+ // },
1027
+ // {
1028
+ // question: "Is the Meta Vault non-custodial?",
1029
+ // answer:
1030
+ // "Yes. The Meta Vault operates entirely on-chain. Users always maintain control of their vault tokens, and the strategy is fully transparent.",
1031
+ // },
1032
+ // {
1033
+ // question: "How is risk managed?",
1034
+ // answer:
1035
+ // "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.",
1036
+ // },
1037
+ // {
1038
+ // question: "Are there any fees?",
1039
+ // answer:
1040
+ // "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.",
1041
+ // },
1042
+ // ];
1043
+ // }
1044
+
1045
+ export function getContractDetails(settings: UniversalStrategySettings & { aumOracle?: ContractAddr }): {address: ContractAddr, name: string}[] {
1046
+ const contracts = [
1128
1047
  { address: settings.vaultAddress, name: "Vault" },
1129
1048
  { address: settings.manager, name: "Vault Manager" },
1130
1049
  { address: settings.vaultAllocator, name: "Vault Allocator" },
1131
1050
  { address: settings.redeemRequestNFT, name: "Redeem Request NFT" },
1132
- // { address: settings.aumOracle, name: "AUM Oracle" },
1133
1051
  ];
1052
+ if (settings.aumOracle) {
1053
+ contracts.push({ address: settings.aumOracle, name: "AUM Oracle" });
1054
+ }
1055
+ return contracts;
1134
1056
  }
1135
1057
 
1136
- const investmentSteps: string[] = [
1137
- "Deposit funds into the vault",
1138
- "Vault manager allocates funds to optimal yield sources",
1139
- "Vault manager reports asset under management (AUM) regularly to the vault",
1140
- "Request withdrawal and vault manager processes it in 1-2 hours"
1141
- ]
1142
-
1143
- const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
1144
- export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
1145
- [
1146
- {
1147
- name: "USDC.e Evergreen",
1148
- description: getDescription('USDC.e', ['vesu', 'extended']),
1149
- address: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
1150
- launchBlock: 0,
1151
- type: 'ERC4626',
1152
- depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDC.e')!],
1153
- additionalInfo: getLooperSettings('USDC.e', 'ETH', usdcVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1154
- risk: {
1155
- riskFactor: _riskFactor,
1156
- netRisk:
1157
- _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1158
- _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1159
- notARisks: getNoRiskTags(_riskFactor)
1160
- },
1161
- auditUrl: AUDIT_URL,
1162
- protocols: [Protocols.VESU],
1163
- maxTVL: Web3Number.fromWei(0, 6),
1164
- contractDetails: getContractDetails(usdcVaultSettings),
1165
- faqs: getFAQs(),
1166
- investmentSteps: investmentSteps,
1167
- },
1168
- {
1169
- name: "WBTC Evergreen",
1170
- description: getDescription('WBTC', ['vesu', 'endur', 'extended']),
1171
- address: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
1172
- launchBlock: 0,
1173
- type: 'ERC4626',
1174
- depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!],
1175
- additionalInfo: getLooperSettings('WBTC', 'ETH', wbtcVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1176
- risk: {
1177
- riskFactor: _riskFactor,
1178
- netRisk:
1179
- _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1180
- _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1181
- notARisks: getNoRiskTags(_riskFactor)
1182
- },
1183
- protocols: [Protocols.VESU],
1184
- maxTVL: Web3Number.fromWei(0, 8),
1185
- contractDetails: getContractDetails(wbtcVaultSettings),
1186
- faqs: getFAQs(),
1187
- investmentSteps: investmentSteps,
1188
- auditUrl: AUDIT_URL,
1189
- },
1190
- {
1191
- name: "ETH Evergreen",
1192
- description: getDescription('ETH', ['vesu', 'extended']),
1193
- address: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
1194
- launchBlock: 0,
1195
- type: 'ERC4626',
1196
- depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'ETH')!],
1197
- additionalInfo: getLooperSettings('ETH', 'WBTC', ethVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1198
- risk: {
1199
- riskFactor: _riskFactor,
1200
- netRisk:
1201
- _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1202
- _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1203
- notARisks: getNoRiskTags(_riskFactor)
1204
- },
1205
- protocols: [Protocols.VESU],
1206
- maxTVL: Web3Number.fromWei(0, 18),
1207
- contractDetails: getContractDetails(ethVaultSettings),
1208
- faqs: getFAQs(),
1209
- investmentSteps: investmentSteps,
1210
- auditUrl: AUDIT_URL,
1211
- },
1212
- {
1213
- name: "STRK Evergreen",
1214
- description: getDescription('STRK', ['vesu', 'endur', 'extended']),
1215
- address: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
1216
- launchBlock: 0,
1217
- type: 'ERC4626',
1218
- depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'STRK')!],
1219
- additionalInfo: getLooperSettings('STRK', 'ETH', strkVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1220
- risk: {
1221
- riskFactor: _riskFactor,
1222
- netRisk:
1223
- _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1224
- _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1225
- notARisks: getNoRiskTags(_riskFactor)
1226
- },
1227
- protocols: [Protocols.VESU],
1228
- maxTVL: Web3Number.fromWei(0, 18),
1229
- contractDetails: getContractDetails(strkVaultSettings),
1230
- faqs: getFAQs(),
1231
- investmentSteps: investmentSteps,
1232
- auditUrl: AUDIT_URL,
1233
- },
1234
- {
1235
- name: "USDT Evergreen",
1236
- description: getDescription('USDT', ['vesu']),
1237
- address: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
1238
- launchBlock: 0,
1239
- type: 'ERC4626',
1240
- depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDT')!],
1241
- additionalInfo: getLooperSettings('USDT', 'ETH', usdtVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1242
- risk: {
1243
- riskFactor: _riskFactor,
1244
- netRisk:
1245
- _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1246
- _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1247
- notARisks: getNoRiskTags(_riskFactor)
1248
- },
1249
- protocols: [Protocols.VESU],
1250
- maxTVL: Web3Number.fromWei(0, 6),
1251
- contractDetails: getContractDetails(usdtVaultSettings),
1252
- faqs: getFAQs(),
1253
- investmentSteps: investmentSteps,
1254
- auditUrl: AUDIT_URL,
1255
- }
1256
- ]
1058
+ // const investmentSteps: string[] = [
1059
+ // "Deposit funds into the vault",
1060
+ // "Vault manager allocates funds to optimal yield sources",
1061
+ // "Vault manager reports asset under management (AUM) regularly to the vault",
1062
+ // "Request withdrawal and vault manager processes it in 1-2 hours"
1063
+ // ]
1064
+
1065
+ // const AUDIT_URL = 'https://docs.troves.fi/p/security#starknet-vault-kit'
1066
+ // export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
1067
+ // [
1068
+ // {
1069
+ // name: "USDC Evergreen",
1070
+ // description: getDescription('USDC', ['vesu', 'extended']),
1071
+ // address: ContractAddr.from('0x7e6498cf6a1bfc7e6fc89f1831865e2dacb9756def4ec4b031a9138788a3b5e'),
1072
+ // launchBlock: 0,
1073
+ // type: 'ERC4626',
1074
+ // depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDC')!],
1075
+ // additionalInfo: getLooperSettings('USDC', 'ETH', usdcVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1076
+ // risk: {
1077
+ // riskFactor: _riskFactor,
1078
+ // netRisk:
1079
+ // _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1080
+ // _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1081
+ // notARisks: getNoRiskTags(_riskFactor)
1082
+ // },
1083
+ // auditUrl: AUDIT_URL,
1084
+ // protocols: [Protocols.VESU],
1085
+ // maxTVL: Web3Number.fromWei(0, 6),
1086
+ // contractDetails: getContractDetails(usdcVaultSettings),
1087
+ // faqs: getFAQs(),
1088
+ // investmentSteps: investmentSteps,
1089
+ // },
1090
+ // {
1091
+ // name: "WBTC Evergreen",
1092
+ // description: getDescription('WBTC', ['vesu', 'endur', 'extended']),
1093
+ // address: ContractAddr.from('0x5a4c1651b913aa2ea7afd9024911603152a19058624c3e425405370d62bf80c'),
1094
+ // launchBlock: 0,
1095
+ // type: 'ERC4626',
1096
+ // depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'WBTC')!],
1097
+ // additionalInfo: getLooperSettings('WBTC', 'ETH', wbtcVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1098
+ // risk: {
1099
+ // riskFactor: _riskFactor,
1100
+ // netRisk:
1101
+ // _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1102
+ // _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1103
+ // notARisks: getNoRiskTags(_riskFactor)
1104
+ // },
1105
+ // protocols: [Protocols.VESU],
1106
+ // maxTVL: Web3Number.fromWei(0, 8),
1107
+ // contractDetails: getContractDetails(wbtcVaultSettings),
1108
+ // faqs: getFAQs(),
1109
+ // investmentSteps: investmentSteps,
1110
+ // auditUrl: AUDIT_URL,
1111
+ // },
1112
+ // {
1113
+ // name: "ETH Evergreen",
1114
+ // description: getDescription('ETH', ['vesu', 'extended']),
1115
+ // address: ContractAddr.from('0x446c22d4d3f5cb52b4950ba832ba1df99464c6673a37c092b1d9622650dbd8'),
1116
+ // launchBlock: 0,
1117
+ // type: 'ERC4626',
1118
+ // depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'ETH')!],
1119
+ // additionalInfo: getLooperSettings('ETH', 'WBTC', ethVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1120
+ // risk: {
1121
+ // riskFactor: _riskFactor,
1122
+ // netRisk:
1123
+ // _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1124
+ // _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1125
+ // notARisks: getNoRiskTags(_riskFactor)
1126
+ // },
1127
+ // protocols: [Protocols.VESU],
1128
+ // maxTVL: Web3Number.fromWei(0, 18),
1129
+ // contractDetails: getContractDetails(ethVaultSettings),
1130
+ // faqs: getFAQs(),
1131
+ // investmentSteps: investmentSteps,
1132
+ // auditUrl: AUDIT_URL,
1133
+ // },
1134
+ // {
1135
+ // name: "STRK Evergreen",
1136
+ // description: getDescription('STRK', ['vesu', 'endur', 'extended']),
1137
+ // address: ContractAddr.from('0x55d012f57e58c96e0a5c7ebbe55853989d01e6538b15a95e7178aca4af05c21'),
1138
+ // launchBlock: 0,
1139
+ // type: 'ERC4626',
1140
+ // depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'STRK')!],
1141
+ // additionalInfo: getLooperSettings('STRK', 'ETH', strkVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1142
+ // risk: {
1143
+ // riskFactor: _riskFactor,
1144
+ // netRisk:
1145
+ // _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1146
+ // _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1147
+ // notARisks: getNoRiskTags(_riskFactor)
1148
+ // },
1149
+ // protocols: [Protocols.VESU],
1150
+ // maxTVL: Web3Number.fromWei(0, 18),
1151
+ // contractDetails: getContractDetails(strkVaultSettings),
1152
+ // faqs: getFAQs(),
1153
+ // investmentSteps: investmentSteps,
1154
+ // auditUrl: AUDIT_URL,
1155
+ // },
1156
+ // {
1157
+ // name: "USDT Evergreen",
1158
+ // description: getDescription('USDT', ['vesu']),
1159
+ // address: ContractAddr.from('0x1c4933d1880c6778585e597154eaca7b428579d72f3aae425ad2e4d26c6bb3'),
1160
+ // launchBlock: 0,
1161
+ // type: 'ERC4626',
1162
+ // depositTokens: [Global.getDefaultTokens().find(token => token.symbol === 'USDT')!],
1163
+ // additionalInfo: getLooperSettings('USDT', 'ETH', usdtVaultSettings, VesuPools.Genesis, VesuPools.Genesis),
1164
+ // risk: {
1165
+ // riskFactor: _riskFactor,
1166
+ // netRisk:
1167
+ // _riskFactor.reduce((acc, curr) => acc + curr.value * curr.weight, 0) /
1168
+ // _riskFactor.reduce((acc, curr) => acc + curr.weight, 0),
1169
+ // notARisks: getNoRiskTags(_riskFactor)
1170
+ // },
1171
+ // protocols: [Protocols.VESU],
1172
+ // maxTVL: Web3Number.fromWei(0, 6),
1173
+ // contractDetails: getContractDetails(usdtVaultSettings),
1174
+ // faqs: getFAQs(),
1175
+ // investmentSteps: investmentSteps,
1176
+ // auditUrl: AUDIT_URL,
1177
+ // }
1178
+ // ]