@strkfarm/sdk 1.0.56 → 1.0.58

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.
@@ -55,7 +55,6 @@ export class VesuAdapter extends BaseAdapter {
55
55
  config: VesuAdapterConfig;
56
56
  networkConfig: IConfig | undefined;
57
57
  pricer: PricerBase | undefined;
58
- cache: Record<string, any> = {};
59
58
 
60
59
  constructor(config: VesuAdapterConfig) {
61
60
  super();
@@ -121,17 +120,19 @@ export class VesuAdapter extends BaseAdapter {
121
120
  denomination: this.formatAmountDenominationEnum(params.collateralAmount.denomination),
122
121
  value: {
123
122
  abs: uint256.bnToUint256(params.collateralAmount.value.abs.toWei()),
124
- is_negative: params.collateralAmount.value.is_negative
123
+ is_negative: params.collateralAmount.value.abs.isZero() ? false: params.collateralAmount.value.is_negative
125
124
  }
126
125
  };
126
+ logger.verbose(`VesuAdapter::ConstructingModify::Collateral::${JSON.stringify(_collateral)}`)
127
127
  const _debt = {
128
128
  amount_type: this.formatAmountTypeEnum(params.debtAmount.amount_type),
129
129
  denomination: this.formatAmountDenominationEnum(params.debtAmount.denomination),
130
130
  value: {
131
131
  abs: uint256.bnToUint256(params.debtAmount.value.abs.toWei()),
132
- is_negative: params.debtAmount.value.is_negative
132
+ is_negative: params.debtAmount.value.abs.isZero() ? false: params.debtAmount.value.is_negative
133
133
  }
134
134
  };
135
+ logger.verbose(`VesuAdapter::ConstructingModify::Debt::${JSON.stringify(_debt)}`)
135
136
  const singletonContract = new Contract(VesuSingletonAbi, this.VESU_SINGLETON.toString(), new RpcProvider({nodeUrl: ''}));
136
137
  const call = singletonContract.populate('modify_position', {
137
138
  params: {
@@ -182,13 +183,14 @@ export class VesuAdapter extends BaseAdapter {
182
183
 
183
184
  async getLTVConfig(config: IConfig) {
184
185
  const CACHE_KEY = 'ltv_config';
185
- if (this.cache[CACHE_KEY]) {
186
- return this.cache[CACHE_KEY] as number;
186
+ const cacheData = this.getCache<number>(CACHE_KEY);
187
+ if (cacheData) {
188
+ return cacheData as number;
187
189
  }
188
190
  const output: any = await this.getVesuSingletonContract(config)
189
191
  .call('ltv_config', [this.config.poolId.address, this.config.collateral.address.address, this.config.debt.address.address])
190
- this.cache[CACHE_KEY] = Number(output.max_ltv) / 1e18;
191
- return this.cache[CACHE_KEY] as number;
192
+ this.setCache(CACHE_KEY, Number(output.max_ltv) / 1e18, 300000); // ttl: 5min
193
+ return this.getCache<number>(CACHE_KEY) as number;
192
194
  }
193
195
 
194
196
  async getPositions(config: IConfig): Promise<VaultPosition[]> {
@@ -197,8 +199,9 @@ export class VesuAdapter extends BaseAdapter {
197
199
  }
198
200
  // { '0': { collateral_shares: 0n, nominal_debt: 0n }, '1': 0n, '2': 0n }
199
201
  const CACHE_KEY = 'positions';
200
- if (this.cache[CACHE_KEY]) {
201
- return this.cache[CACHE_KEY];
202
+ const cacheData = this.getCache<VaultPosition[]>(CACHE_KEY);
203
+ if (cacheData) {
204
+ return cacheData;
202
205
  }
203
206
  const output: any = await this.getVesuSingletonContract(config)
204
207
  .call('position_unsafe', [
@@ -224,10 +227,77 @@ export class VesuAdapter extends BaseAdapter {
224
227
  usdValue: debtAmount.multipliedBy(token2Price.price).toNumber(),
225
228
  remarks: "Debt"
226
229
  }];
227
- this.cache[CACHE_KEY] = value;
230
+ this.setCache(CACHE_KEY, value, 60000); // ttl: 1min
228
231
  return value;
229
232
  }
230
233
 
234
+ async getCollateralization(config: IConfig): Promise<Omit<VaultPosition, 'amount'>[]> {
235
+ if (!this.pricer) {
236
+ throw new Error('Pricer is not initialized');
237
+ }
238
+ // { '0': bool, '1': 0n, '2': 0n }
239
+ const CACHE_KEY = 'collateralization';
240
+ const cacheData = this.getCache<Omit<VaultPosition, 'amount'>[]>(CACHE_KEY);
241
+ if (cacheData) {
242
+ return cacheData;
243
+ }
244
+ const output: any = await this.getVesuSingletonContract(config)
245
+ .call('check_collateralization_unsafe', [
246
+ this.config.poolId.address,
247
+ this.config.collateral.address.address,
248
+ this.config.debt.address.address,
249
+ this.config.vaultAllocator.address
250
+ ]);
251
+
252
+ // usd values
253
+ const collateralAmount = Web3Number.fromWei(output['1'].toString(), 18);
254
+ const debtAmount = Web3Number.fromWei(output['2'].toString(), 18);
255
+ const value = [{
256
+ token: this.config.collateral,
257
+ usdValue: collateralAmount.toNumber(),
258
+ remarks: "Collateral"
259
+ }, {
260
+ token: this.config.debt,
261
+ usdValue: debtAmount.toNumber(),
262
+ remarks: "Debt"
263
+ }];
264
+ this.setCache(CACHE_KEY, value, 60000); // ttl: 1min
265
+ return value;
266
+ }
267
+
268
+ async getAssetPrices() {
269
+ const collateralizationProm = this.getCollateralization(this.networkConfig!);
270
+ const positionsProm = this.getPositions(this.networkConfig!);
271
+ const ltvProm = this.getLTVConfig(this.networkConfig!);
272
+
273
+ const output = await Promise.all([collateralizationProm, positionsProm, ltvProm]);
274
+ const [collateralization, positions, ltv] = output;
275
+
276
+ const collateralTokenAmount = positions[0].amount;
277
+ const collateralUSDAmount = collateralization[0].usdValue;
278
+ const collateralPrice = collateralUSDAmount / collateralTokenAmount.toNumber();
279
+
280
+ const debtTokenAmount = positions[1].amount;
281
+ const debtUSDAmount = collateralization[1].usdValue;
282
+ const debtPrice = debtUSDAmount / debtTokenAmount.toNumber();
283
+
284
+ return {
285
+ collateralTokenAmount,
286
+ collateralUSDAmount,
287
+ collateralPrice,
288
+ debtTokenAmount,
289
+ debtUSDAmount,
290
+ debtPrice,
291
+ ltv
292
+ }
293
+ }
294
+
295
+ async getHealthFactor() {
296
+ const ltv = await this.getLTVConfig(this.networkConfig!);
297
+ const collateralisation = await this.getCollateralization(this.networkConfig!);
298
+ return collateralisation[0].usdValue * ltv / collateralisation[1].usdValue;
299
+ }
300
+
231
301
  static async getVesuPools(
232
302
  retry = 0
233
303
  ): Promise<VesuPoolsInfo> {
@@ -9,13 +9,17 @@ import UniversalVaultAbi from '../data/universal-vault.abi.json';
9
9
  import ManagerAbi from '../data/vault-manager.abi.json';
10
10
  import { ApproveCallParams, BaseAdapter, CommonAdapter, FlashloanCallParams, GenerateCallFn, LeafAdapterFn, ManageCall, VesuAdapter, VesuModifyPositionCallParams, VesuPools } from "./universal-adapters";
11
11
  import { Global } from "@/global";
12
+ import { ERC20 } from "@/modules";
12
13
 
13
14
  export interface UniversalStrategySettings {
14
15
  manager: ContractAddr,
15
16
  vaultAllocator: ContractAddr,
16
17
  redeemRequestNFT: ContractAddr,
18
+ aumOracle: ContractAddr,
17
19
  leafAdapters: LeafAdapterFn<any>[],
18
- adapters: {id: string, adapter: BaseAdapter}[]
20
+ adapters: {id: string, adapter: BaseAdapter}[],
21
+ targetHealthFactor: number,
22
+ minHealthFactor: number
19
23
  }
20
24
 
21
25
 
@@ -166,7 +170,7 @@ export class UniversalStrategy<
166
170
  * Calculates the weighted average APY across all pools based on USD value.
167
171
  * @returns {Promise<number>} The weighted average APY across all pools
168
172
  */
169
- async netAPY(): Promise<number> {
173
+ async netAPY(): Promise<{ net: number, splits: { apy: number, id: string }[] }> {
170
174
  const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
171
175
  const pools = await VesuAdapter.getVesuPools();
172
176
  const pool1 = pools.pools.find(p => vesuAdapter1.config.poolId.eqString(num.getHexString(p.id)));
@@ -182,20 +186,32 @@ export class UniversalStrategy<
182
186
  // supplyApy: { value: '8057256029163289', decimals: 18 },
183
187
  // defiSpringSupplyApr: { value: '46856062629264560', decimals: 18 },
184
188
  // borrowApr: { value: '12167825982336000', decimals: 18 },
185
- const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18 + Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18;
189
+ const collateral1APY = Number(collateralAsset1.supplyApy.value) / 1e18;
186
190
  const debt1APY = Number(debtAsset1.borrowApr.value) / 1e18;
187
- const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18 + Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18;
191
+ const collateral2APY = Number(collateralAsset2.supplyApy.value) / 1e18;
188
192
  const debt2APY = Number(debtAsset2.borrowApr.value) / 1e18;
189
193
 
190
- const apys = [collateral1APY, debt1APY, collateral2APY, debt2APY];
191
194
  const positions = await this.getVaultPositions();
192
- assert(positions.length == apys.length, "Positions and APYs length mismatch");
193
- const weightedAPYs = positions.map((pos, i) => {
194
- return pos.usdValue * apys[i] * (i % 2 == 0 ? 1 : -1);
195
- });
196
- const netPosition = positions.reduce((acc, val, index) => acc + val.usdValue * (index % 2 == 0 ? 1 : -1), 0);
197
- const apy = weightedAPYs.reduce((acc, val) => acc + val, 0) / netPosition;
198
- return apy;
195
+ const weights = positions.map((p, index) => p.usdValue * (index % 2 == 0 ? 1 : -1));
196
+ const baseAPYs = [collateral1APY, debt1APY, collateral2APY, debt2APY];
197
+ assert(positions.length == baseAPYs.length, "Positions and APYs length mismatch");
198
+ const rewardAPYs = [Number(collateralAsset1.defiSpringSupplyApr.value) / 1e18, 0, Number(collateralAsset2.defiSpringSupplyApr.value) / 1e18, 0];
199
+ const baseAPY = this.computeAPY(baseAPYs, weights);
200
+ const rewardAPY = this.computeAPY(rewardAPYs, weights);
201
+ const apys = [...baseAPYs, ...rewardAPYs];
202
+ const netAPY = baseAPY + rewardAPY;
203
+ return { net: netAPY, splits: [{
204
+ apy: baseAPY, id: 'base'
205
+ }, {
206
+ apy: rewardAPY, id: 'defispring'
207
+ }] };
208
+ }
209
+
210
+ private computeAPY(apys: number[], weights: number[]) {
211
+ assert(apys.length === weights.length, "APYs and weights length mismatch");
212
+ const weightedSum = apys.reduce((acc, apy, i) => acc + apy * weights[i], 0);
213
+ const totalWeight = weights.reduce((acc, weight) => acc + weight, 0);
214
+ return weightedSum / totalWeight;
199
215
  }
200
216
 
201
217
  /**
@@ -219,23 +235,56 @@ export class UniversalStrategy<
219
235
  };
220
236
  }
221
237
 
222
- async getAUM(): Promise<SingleTokenInfo> {
238
+ async getAUM(): Promise<{net: SingleTokenInfo, prevAum: Web3Number, splits: {id: string, aum: Web3Number}[]}> {
239
+ const currentAUM: bigint = await this.contract.call('aum', []) as bigint;
240
+ const lastReportTime = await this.contract.call('last_report_timestamp', []);
241
+
242
+ const token1Price = await this.pricer.getPrice(this.metadata.depositTokens[0].symbol);
243
+
244
+ // calculate actual aum
223
245
  const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
224
246
  const leg1AUM = await vesuAdapter1.getPositions(this.config);
225
247
  const leg2AUM = await vesuAdapter2.getPositions(this.config);
226
248
 
227
- const token1Price = await this.pricer.getPrice(vesuAdapter1.config.collateral.symbol);
249
+ const balance = await (new ERC20(this.config)).balanceOf(this.asset().address, this.metadata.additionalInfo.vaultAllocator, this.asset().decimals);
250
+ logger.verbose(`${this.getTag()} unused balance: ${balance}`);
228
251
 
229
252
  const aumToken = leg1AUM[0].amount
230
253
  .plus(leg2AUM[0].usdValue / token1Price.price)
231
254
  .minus(leg1AUM[1].usdValue / token1Price.price)
232
- .minus(leg2AUM[1].amount);
233
-
234
- return {
255
+ .minus(leg2AUM[1].amount).plus(balance);
256
+ logger.verbose(`${this.getTag()} Actual AUM: ${aumToken}`);
257
+
258
+ // calculate estimated growth from strk rewards
259
+ const netAPY = await this.netAPY();
260
+ const defispringAPY = netAPY.splits.find(s => s.id === 'defispring')?.apy || 0;
261
+ if (!defispringAPY) throw new Error('DefiSpring APY not found');
262
+
263
+ const timeDiff = (Math.round(Date.now() / 1000) - Number(lastReportTime));
264
+ const growthRate = timeDiff * defispringAPY / (365 * 24 * 60 * 60);
265
+ const prevAum = Web3Number.fromWei(currentAUM.toString(), this.asset().decimals);
266
+ const rewardAssets = prevAum.multipliedBy(growthRate);
267
+ logger.verbose(`${this.getTag()} DefiSpring AUM time difference: ${timeDiff}`);
268
+ logger.verbose(`${this.getTag()} Current AUM: ${currentAUM}`);
269
+ logger.verbose(`${this.getTag()} Net APY: ${JSON.stringify(netAPY)}`);
270
+ logger.verbose(`${this.getTag()} rewards AUM: ${rewardAssets}`);
271
+
272
+ const newAUM = aumToken.plus(rewardAssets);
273
+ logger.verbose(`${this.getTag()} New AUM: ${newAUM}`);
274
+
275
+ const net = {
235
276
  tokenInfo: this.asset(),
236
- amount: aumToken,
237
- usdValue: aumToken.multipliedBy(token1Price.price).toNumber()
238
- }
277
+ amount: newAUM,
278
+ usdValue: newAUM.multipliedBy(token1Price.price).toNumber()
279
+ };
280
+ const splits = [{
281
+ id: 'finalised',
282
+ aum: aumToken
283
+ }, {
284
+ id: 'defispring',
285
+ aum: rewardAssets
286
+ }];
287
+ return { net, splits, prevAum };
239
288
  }
240
289
 
241
290
  getVesuAdapters() {
@@ -243,6 +292,8 @@ export class UniversalStrategy<
243
292
  const vesuAdapter2 = this.getAdapter(UNIVERSAL_ADAPTERS.VESU_LEG2) as VesuAdapter;
244
293
  vesuAdapter1.pricer = this.pricer;
245
294
  vesuAdapter2.pricer = this.pricer;
295
+ vesuAdapter1.networkConfig = this.config;
296
+ vesuAdapter2.networkConfig = this.config;
246
297
 
247
298
  return [vesuAdapter1, vesuAdapter2];
248
299
  }
@@ -297,12 +348,14 @@ export class UniversalStrategy<
297
348
 
298
349
  const output = [{
299
350
  proofs: manage5Info.proofs,
300
- manageCall: manageCall5
351
+ manageCall: manageCall5,
352
+ step: STEP2_ID
301
353
  }];
302
354
  if (approveAmount.gt(0)) {
303
355
  output.unshift({
304
356
  proofs: manage4Info.proofs,
305
- manageCall: manageCall4
357
+ manageCall: manageCall4,
358
+ step: STEP1_ID
306
359
  })
307
360
  }
308
361
  return output;
@@ -312,12 +365,114 @@ export class UniversalStrategy<
312
365
  return `${UniversalStrategy.name}:${this.metadata.name}`;
313
366
  }
314
367
 
368
+ async getVesuHealthFactors() {
369
+ return await Promise.all(this.getVesuAdapters().map(v => v.getHealthFactor()));
370
+ }
371
+
372
+ async computeRebalanceConditionAndReturnCalls(): Promise<Call[]> {
373
+ const vesuAdapters = this.getVesuAdapters();
374
+ const healthFactors = await this.getVesuHealthFactors();
375
+ const leg1HealthFactor = healthFactors[0];
376
+ const leg2HealthFactor = healthFactors[1];
377
+ logger.verbose(`${this.getTag()}: HealthFactorLeg1: ${leg1HealthFactor}`);
378
+ logger.verbose(`${this.getTag()}: HealthFactorLeg2: ${leg2HealthFactor}`);
379
+
380
+ const minHf = this.metadata.additionalInfo.minHealthFactor;
381
+ const isRebalanceNeeded1 = leg1HealthFactor < minHf;
382
+ const isRebalanceNeeded2 = leg2HealthFactor < minHf;
383
+ if (!isRebalanceNeeded1 && !isRebalanceNeeded2) {
384
+ return [];
385
+ }
386
+
387
+ if (isRebalanceNeeded1) {
388
+ const amount = await this.getLegRebalanceAmount(vesuAdapters[0], leg1HealthFactor, false);
389
+ const leg2HF = await this.getNewHealthFactor(vesuAdapters[1], amount, true);
390
+ assert(leg2HF > minHf, `Rebalance Leg1 failed: Leg2 HF after rebalance would be too low: ${leg2HF}`);
391
+ return [await this.getRebalanceCall({
392
+ isLeg1toLeg2: false,
393
+ amount: amount
394
+ })];
395
+ } else {
396
+ const amount = await this.getLegRebalanceAmount(vesuAdapters[1], leg2HealthFactor, true);
397
+ const leg1HF = await this.getNewHealthFactor(vesuAdapters[0], amount, false);
398
+ assert(leg1HF > minHf, `Rebalance Leg2 failed: Leg1 HF after rebalance would be too low: ${leg1HF}`);
399
+ return [await this.getRebalanceCall({
400
+ isLeg1toLeg2: true,
401
+ amount: amount
402
+ })];
403
+ }
404
+ }
405
+
406
+ private async getNewHealthFactor(vesuAdapter: VesuAdapter, newAmount: Web3Number, isWithdraw: boolean) {
407
+ const {
408
+ collateralTokenAmount,
409
+ collateralUSDAmount,
410
+ collateralPrice,
411
+ debtTokenAmount,
412
+ debtUSDAmount,
413
+ debtPrice,
414
+ ltv
415
+ } = await vesuAdapter.getAssetPrices();
416
+
417
+ if (isWithdraw) {
418
+ const newHF = ((collateralTokenAmount.toNumber() - newAmount.toNumber()) * collateralPrice * ltv) / debtUSDAmount;
419
+ logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isDeposit`);
420
+ return newHF;
421
+ } else { // is borrow
422
+ const newHF = (collateralUSDAmount * ltv) / ((debtTokenAmount.toNumber() + newAmount.toNumber()) * debtPrice);
423
+ logger.verbose(`getNewHealthFactor:: HF: ${newHF}, amoutn: ${newAmount.toNumber()}, isRepay`);
424
+ return newHF;
425
+ }
426
+ }
427
+
428
+ /**
429
+ *
430
+ * @param vesuAdapter
431
+ * @param currentHf
432
+ * @param isDeposit if true, attempt by adding collateral, else by repaying
433
+ * @returns
434
+ */
435
+ private async getLegRebalanceAmount(vesuAdapter: VesuAdapter, currentHf: number, isDeposit: boolean) {
436
+ const {
437
+ collateralTokenAmount,
438
+ collateralUSDAmount,
439
+ collateralPrice,
440
+ debtTokenAmount,
441
+ debtUSDAmount,
442
+ debtPrice,
443
+ ltv
444
+ } = await vesuAdapter.getAssetPrices();
445
+
446
+ // debt is zero, nothing to rebalance
447
+ if(debtTokenAmount.isZero()) {
448
+ return Web3Number.fromWei(0, 0);
449
+ }
450
+
451
+ assert(collateralPrice > 0 && debtPrice > 0, "getRebalanceAmount: Invalid price");
452
+
453
+ // avoid calculating for too close
454
+ const targetHF = this.metadata.additionalInfo.targetHealthFactor;
455
+ if (currentHf > targetHF - 0.01)
456
+ throw new Error("getLegRebalanceAmount: Current health factor is healthy");
457
+
458
+ if (isDeposit) {
459
+ // TargetHF = (collAmount + newAmount) * price * ltv / debtUSD
460
+ const newAmount = targetHF * debtUSDAmount / (collateralPrice * ltv) - collateralTokenAmount.toNumber();
461
+ 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}`);
462
+ return new Web3Number(newAmount.toFixed(8), collateralTokenAmount.decimals);
463
+ } else {
464
+ // TargetHF = collUSD * ltv / (debtAmount - newAmount) * debtPrice
465
+ const newAmount = debtTokenAmount.toNumber() - collateralUSDAmount * ltv / (targetHF * debtPrice);
466
+ 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}`);
467
+ return new Web3Number(newAmount.toFixed(8), debtTokenAmount.decimals);
468
+ }
469
+ }
470
+
315
471
  async getVesuMultiplyCall(params: {
316
472
  isDeposit: boolean,
317
473
  leg1DepositAmount: Web3Number
318
474
  }) {
319
- const vesuAdapter1 = this.getAdapter(UNIVERSAL_ADAPTERS.VESU_LEG1) as VesuAdapter;
320
- const vesuAdapter2 = this.getAdapter(UNIVERSAL_ADAPTERS.VESU_LEG2) as VesuAdapter;
475
+ const [vesuAdapter1, vesuAdapter2] = this.getVesuAdapters();
321
476
  const leg1LTV = await vesuAdapter1.getLTVConfig(this.config);
322
477
  const leg2LTV = await vesuAdapter2.getLTVConfig(this.config);
323
478
  logger.verbose(`${this.getTag()}: LTVLeg1: ${leg1LTV}`);
@@ -328,7 +483,7 @@ export class UniversalStrategy<
328
483
  logger.verbose(`${this.getTag()}: Price${vesuAdapter1.config.collateral.symbol}: ${token1Price.price}`);
329
484
  logger.verbose(`${this.getTag()}: Price${vesuAdapter2.config.collateral.symbol}: ${token2Price.price}`);
330
485
 
331
- const TARGET_HF = 1.3;
486
+ const TARGET_HF = this.metadata.additionalInfo.targetHealthFactor;
332
487
 
333
488
  const k1 = token1Price.price * leg1LTV / token2Price.price / TARGET_HF;
334
489
  const k2 = token1Price.price * TARGET_HF / token2Price.price / leg2LTV;
@@ -399,14 +554,12 @@ export class UniversalStrategy<
399
554
 
400
555
  if (params.isLeg1toLeg2) {
401
556
  const manageCall = this.getManageCall([
402
- UNIVERSAL_MANAGE_IDS.VESU_LEG1,
403
- UNIVERSAL_MANAGE_IDS.VESU_LEG2
557
+ ...callSet1.map(i => i.step), ...callSet2.map(i => i.step)
404
558
  ], [...callSet1.map(i => i.manageCall), ...callSet2.map(i => i.manageCall)]);
405
559
  return manageCall;
406
560
  } else {
407
561
  const manageCall = this.getManageCall([
408
- UNIVERSAL_MANAGE_IDS.VESU_LEG2,
409
- UNIVERSAL_MANAGE_IDS.VESU_LEG1
562
+ ...callSet2.map(i => i.step), ...callSet1.map(i => i.step)
410
563
  ], [...callSet2.map(i => i.manageCall), ...callSet1.map(i => i.manageCall)]);
411
564
  return manageCall;
412
565
  }
@@ -484,16 +637,22 @@ const usdcVaultSettings: UniversalStrategySettings = {
484
637
  manager: ContractAddr.from('0xf41a2b1f498a7f9629db0b8519259e66e964260a23d20003f3e42bb1997a07'),
485
638
  vaultAllocator: ContractAddr.from('0x228cca1005d3f2b55cbaba27cb291dacf1b9a92d1d6b1638195fbd3d0c1e3ba'),
486
639
  redeemRequestNFT: ContractAddr.from('0x906d03590010868cbf7590ad47043959d7af8e782089a605d9b22567b64fda'),
640
+ aumOracle: ContractAddr.from("0x6faf45ed185dec13ef723c9ead4266cab98d06f2cb237e331b1fa5c2aa79afe"),
487
641
  leafAdapters: [],
488
- adapters: []
642
+ adapters: [],
643
+ targetHealthFactor: 1.3,
644
+ minHealthFactor: 1.25
489
645
  }
490
646
 
491
647
  const wbtcVaultSettings: UniversalStrategySettings = {
492
648
  manager: ContractAddr.from('0xef8a664ffcfe46a6af550766d27c28937bf1b77fb4ab54d8553e92bca5ba34'),
493
649
  vaultAllocator: ContractAddr.from('0x1e01c25f0d9494570226ad28a7fa856c0640505e809c366a9fab4903320e735'),
494
650
  redeemRequestNFT: ContractAddr.from('0x4fec59a12f8424281c1e65a80b5de51b4e754625c60cddfcd00d46941ec37b2'),
651
+ aumOracle: ContractAddr.from("0x2edf4edbed3f839e7f07dcd913e92299898ff4cf0ba532f8c572c66c5b331b2"),
495
652
  leafAdapters: [],
496
- adapters: []
653
+ adapters: [],
654
+ targetHealthFactor: 1.3,
655
+ minHealthFactor: 1.25
497
656
  }
498
657
 
499
658
  export const UniversalStrategies: IStrategyMetadata<UniversalStrategySettings>[] =
@@ -0,0 +1,29 @@
1
+ interface CacheData {
2
+ timestamp: number;
3
+ ttl: number;
4
+ data: any;
5
+ }
6
+ export class CacheClass {
7
+ readonly cache: Map<string, CacheData> = new Map();
8
+
9
+ setCache(key: string, data: any, ttl: number = 60000): void {
10
+ const timestamp = Date.now();
11
+ this.cache.set(key, { timestamp, ttl, data });
12
+ }
13
+
14
+ getCache<T>(key: string): T | null {
15
+ const cachedData = this.cache.get(key);
16
+ if (!cachedData || !this.isCacheValid(key)) {
17
+ return null;
18
+ }
19
+ return cachedData.data;
20
+ }
21
+
22
+ isCacheValid(key: string): boolean {
23
+ const cachedData = this.cache.get(key);
24
+ if (!cachedData) return false;
25
+
26
+ const { timestamp, ttl } = cachedData;
27
+ return Date.now() - timestamp <= ttl;
28
+ }
29
+ }
@@ -59,15 +59,6 @@ export class StandardMerkleTree extends MerkleTreeImpl<LeafData> {
59
59
  return new StandardMerkleTree(tree, indexedValues, leafEncoding);
60
60
  }
61
61
 
62
- static load(data: StandardMerkleTreeData<LeafData>): StandardMerkleTree {
63
- validateArgument(data.format === 'standard-v1', `Unknown format '${data.format}'`);
64
- validateArgument(data.leafEncoding !== undefined, 'Expected leaf encoding');
65
-
66
- const tree = new StandardMerkleTree(data.tree, data.values, data.leafEncoding);
67
- tree.validate();
68
- return tree;
69
- }
70
-
71
62
  static verify<T extends any[]>(root: BytesLike, leafEncoding: ValueType[], leaf: T, proof: BytesLike[]): boolean {
72
63
  // use default nodeHash (standardNodeHash) for processProof
73
64
  return toHex(root) === processProof(standardLeafHash(leafEncoding, leaf), proof);