@strkfarm/sdk 2.0.0-dev.2 → 2.0.0-dev.21

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.
@@ -13,7 +13,8 @@ import { logger } from "@/utils";
13
13
  import { AUDIT_URL } from "../universal-lst-muliplier-strategy";
14
14
  import { getNoRiskTags } from "@/interfaces";
15
15
  import { _riskFactor } from "../universal-lst-muliplier-strategy";
16
- import { BUFFER_USDC_IN_WITHDRAWAL, EXTENDED_QTY_PRECISION, LIMIT_BALANCE, MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED, MINIMUM_EXTENDED_POSITION_SIZE, USDC_TOKEN_DECIMALS, WALLET_ADDRESS, WBTC_TOKEN_DECIMALS } from "./utils/constants";
16
+ import { BUFFER_USDC_IN_WITHDRAWAL, LIMIT_BALANCE, LIMIT_BALANCE_VALUE, MINIMUM_EXTENDED_POSITION_SIZE, USDC_TOKEN_DECIMALS, WALLET_ADDRESS, WBTC_TOKEN_DECIMALS } from "./utils/constants";
17
+ import { CycleType } from "./types/transaction-metadata";
17
18
  import { PricerBase } from "@/modules/pricerBase";
18
19
  import { ContractAddr, Web3Number } from "@/dataTypes";
19
20
  import { Global } from "@/global";
@@ -53,6 +54,8 @@ import {
53
54
  } from "./utils/helper";
54
55
  import { SingleTokenInfo } from "../base-strategy";
55
56
  import { Call } from "starknet";
57
+ import { PositionTypeAvnuExtended } from "../universal-strategy";
58
+ import { TransactionMetadata, TransactionResult } from "./types/transaction-metadata";
56
59
 
57
60
 
58
61
  export interface VesuExtendedStrategySettings
@@ -64,6 +67,7 @@ export interface VesuExtendedStrategySettings
64
67
  minHealthFactor: number;
65
68
  aumOracle: ContractAddr;
66
69
  minimumWBTCDifferenceForAvnuSwap: number;
70
+ walletAddress: string;
67
71
  }
68
72
 
69
73
  export class VesuExtendedMultiplierStrategy<
@@ -71,7 +75,6 @@ export class VesuExtendedMultiplierStrategy<
71
75
  >
72
76
  extends SVKStrategy<S>
73
77
  implements Operations {
74
-
75
78
  constructor(
76
79
  config: IConfig,
77
80
  pricer: PricerBase,
@@ -108,7 +111,7 @@ export class VesuExtendedMultiplierStrategy<
108
111
  debtPrice,
109
112
  };
110
113
  }
111
-
114
+
112
115
  async getUnusedBalanceUSDCE(): Promise<SingleTokenInfo> {
113
116
  const usdceToken = Global.getDefaultTokens().find(
114
117
  (token) => token.symbol === "USDCe"
@@ -179,20 +182,40 @@ export class VesuExtendedMultiplierStrategy<
179
182
  return extendedAdapter.adapter as ExtendedAdapter;
180
183
  }
181
184
 
182
- async moveAssetsToVaultAllocator(amount: Web3Number, extendedAdapter: ExtendedAdapter): Promise<Call[]> {
185
+ async moveAssetsToVaultAllocator(amount: Web3Number, extendedAdapter: ExtendedAdapter): Promise<{
186
+ calls: Call[],
187
+ status: boolean,
188
+ }> {
183
189
  try {
184
190
  const usdceToken = Global.getDefaultTokens().find(
185
191
  (token) => token.symbol === "USDCe"
186
192
  )!;
193
+ const walletBalance = await new ERC20(this.config).balanceOf(
194
+ usdceToken.address,
195
+ WALLET_ADDRESS,
196
+ usdceToken.decimals
197
+ );
198
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator walletBalance: ${walletBalance}`);
199
+ const amountToBeTransferred = amount.minimum(walletBalance);
200
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator amountToBeTransferred: ${amountToBeTransferred.toNumber()}`);
201
+
202
+ if (amountToBeTransferred.lessThan(0)) {
203
+ logger.error(`${VesuExtendedMultiplierStrategy.name}::moveAssetsToVaultAllocator amountToBeTransferred is less than 0: ${amountToBeTransferred.toNumber()}`);
204
+ return {
205
+ calls: [],
206
+ status: false,
207
+ };
208
+ }
209
+
187
210
  const approveCall = new ERC20(this.config).approve(
188
211
  usdceToken.address,
189
212
  this.metadata.additionalInfo.vaultAllocator,
190
- amount
213
+ amountToBeTransferred
191
214
  );
192
215
  const transferCall = new ERC20(this.config).transfer(
193
216
  usdceToken.address,
194
217
  this.metadata.additionalInfo.vaultAllocator,
195
- amount
218
+ amountToBeTransferred
196
219
  );
197
220
  const proofsInfo = extendedAdapter.getProofsForFromLegacySwap(
198
221
  this.getMerkleTree()
@@ -200,12 +223,18 @@ export class VesuExtendedMultiplierStrategy<
200
223
  const proofGroups = proofsInfo.proofs;
201
224
  const call = this.getManageCall(
202
225
  proofGroups,
203
- await proofsInfo.callConstructor({ amount: amount })
226
+ await proofsInfo.callConstructor({ amount: amountToBeTransferred })
204
227
  );
205
- return [approveCall, transferCall, call];
228
+ return {
229
+ calls: [approveCall, transferCall, call],
230
+ status: true,
231
+ };
206
232
  } catch (err) {
207
233
  logger.error(`error moving assets to vault allocator: ${err}`);
208
- return [];
234
+ return {
235
+ calls: [],
236
+ status: false,
237
+ };
209
238
  }
210
239
  }
211
240
 
@@ -219,11 +248,42 @@ export class VesuExtendedMultiplierStrategy<
219
248
  vesuLeverage: number;
220
249
  }> {
221
250
  try {
251
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
222
252
  const vesuAdapter = await this.getVesuAdapter();
223
253
  const extendedAdapter = await this.getExtendedAdapter();
224
- if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
254
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
255
+
256
+ if (!vesuAdapter) {
225
257
  logger.error(
226
- `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
258
+ `Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
259
+ );
260
+ return {
261
+ shouldInvest: false,
262
+ vesuAmount: new Web3Number(0, 0),
263
+ extendedAmount: new Web3Number(0, 0),
264
+ extendedLeverage: 0,
265
+ collateralPrice: 0,
266
+ debtPrice: 0,
267
+ vesuLeverage: 0,
268
+ };
269
+ }
270
+ if (!extendedAdapter) {
271
+ logger.error(
272
+ `Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
273
+ );
274
+ return {
275
+ shouldInvest: false,
276
+ vesuAmount: new Web3Number(0, 0),
277
+ extendedAmount: new Web3Number(0, 0),
278
+ extendedLeverage: 0,
279
+ collateralPrice: 0,
280
+ debtPrice: 0,
281
+ vesuLeverage: 0,
282
+ };
283
+ }
284
+ if (!extendedAdapter.client) {
285
+ logger.error(
286
+ `Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
227
287
  );
228
288
  return {
229
289
  shouldInvest: false,
@@ -235,12 +295,67 @@ export class VesuExtendedMultiplierStrategy<
235
295
  vesuLeverage: 0,
236
296
  };
237
297
  }
298
+
299
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
238
300
  const balance = await this.getUnusedBalance();
301
+
302
+ if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
303
+ logger.error(
304
+ `Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
305
+ );
306
+ return {
307
+ shouldInvest: false,
308
+ vesuAmount: new Web3Number(0, 0),
309
+ extendedAmount: new Web3Number(0, 0),
310
+ extendedLeverage: 0,
311
+ collateralPrice: 0,
312
+ debtPrice: 0,
313
+ vesuLeverage: 0,
314
+ };
315
+ }
316
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
239
317
  const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
318
+
319
+ if (usdcBalanceOnExtended) {
320
+ const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
321
+ if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
322
+ logger.error(
323
+ `Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
324
+ );
325
+ return {
326
+ shouldInvest: false,
327
+ vesuAmount: new Web3Number(0, 0),
328
+ extendedAmount: new Web3Number(0, 0),
329
+ extendedLeverage: 0,
330
+ collateralPrice: 0,
331
+ debtPrice: 0,
332
+ vesuLeverage: 0,
333
+ };
334
+ }
335
+ }
336
+
240
337
  /** The LIMIT_BALANCE is the bffer amount to keep in the investing Cycle */
241
- const amountToInvest = balance.amount.plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).minus(LIMIT_BALANCE);
338
+ const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
339
+
242
340
 
243
- if (amountToInvest.lessThan(0)) {
341
+ const amountToInvestNumber = amountToInvest.toNumber();
342
+ if (!Number.isFinite(amountToInvestNumber)) {
343
+ logger.error(
344
+ `Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
345
+ );
346
+ return {
347
+ shouldInvest: false,
348
+ vesuAmount: new Web3Number(0, 0),
349
+ extendedAmount: new Web3Number(0, 0),
350
+ extendedLeverage: 0,
351
+ collateralPrice: 0,
352
+ debtPrice: 0,
353
+ vesuLeverage: 0,
354
+ };
355
+ }
356
+
357
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
358
+ if (amountToInvest.lessThan(LIMIT_BALANCE_VALUE)) {
244
359
  return {
245
360
  shouldInvest: false,
246
361
  vesuAmount: new Web3Number(0, 0),
@@ -272,6 +387,37 @@ export class VesuExtendedMultiplierStrategy<
272
387
  collateralPrice,
273
388
  debtPrice
274
389
  } = await this.getAssetPrices();
390
+
391
+
392
+ if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
393
+ logger.error(
394
+ `Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
395
+ );
396
+ return {
397
+ shouldInvest: false,
398
+ vesuAmount: new Web3Number(0, 0),
399
+ extendedAmount: new Web3Number(0, 0),
400
+ extendedLeverage: 0,
401
+ collateralPrice: 0,
402
+ debtPrice: 0,
403
+ vesuLeverage: 0,
404
+ };
405
+ }
406
+ if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
407
+ logger.error(
408
+ `Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
409
+ );
410
+ return {
411
+ shouldInvest: false,
412
+ vesuAmount: new Web3Number(0, 0),
413
+ extendedAmount: new Web3Number(0, 0),
414
+ extendedLeverage: 0,
415
+ collateralPrice: 0,
416
+ debtPrice: 0,
417
+ vesuLeverage: 0,
418
+ };
419
+ }
420
+
275
421
  const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } =
276
422
  await calculateAmountDistribution(
277
423
  amountToInvest.toNumber(),
@@ -301,6 +447,7 @@ export class VesuExtendedMultiplierStrategy<
301
447
  vesuLeverage: 0,
302
448
  };
303
449
  }
450
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest vesu_amount: ${vesu_amount.toNumber()}, extended_amount: ${extended_amount.toNumber()}`);
304
451
  return {
305
452
  shouldInvest: true,
306
453
  vesuAmount: vesu_amount,
@@ -324,110 +471,258 @@ export class VesuExtendedMultiplierStrategy<
324
471
  }
325
472
  }
326
473
 
327
- async shouldMoveAssets(extendedAmount: Web3Number, vesuAmount: Web3Number): Promise<Call[]> {
474
+ async shouldMoveAssets(extendedAmount: Web3Number, vesuAmount: Web3Number): Promise<TransactionResult[]> {
328
475
  try {
329
476
  const vesuAdapter = await this.getVesuAdapter();
330
477
  const extendedAdapter = await this.getExtendedAdapter();
331
- let calls: Call[] = [];
332
478
  if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
333
479
  logger.error(
334
480
  `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
335
481
  );
336
- return calls;
482
+ return [];
483
+ }
484
+
485
+ const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
486
+ if (!extendedHoldings) {
487
+ logger.error(`error getting extended holdings: ${extendedHoldings}`);
488
+ return [];
337
489
  }
338
- if (extendedAmount.lessThan(0)) {
490
+ const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
491
+ const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
492
+ extendedHoldings.availableForWithdrawal
493
+ );
494
+
495
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
496
+
497
+ let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
498
+ let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
499
+
500
+ if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
501
+ totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
502
+ }
503
+
504
+ // Calculate remaining Extended difference (target vs current)
505
+ // If extendedAmount was negative, we've already accounted for that withdrawal
506
+ // So we calculate based on what Extended will be after that withdrawal
507
+ const extendedTargetAmount = extendedAmount.abs(); // Use absolute value as target
508
+ let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
509
+
510
+ if (extendedAmount.isNegative()) {
511
+ projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
512
+ }
513
+
514
+ const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
515
+ const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
516
+
517
+ // Track additional Extended movements
518
+ if (extendedAmountDifference.lessThan(0)) {
519
+ totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
520
+ } else if (extendedAmountDifference.greaterThan(0)) {
521
+ totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
522
+ }
523
+
524
+ const vesuTargetAmount = vesuAmount.abs();
525
+ const projectedWalletBalance = usdcAmountInWallet
526
+ .plus(totalExtendedWithdrawal)
527
+ .minus(totalExtendedDeposit);
528
+
529
+ let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
530
+ const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
531
+
532
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculated movements - Extended withdrawal: ${totalExtendedWithdrawal.toNumber()}, Extended deposit: ${totalExtendedDeposit.toNumber()}, Extended diff: ${extendedAmountDifference.toNumber()}, Projected wallet: ${projectedWalletBalance.toNumber()}, Vesu diff: ${vesuAmountDifference.toNumber()}`);
533
+ let calls: Call[] = [];
534
+ let transactionResults: TransactionResult[] = [];
535
+
536
+ // Handle negative extendedAmount (initial withdrawal needed)
537
+ if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
339
538
  try {
340
- const {calls: extendedCalls, status: extendedStatus} = await this.moveAssets(
539
+ const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
341
540
  {
342
541
  to: Protocols.VAULT.name,
343
542
  from: Protocols.EXTENDED.name,
344
543
  amount: extendedAmount.abs(),
544
+ cycleType: CycleType.INVESTMENT
345
545
  },
346
546
  extendedAdapter,
347
547
  vesuAdapter
348
548
  );
349
- //If withdrawal succesfull, then do further
350
- if(extendedStatus){
351
- calls.push(...extendedCalls);
352
- }else{
353
- return [];
549
+ if (extendedStatus) {
550
+ transactionResults.push({
551
+ status: extendedStatus,
552
+ calls: extendedCalls,
553
+ transactionMetadata: {
554
+ ...extendedTransactionMetadata,
555
+ transactionType: "DEPOSIT",
556
+ },
557
+ })
558
+ } else {
559
+ return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmount.abs() }, "NONE", CycleType.INVESTMENT)];
354
560
  }
355
561
  } catch (err) {
356
562
  logger.error(`Failed moving assets to vault: ${err}`);
563
+ return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmount.abs() }, "NONE", CycleType.INVESTMENT)];
357
564
  }
358
565
  }
359
566
 
360
- if (vesuAmount.lessThan(0)) {
567
+ if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
361
568
  try {
362
- const {calls: vesuCalls, status: vesuStatus} = await this.moveAssets(
569
+ const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
363
570
  {
364
571
  to: Protocols.EXTENDED.name,
365
572
  from: Protocols.VESU.name,
366
573
  amount: vesuAmount.abs(),
574
+ cycleType: CycleType.INVESTMENT
367
575
  },
368
576
  extendedAdapter,
369
577
  vesuAdapter
370
578
  );
371
- calls.push(...vesuCalls);
372
- if(!vesuStatus){
373
- return [];
579
+ if (!vesuStatus) {
580
+ return [this.createTransactionResult([], false, { from: Protocols.VESU.name, to: Protocols.EXTENDED.name, amount: vesuAmount.abs() }, "NONE", CycleType.INVESTMENT)];
374
581
  }
582
+ transactionResults.push({
583
+ status: vesuStatus,
584
+ calls: vesuCalls,
585
+ transactionMetadata: {
586
+ ...vesuTransactionMetadata,
587
+ transactionType: "DEPOSIT",
588
+ }
589
+ })
375
590
  } catch (err) {
376
- logger.error(`Failed moving assets to vault: ${err}`);
591
+ logger.error(`Failed moving assets to extended via vault allocator: ${err}`);
592
+ return [this.createTransactionResult([], false, { from: Protocols.VESU.name, to: Protocols.EXTENDED.name, amount: vesuAmount.abs() }, "NONE", CycleType.INVESTMENT)];
377
593
  }
378
594
  }
379
595
 
380
- const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
381
- if (!extendedHoldings) {
382
- logger.error(`error getting extended holdings: ${extendedHoldings}`);
383
- return calls;
384
- }
385
- const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
386
- const usdcAmountOnExtended = parseFloat(
387
- extendedHoldings.availableForWithdrawal
388
- );
389
- if (extendedAmount.minus(usdcAmountOnExtended).greaterThan(0)) {
390
- //move assets to extended
391
- try {
392
- const {calls: extendedCalls} = await this.moveAssets(
393
- {
394
- to: Protocols.EXTENDED.name,
395
- from: Protocols.VAULT.name,
396
- amount: extendedAmount.minus(usdcAmountOnExtended),
397
- },
398
- extendedAdapter,
399
- vesuAdapter
400
- );
401
- calls.push(...extendedCalls);
402
- } catch (err) {
403
- logger.error(`Failed moving assets to extended: ${err}`);
596
+ // Handle Extended adjustments based on calculated difference
597
+ if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
598
+ if (extendedAmountDifference.greaterThan(0)) {
599
+ try {
600
+ const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
601
+ {
602
+ to: Protocols.EXTENDED.name,
603
+ from: Protocols.VAULT.name,
604
+ amount: extendedAmountDifference,
605
+ cycleType: CycleType.INVESTMENT
606
+ },
607
+ extendedAdapter,
608
+ vesuAdapter
609
+ );
610
+ if (extendedStatus) {
611
+ transactionResults.push({
612
+ status: extendedStatus,
613
+ calls: extendedCalls,
614
+ transactionMetadata: extendedTransactionMetadata
615
+ })
616
+ } else {
617
+ logger.error(`Failed to move assets to extended - operation returned false status`);
618
+ return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.EXTENDED.name, amount: extendedAmountDifference }, "NONE", CycleType.INVESTMENT)];
619
+ }
620
+ } catch (err) {
621
+ logger.error(`Failed moving assets to extended: ${err}`);
622
+ return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.EXTENDED.name, amount: extendedAmountDifference }, "NONE", CycleType.INVESTMENT)];
623
+ }
624
+ } else if (extendedAmountDifference.lessThan(0)) {
625
+ try {
626
+ const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
627
+ {
628
+ to: Protocols.VAULT.name,
629
+ from: Protocols.EXTENDED.name,
630
+ amount: extendedAmountDifferenceAbs,
631
+ cycleType: CycleType.INVESTMENT
632
+ },
633
+ extendedAdapter,
634
+ vesuAdapter
635
+ );
636
+ if (extendedStatus) {
637
+ transactionResults.push({
638
+ status: extendedStatus,
639
+ calls: extendedCalls,
640
+ transactionMetadata: {
641
+ ...extendedTransactionMetadata,
642
+ transactionType: "DEPOSIT",
643
+ }
644
+ })
645
+ } else {
646
+ logger.error(`Failed to withdraw from extended - operation returned false status`);
647
+ return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmountDifferenceAbs }, "NONE", CycleType.INVESTMENT)];
648
+ }
649
+ } catch (err) {
650
+ logger.error(`Failed moving assets from extended to vault: ${err}`);
651
+ return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: extendedAmountDifferenceAbs }, "NONE", CycleType.INVESTMENT)];
652
+ }
404
653
  }
405
654
  }
406
- if (vesuAmount.minus(usdcAmountInWallet).greaterThan(0)) {
407
- //move assets to vesu
408
- try {
409
- const {calls: vesuCalls, status: vesuStatus} = await this.moveAssets(
410
- {
411
- to: Protocols.VAULT.name,
412
- from: Protocols.EXTENDED.name,
413
- amount: vesuAmount.minus(usdcAmountInWallet),
414
- },
415
- extendedAdapter,
416
- vesuAdapter
655
+
656
+ // Handle Vesu adjustments based on calculated difference (already adjusted for Extended movements)
657
+ if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
658
+ if (vesuAmountDifference.lessThanOrEqualTo(0)) {
659
+ logger.warn(
660
+ `Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
417
661
  );
418
- if(!vesuStatus){
419
- return [];
662
+ } else {
663
+ // Move assets from Extended to Vault (which will then go to Vesu)
664
+ try {
665
+ const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
666
+ {
667
+ to: Protocols.VAULT.name,
668
+ from: Protocols.EXTENDED.name,
669
+ amount: vesuAmountDifference,
670
+ cycleType: CycleType.INVESTMENT
671
+ },
672
+ extendedAdapter,
673
+ vesuAdapter
674
+ );
675
+ if (!vesuStatus) {
676
+ logger.error(`Failed to move assets to vesu - operation returned false status`);
677
+ return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: vesuAmountDifference }, "NONE", CycleType.INVESTMENT)];
678
+ }
679
+ transactionResults.push({
680
+ status: vesuStatus,
681
+ calls: vesuCalls,
682
+ transactionMetadata: {
683
+ ...vesuTransactionMetadata,
684
+ transactionType: "DEPOSIT",
685
+ }
686
+ })
687
+ } catch (err) {
688
+ logger.error(`Failed moving assets to vault: ${err}`);
689
+ return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: vesuAmountDifference }, "NONE", CycleType.INVESTMENT)];
420
690
  }
421
- calls.push(...vesuCalls);
422
- } catch (err) {
423
- logger.error(`Failed moving assets to vault: ${err}`);
424
691
  }
425
692
  }
426
- return calls;
693
+
694
+ return transactionResults;
427
695
  } catch (err) {
428
696
  logger.error(`Failed moving assets to vesu: ${err}`);
429
- return [];
697
+ return [this.createTransactionResult([], false, { from: Protocols.EXTENDED.name, to: Protocols.VAULT.name, amount: new Web3Number(0, USDC_TOKEN_DECIMALS) }, "NONE", CycleType.INVESTMENT)];
698
+ }
699
+ }
700
+
701
+ /**
702
+ * Helper method to create transaction result with metadata
703
+ */
704
+ private createTransactionResult(
705
+ calls: Call[],
706
+ status: boolean,
707
+ params: { from: string; to: string; amount: Web3Number },
708
+ transactionType: 'DEPOSIT' | 'WITHDRAWAL' | 'NONE',
709
+ cycleType: CycleType
710
+ ): TransactionResult {
711
+ if (status) {
712
+ return {
713
+ calls,
714
+ status: status,
715
+ transactionMetadata: {
716
+ protocolFrom: params.from,
717
+ protocolTo: params.to,
718
+ transactionType: transactionType,
719
+ usdAmount: params.amount.abs().toFixed(),
720
+ status: 'PENDING',
721
+ cycleType: cycleType
722
+ }
723
+ };
430
724
  }
725
+ return { calls: [], status: false, transactionMetadata: { protocolFrom: '', protocolTo: '', transactionType: 'DEPOSIT', usdAmount: '0', status: 'FAILED', cycleType: cycleType } };
431
726
  }
432
727
 
433
728
  async moveAssets(
@@ -435,21 +730,43 @@ export class VesuExtendedMultiplierStrategy<
435
730
  amount: Web3Number;
436
731
  from: string;
437
732
  to: string;
733
+ cycleType: CycleType;
438
734
  },
439
735
  extendedAdapter: ExtendedAdapter,
440
- vesuAdapter: VesuMultiplyAdapter
441
- ): Promise<{
442
- calls: Call[];
443
- status: boolean;
444
- }> {
736
+ vesuAdapter: VesuMultiplyAdapter,
737
+ ): Promise<TransactionResult> {
445
738
  try {
739
+ // Validate amount is positive before starting operations
740
+ if (params.amount.lessThanOrEqualTo(0)) {
741
+ logger.error(
742
+ `Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
743
+ );
744
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
745
+ }
746
+
747
+ // Check minimum movement amounts before starting operations
748
+ const amountAbs = params.amount.abs();
749
+ if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
750
+ if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
751
+ logger.warn(
752
+ `Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
753
+ );
754
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
755
+ }
756
+ }
757
+ if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
758
+ if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
759
+ logger.warn(
760
+ `Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
761
+ );
762
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
763
+ }
764
+ }
765
+
446
766
  const avnuAdapter = await this.getAvnuAdapter();
447
767
  if (!avnuAdapter) {
448
768
  logger.error(`avnu adapter not found: ${avnuAdapter}`);
449
- return {
450
- calls: [],
451
- status: false
452
- };
769
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
453
770
  }
454
771
  logger.info(`moveAssets params, ${JSON.stringify(params)}`);
455
772
  const collateralToken = vesuAdapter.config.supportedPositions[0].asset;
@@ -469,67 +786,84 @@ export class VesuExtendedMultiplierStrategy<
469
786
  await proofsInfo.callConstructor({ amount: params.amount })
470
787
  );
471
788
  calls.push(call);
472
- return {
473
- calls: [call],
474
- status: true
475
- };
789
+ return this.createTransactionResult(calls, true, params, "DEPOSIT", params.cycleType);
476
790
  } else if (params.to === Protocols.VAULT.name && params.from === Protocols.EXTENDED.name) {
477
791
  const extendedLeverage = calculateExtendedLevergae();
478
792
  const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
479
793
  if (!extendedHoldings) {
480
794
  logger.error(`error getting extended holdings: ${extendedHoldings}`);
481
- return {
482
- calls: [],
483
- status: false
484
- };
795
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
485
796
  }
486
797
  const extendedHoldingAmount = new Web3Number(
487
798
  extendedHoldings.availableForWithdrawal,
488
799
  USDC_TOKEN_DECIMALS
489
800
  );
490
-
491
- const leftAmountAfterWithdrawalAmountInAccount = params.amount.minus(extendedHoldingAmount);
492
- const btcAmount = leftAmountAfterWithdrawalAmountInAccount.dividedBy(collateralPrice.price);
493
- const openLongPosition = await extendedAdapter.createOrder(
494
- extendedLeverage.toString(),
495
- btcAmount.toNumber(),
496
- OrderSide.BUY
497
- )
498
- if (!openLongPosition) {
499
- logger.error(`error opening long position: ${openLongPosition}`);
500
- return {
501
- calls: [],
502
- status: false
503
- };
801
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::moveAssets extendedHoldingAmount: ${extendedHoldingAmount.toNumber()}`);
802
+ if (params.amount.abs().greaterThan(extendedHoldingAmount)) {
803
+ const leftAmountAfterWithdrawalAmountInAccount = params.amount.abs().minus(extendedHoldingAmount);
804
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::moveAssets leftAmountAfterWithdrawalAmountInAccount: ${leftAmountAfterWithdrawalAmountInAccount.toNumber()}`);
805
+ const btcAmount = leftAmountAfterWithdrawalAmountInAccount.dividedBy(collateralPrice.price);
806
+ const openLongPosition = btcAmount.multipliedBy(3).greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
807
+ extendedLeverage.toString(),
808
+ btcAmount.toNumber(),
809
+ OrderSide.BUY
810
+ ) : await extendedAdapter.createOrder(
811
+ extendedLeverage.toString(),
812
+ 0.000034, // just in case amount falls short then we need to create a withdrawal
813
+ OrderSide.BUY
814
+ )
815
+ if (!openLongPosition) {
816
+ logger.error(`error opening long position: ${openLongPosition}`);
817
+ }
818
+ const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
819
+ if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
820
+ logger.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
821
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
822
+ }
504
823
  }
505
- await new Promise(resolve => setTimeout(resolve, 5000));
506
- const withdrawalFromExtended =
824
+ const {
825
+ status: withdrawalFromExtendedStatus,
826
+ receivedTxnHash: withdrawalFromExtendedTxnHash,
827
+ } =
507
828
  await extendedAdapter.withdrawFromExtended(params.amount);
508
- if (withdrawalFromExtended) {
829
+ /**
830
+ * This logic needs fixing
831
+ */
832
+ logger.info(`withdrawalFromExtendedStatus: ${withdrawalFromExtendedStatus}, withdrawalFromExtendedTxnHash: ${withdrawalFromExtendedTxnHash}`);
833
+ if (withdrawalFromExtendedStatus && withdrawalFromExtendedTxnHash) {
509
834
  /**
510
835
  * We need to move assets from my wallet back to vault contract
511
836
  */
512
837
  const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
513
- logger.info(`extendedHoldings after withdrawal ${extendedHoldings}`);
514
- await new Promise(resolve => setTimeout(resolve, 10000));
515
- const calls = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
516
- if (calls.length > 0) {
517
- return {
518
- calls: calls,
519
- status: true
520
- };
838
+ logger.info(`extendedHoldings after withdrawal ${extendedHoldings?.availableForWithdrawal}`);
839
+ await new Promise(resolve => setTimeout(resolve, 5000));
840
+ const { calls, status } = await this.moveAssetsToVaultAllocator(params.amount, extendedAdapter);
841
+ if (calls.length > 0 && status) {
842
+ return this.createTransactionResult(calls, true, params, "WITHDRAWAL", params.cycleType);
843
+ } else {
844
+ /**
845
+ * This is a fallback scenario, where the funds were withdrawn from extended, but didn't get transferred to the wallet
846
+ * We need to return a successful transaction result, but with no calls
847
+ * Db update will be handled by the risk engine for this specific case
848
+ */
849
+ return this.createTransactionResult([], true, params, "WITHDRAWAL", params.cycleType);
521
850
  }
851
+ } else if (withdrawalFromExtendedStatus && !withdrawalFromExtendedTxnHash) {
852
+ logger.error("withdrawal from extended successful, but funds didn't get transferred to the wallet");
853
+ return this.createTransactionResult([], true, params, "WITHDRAWAL", params.cycleType);
522
854
  } else {
523
855
  logger.error("withdrawal from extended failed");
524
- return {
525
- calls: [],
526
- status: false
527
- };
856
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
528
857
  }
529
858
  } else if (params.to === Protocols.VAULT.name && params.from === Protocols.VESU.name) {
859
+ const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, PositionTypeAvnuExtended.CLOSE);
860
+ if (!isPriceDifferenceBetweenAvnuAndExtended) {
861
+ logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
862
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
863
+ }
530
864
  //withdraw from vesu
531
865
  const vesuAmountInBTC = new Web3Number(
532
- params.amount.dividedBy(collateralPrice.price).toNumber(),
866
+ params.amount.dividedBy(collateralPrice.price).toFixed(WBTC_TOKEN_DECIMALS),
533
867
  collateralToken.decimals
534
868
  );
535
869
  const proofsInfo = vesuAdapter.getProofs(false, this.getMerkleTree());
@@ -547,11 +881,13 @@ export class VesuExtendedMultiplierStrategy<
547
881
  await swapProofsInfo.callConstructor({ amount: vesuAmountInBTC })
548
882
  );
549
883
  calls.push(swapCall);
550
- return {
551
- calls: calls,
552
- status: true
553
- };
884
+ return this.createTransactionResult(calls, true, params, "WITHDRAWAL", params.cycleType);
554
885
  } else if (params.to === Protocols.EXTENDED.name && params.from === Protocols.VESU.name) {
886
+ const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter, PositionTypeAvnuExtended.CLOSE);
887
+ if (!isPriceDifferenceBetweenAvnuAndExtended) {
888
+ logger.warn(`price difference between avnu and extended doesn't fit the range for close position, ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
889
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
890
+ }
555
891
  const vesuAmountInBTC = new Web3Number(
556
892
  params.amount.dividedBy(collateralPrice.price).toNumber(),
557
893
  collateralToken.decimals
@@ -582,163 +918,77 @@ export class VesuExtendedMultiplierStrategy<
582
918
  await proofsInfoDeposit.callConstructor({ amount: params.amount })
583
919
  );
584
920
  calls.push(callDeposit);
585
- return {
586
- calls: calls,
587
- status: true
588
- };
921
+ return this.createTransactionResult(calls, true, params, "DEPOSIT", params.cycleType);
589
922
  }
590
- return {
591
- calls: [],
592
- status: false
593
- };
923
+ logger.error(`Unsupported assets movement: ${params.from} to ${params.to}`);
924
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
594
925
  } catch (err) {
595
926
  logger.error(`error moving assets: ${err}`);
596
- return {
597
- calls: [],
598
- status: false
599
- };
927
+ return this.createTransactionResult([], false, params, "NONE", params.cycleType);
600
928
  }
601
929
  }
602
930
 
603
- async handleDeposit(): Promise<{
604
- extendedAmountInBTC: Web3Number,
605
- calls: Call[]
606
- }> {
931
+ async handleDeposit(): Promise<TransactionResult> {
607
932
  try {
608
- const vesuAdapter = await this.getVesuAdapter();
609
- const extendedAdapter = await this.getExtendedAdapter();
610
- const avnuAdapter = await this.getAvnuAdapter();
611
- if (
612
- !vesuAdapter ||
613
- !extendedAdapter ||
614
- !extendedAdapter.client ||
615
- !avnuAdapter
616
- ) {
617
- logger.error(
618
- "vesu or extended adapter not found",
619
- vesuAdapter,
620
- extendedAdapter
621
- );
622
- return {
623
- extendedAmountInBTC: new Web3Number(0, 0),
624
- calls: [],
625
- };
626
- }
627
- const extendedLeverage = calculateExtendedLevergae();
628
- const isPriceDifferenceBetweenAvnuAndExtended = await this.checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter, vesuAdapter, avnuAdapter);
629
- if (!isPriceDifferenceBetweenAvnuAndExtended) {
630
- logger.error("price difference between avnu and extended doesn't fit the range");
631
- return {
632
- extendedAmountInBTC: new Web3Number(0, 0),
633
- calls: [],
634
- };
635
- }
636
- const position = await extendedAdapter.getAllOpenPositions();
637
- if (!position) {
638
- logger.error("error getting extended position", position);
639
- return {
640
- extendedAmountInBTC: new Web3Number(0, 0),
641
- calls: [],
642
- };
643
- }
644
- const extendedPositionValue = position.length > 0 ? parseFloat(position[0].value) : 0;
645
- const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
646
- if (!extendedHoldings) {
647
- logger.error(`error getting extended holdings: ${extendedHoldings}`);
648
- return {
649
- extendedAmountInBTC: new Web3Number(0, 0),
650
- calls: [],
651
- };
652
- }
653
- const extendedHoldingAmount = new Web3Number(
654
- extendedHoldings.availableForWithdrawal,
655
- USDC_TOKEN_DECIMALS
656
- );
657
- const {
658
- collateralTokenAmount,
659
- } = await vesuAdapter.vesuAdapter.getAssetPrices();
660
- const { collateralPrice } = await this.getAssetPrices();
661
- const { vesuAmountInBTC, extendedAmountInBTC } = calculateVesUPositionSizeGivenExtended(
662
- extendedPositionValue,
663
- extendedHoldingAmount,
664
- collateralTokenAmount,
665
- collateralPrice.price
666
- );
667
- logger.info(`vesuAmountInBTC ${vesuAmountInBTC}, extendedAmountInBTC ${extendedAmountInBTC}`);
668
-
669
- let calls: Call[] = [];
670
- if (vesuAmountInBTC.greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
671
- const proofsInfo = vesuAdapter.getProofs(true, this.getMerkleTree());
672
- const proofGroups = proofsInfo.proofs;
673
- const call = this.getManageCall(
674
- proofGroups,
675
- await proofsInfo.callConstructor({
676
- amount: vesuAmountInBTC,
677
- })
678
- );
679
- const { amount: wbtcAmountInVaultAllocator } = await this.getUnusedBalanceWBTC();
680
- if (wbtcAmountInVaultAllocator.lessThan(vesuAmountInBTC)) {
681
- logger.info(`WBTC amount in vault allocator is less than vesu amount required in WBTC thus swapping, wbtcAmountInVaultAllocator: ${wbtcAmountInVaultAllocator}, vesuAmountInBTC: ${vesuAmountInBTC}`);
682
- const swapProofsInfo = avnuAdapter.getProofs(true, this.getMerkleTree());
683
- const swapProofGroups = swapProofsInfo.proofs;
684
- const swapCall = this.getManageCall(
685
- swapProofGroups,
686
- await swapProofsInfo.callConstructor({
687
- amount: vesuAmountInBTC,
688
- })
689
- );
690
- calls.push(swapCall);
691
- }
692
- calls.push(call);
693
- }
694
-
695
- const shortPosition = extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE) ? await extendedAdapter.createOrder(
696
- extendedLeverage.toString(),
697
- extendedAmountInBTC.toNumber(),
698
- OrderSide.SELL
699
- ) : null;
700
- if (!shortPosition && extendedAmountInBTC.multipliedBy(3).abs().greaterThan(MINIMUM_EXTENDED_POSITION_SIZE)) {
701
- logger.error(`error creating short position thus no position to be opened on vesu: ${shortPosition}`);
702
- return {
703
- extendedAmountInBTC: new Web3Number(0, 0),
704
- calls: [],
705
- };
706
- }
707
- return {
708
- extendedAmountInBTC: extendedAmountInBTC,
709
- calls: calls,
710
- };
933
+ /**
934
+ * Just a demo function, not used in the risk engine
935
+ */
936
+ return this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.VAULT.name, amount: new Web3Number(0, 0) }, "NONE", CycleType.INVESTMENT);
711
937
  } catch (err) {
712
938
  logger.error(`error handling deposit: ${err}`);
713
- return {
714
- extendedAmountInBTC: new Web3Number(0, 0),
715
- calls: [],
716
- };;
939
+ return this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.VAULT.name, amount: new Web3Number(0, 0) }, "NONE", CycleType.INVESTMENT);
717
940
  }
718
941
  }
719
942
 
720
- async checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter: ExtendedAdapter, vesuAdapter: VesuMultiplyAdapter, avnuAdapter: AvnuAdapter): Promise<boolean> {
943
+
944
+ /**
945
+ * Check if the price difference between avnu and extended is within the acceptable range to enhance the position size or close the position
946
+ * @param extendedAdapter - the extended adapter
947
+ * @param vesuAdapter - the vesu adapter
948
+ * @param avnuAdapter - the avnu adapter
949
+ * @param positionType - the position type (open or close)
950
+ * @returns true if the price difference is within the acceptable range, false otherwise
951
+ */
952
+ async checkPriceDifferenceBetweenAvnuAndExtended(extendedAdapter: ExtendedAdapter, vesuAdapter: VesuMultiplyAdapter, avnuAdapter: AvnuAdapter, positionType: PositionTypeAvnuExtended): Promise<boolean> {
721
953
  const {
722
954
  ask, bid
723
955
  } = await extendedAdapter.fetchOrderBookBTCUSDC();
724
956
  const price = ask.plus(bid).dividedBy(2);
725
957
  const btcToken = vesuAdapter.config.supportedPositions[0].asset;
726
958
  const btcPriceAvnu = await avnuAdapter.getPriceOfToken(btcToken.address.toString());
959
+
727
960
  if (!btcPriceAvnu) {
728
961
  logger.error(`error getting btc price avnu: ${btcPriceAvnu}`);
729
962
  return false;
730
963
  }
731
- const priceDifference = price.minus(btcPriceAvnu).toNumber();
732
- if (priceDifference < MAX_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED && priceDifference > MIN_PRICE_DIFFERENCE_BETWEEN_AVNU_AND_EXTENDED) {
733
- return true;
964
+ logger.info(`price: ${price}`);
965
+ logger.info(`btcPriceAvnu: ${btcPriceAvnu}`);
966
+ const priceDifference = new Web3Number(price.minus(btcPriceAvnu).toFixed(2), 0);
967
+ logger.info(`priceDifference: ${priceDifference}`);
968
+ if (priceDifference.isNegative()) {
969
+ return false;
970
+ }
971
+ if (positionType === PositionTypeAvnuExtended.OPEN) {
972
+ logger.info(`price difference between avnu and extended for open position: ${priceDifference.toNumber()}, minimumExtendedPriceDifferenceForSwapOpen: ${avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen}`);
973
+ const result = priceDifference.greaterThanOrEqualTo(avnuAdapter.config.minimumExtendedPriceDifferenceForSwapOpen); // 500 for now
974
+ logger.info(`result: ${result}`);
975
+ return result;
976
+ } else {
977
+ logger.info(`price difference between avnu and extended for close position: ${priceDifference.toNumber()}, maximumExtendedPriceDifferenceForSwapClosing: ${avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing}`);
978
+ const result = priceDifference.lessThanOrEqualTo(avnuAdapter.config.maximumExtendedPriceDifferenceForSwapClosing); // 1000 for now
979
+ logger.info(`result: ${result}`);
980
+ return result;
734
981
  }
735
- logger.error(`price difference between avnu and extended doesn't fit the range, priceDifference: ${priceDifference}`);
736
- return false;
737
982
  }
738
983
 
739
- async handleWithdraw(amount: Web3Number): Promise<{calls: Call[], status: boolean}> {
984
+ /**
985
+ * Handle the withdrawal of assets from the vault
986
+ * @param amount - the amount to withdraw in USDC
987
+ * @returns the calls to be executed and the status of the calls generated along with the metadata for the calls
988
+ */
989
+ async handleWithdraw(amount: Web3Number): Promise<TransactionResult[]> {
740
990
  try {
741
- const usdcBalanceVaultAllocator = await this.getUnusedBalance()
991
+ const usdcBalanceVaultAllocator = await this.getUnusedBalance();
742
992
  const usdcBalanceDifference = amount.plus(BUFFER_USDC_IN_WITHDRAWAL).minus(usdcBalanceVaultAllocator.usdValue);
743
993
  logger.info(`usdcBalanceDifference, ${usdcBalanceDifference.toNumber()}`);
744
994
  let calls: Call[] = [];
@@ -747,12 +997,8 @@ export class VesuExtendedMultiplierStrategy<
747
997
  const withdrawCall = await this.getBringLiquidityCall({
748
998
  amount: usdcBalanceVaultAllocator.amount
749
999
  })
750
- logger.info("withdraw call", withdrawCall);
751
1000
  calls.push(withdrawCall);
752
- return {
753
- calls:calls,
754
- status:true
755
- };
1001
+ return [this.createTransactionResult(calls, true, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount: amount }, "WITHDRAWAL", CycleType.WITHDRAWAL)];
756
1002
  }
757
1003
  const vesuAdapter = await this.getVesuAdapter();
758
1004
  const extendedAdapter = await this.getExtendedAdapter();
@@ -761,24 +1007,19 @@ export class VesuExtendedMultiplierStrategy<
761
1007
  logger.error(
762
1008
  `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
763
1009
  );
764
- return {
765
- calls:calls,
766
- status:status
767
- };
1010
+ return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount: amount }, "NONE", CycleType.WITHDRAWAL)];
768
1011
  }
1012
+ let transactionResults: TransactionResult[] = [];
769
1013
  const { collateralTokenAmount } =
770
1014
  await vesuAdapter.vesuAdapter.getAssetPrices();
771
1015
  const {
772
1016
  collateralPrice
773
1017
  } = await this.getAssetPrices();
774
1018
  const extendedPositon = await extendedAdapter.getAllOpenPositions();
775
- if(!extendedPositon) {
1019
+ if (!extendedPositon) {
776
1020
  status = false;
777
1021
  logger.error("error getting extended position", extendedPositon);
778
- return {
779
- calls:calls,
780
- status:status
781
- }
1022
+ return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount: amount }, "NONE", CycleType.WITHDRAWAL)];
782
1023
  }
783
1024
  const amountDistributionForWithdrawal =
784
1025
  await calculateAmountDistributionForWithdrawal(
@@ -792,62 +1033,71 @@ export class VesuExtendedMultiplierStrategy<
792
1033
  logger.error(
793
1034
  `error calculating amount distribution for withdrawal: ${amountDistributionForWithdrawal}`
794
1035
  );
795
- return {
796
- calls:calls,
797
- status:status
798
- };
1036
+ return [this.createTransactionResult(calls, status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount: amount }, "NONE", CycleType.WITHDRAWAL)];
799
1037
  }
800
1038
  const { vesu_amount, extended_amount } = amountDistributionForWithdrawal;
801
-
1039
+
802
1040
  if (status && vesu_amount.greaterThan(0)) {
803
- const {calls: vesuCalls, status: vesuStatus} = await this.moveAssets(
1041
+ const { calls: vesuCalls, status: vesuStatus, transactionMetadata: vesuTransactionMetadata } = await this.moveAssets(
804
1042
  {
805
1043
  amount: vesu_amount,
806
1044
  from: Protocols.VESU.name,
807
1045
  to: Protocols.VAULT.name,
1046
+ cycleType: CycleType.WITHDRAWAL
808
1047
  },
809
1048
  extendedAdapter,
810
1049
  vesuAdapter
811
1050
  );
812
1051
  status = vesuStatus;
813
- calls.push(...vesuCalls);
1052
+ transactionResults.push({
1053
+ status: vesuStatus,
1054
+ calls: vesuCalls,
1055
+ transactionMetadata: vesuTransactionMetadata
1056
+ })
814
1057
  }
815
1058
  if (status && extended_amount.greaterThan(0)) {
816
- const {calls: extendedCalls, status: extendedStatus} = await this.moveAssets(
1059
+ const { calls: extendedCalls, status: extendedStatus, transactionMetadata: extendedTransactionMetadata } = await this.moveAssets(
817
1060
  {
818
1061
  amount: extended_amount,
819
1062
  from: Protocols.EXTENDED.name,
820
1063
  to: Protocols.VAULT.name,
1064
+ cycleType: CycleType.WITHDRAWAL
821
1065
  },
822
1066
  extendedAdapter,
823
1067
  vesuAdapter
824
1068
  );
825
1069
  status = extendedStatus;
826
- if(status) {
827
- calls.push(...extendedCalls);
828
- }else{
1070
+ if (status) {
1071
+ transactionResults.push({
1072
+ status: extendedStatus,
1073
+ calls: extendedCalls,
1074
+ transactionMetadata: extendedTransactionMetadata
1075
+ })
1076
+ } else {
829
1077
  logger.error("error moving assets to vault: extendedStatus: ${extendedStatus}");
830
- return {
831
- calls: [],
832
- status: status
833
- };
1078
+ return [this.createTransactionResult([], status, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount: amount }, "NONE", CycleType.WITHDRAWAL)];
834
1079
  }
835
1080
  }
836
1081
  const withdrawCall = await this.getBringLiquidityCall({
837
1082
  amount: amount
838
1083
  })
839
1084
  logger.info("withdraw call", withdrawCall);
840
- calls.push(withdrawCall);
841
- return {
842
- calls: calls,
843
- status: status
844
- };
1085
+ transactionResults.push({
1086
+ status: status,
1087
+ calls: [withdrawCall],
1088
+ transactionMetadata: {
1089
+ protocolFrom: Protocols.VAULT.name,
1090
+ protocolTo: Protocols.NONE.name,
1091
+ transactionType: "WITHDRAWAL",
1092
+ usdAmount: amount.toFixed(),
1093
+ status: 'PENDING',
1094
+ cycleType: CycleType.WITHDRAWAL
1095
+ }
1096
+ })
1097
+ return transactionResults;
845
1098
  } catch (err) {
846
1099
  logger.error(`error handling withdrawal: ${err}`);
847
- return {
848
- calls: [],
849
- status: false
850
- };
1100
+ return [this.createTransactionResult([], false, { from: Protocols.VAULT.name, to: Protocols.NONE.name, amount: amount }, "NONE", CycleType.WITHDRAWAL)];
851
1101
  }
852
1102
  }
853
1103
 
@@ -896,6 +1146,187 @@ export class VesuExtendedMultiplierStrategy<
896
1146
  };
897
1147
  }
898
1148
 
1149
+ async processTransactionDataFromSDK(txnData: TransactionResult<any>[]): Promise<{ callsToBeExecutedFinal: Call[], txnMetadata: TransactionMetadata[] } | null> {
1150
+ try {
1151
+ const txnsToBeExecuted = txnData.filter(txn => {
1152
+ return txn.transactionMetadata.transactionType !== 'NONE' && txn.transactionMetadata.protocolFrom !== "" && txn.transactionMetadata.protocolTo !== "";
1153
+ })
1154
+ const callsToBeExecutedFinal = txnsToBeExecuted.flatMap(txn => txn.calls);
1155
+ const txnMetadata = txnsToBeExecuted.map(txn => txn.transactionMetadata);
1156
+ return { callsToBeExecutedFinal, txnMetadata };
1157
+ } catch (err) {
1158
+ logger.error(`error processing transaction data from SDK: ${err}`);
1159
+ return null;
1160
+ }
1161
+ }
1162
+
1163
+ async processTransactionMetadata(txnMetadata: TransactionMetadata[], extendedIntentFulfilled: boolean): Promise<TransactionMetadata[] | null> {
1164
+ try {
1165
+ const txnMetadataNew = txnMetadata.map(txn => {
1166
+ const isExtendedProtocol = txn.protocolFrom === Protocols.EXTENDED.name || txn.protocolTo === Protocols.EXTENDED.name;
1167
+ // Only update status for extended protocol transactions since thsoe only cause delays
1168
+ if (isExtendedProtocol) {
1169
+ txn.status = extendedIntentFulfilled ? 'COMPLETED' : 'PENDING';
1170
+ } else {
1171
+ txn.status = 'COMPLETED';
1172
+ }
1173
+ return txn;
1174
+ })
1175
+ return txnMetadataNew;
1176
+ } catch (err) {
1177
+ logger.error(`error processing transaction data from SDK: ${err}`);
1178
+ return null;
1179
+ }
1180
+ }
1181
+
1182
+ async getMaxBorrowableAmount(): Promise<Web3Number> {
1183
+ const vesuAdapter = await this.getVesuAdapter();
1184
+ const extendedAdapter = await this.getExtendedAdapter();
1185
+ if (!vesuAdapter || !extendedAdapter) {
1186
+ return new Web3Number(0, 0);
1187
+ }
1188
+ const extendedFundingRate = new Web3Number((await extendedAdapter.getNetAPY()).toFixed(4), 0);
1189
+ const extendedPositions = await extendedAdapter.getAllOpenPositions();
1190
+ if (!extendedPositions || extendedPositions.length === 0) {
1191
+ logger.info(`no extended positions found`);
1192
+ return new Web3Number(0, 0);
1193
+ }
1194
+ const extendePositionSizeUSD = new Web3Number(extendedPositions[0].value || 0, 0);
1195
+ const vesuPositions = await vesuAdapter.getPositions();
1196
+ const vesuSupplyApy = vesuPositions[0].apy.apy;
1197
+ const vesuCollateralSizeUSD = new Web3Number(vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
1198
+ const vesuDebtSizeUSD = new Web3Number(vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS)
1199
+ const num1 = extendePositionSizeUSD.multipliedBy(extendedFundingRate);
1200
+ const num2 = vesuCollateralSizeUSD.multipliedBy(vesuSupplyApy);
1201
+ const num3 = vesuDebtSizeUSD.abs()
1202
+ const maxBorrowApy = num1.plus(num2).minus(0.1).dividedBy(num3);
1203
+ const vesuMaxBorrowableAmount = await vesuAdapter.vesuAdapter.getMaxBorrowableByInterestRate(this.config, vesuAdapter.config.debt, maxBorrowApy.toNumber());
1204
+ return new Web3Number(vesuMaxBorrowableAmount.toFixed(USDC_TOKEN_DECIMALS), USDC_TOKEN_DECIMALS);
1205
+ }
1206
+
1207
+ async getVesuHealthFactors(): Promise<number[]> {
1208
+ const vesuAdapter = await this.getVesuAdapter();
1209
+ const extendedAdapter = await this.getExtendedAdapter();
1210
+ if (!vesuAdapter || !extendedAdapter) {
1211
+ return [0, 0];
1212
+ }
1213
+ const vesuPositions = await vesuAdapter.getPositions();
1214
+ const vesuCollateralSizeUSD = new Web3Number(vesuPositions[0].usdValue.toFixed(USDC_TOKEN_DECIMALS), 0);
1215
+ const vesuDebtSizeUSD = new Web3Number(vesuPositions[1].usdValue.toFixed(USDC_TOKEN_DECIMALS), 0);
1216
+ const actualLtv = vesuDebtSizeUSD.dividedBy(vesuCollateralSizeUSD).abs();
1217
+ logger.info(`actualLtv: ${actualLtv.toNumber()}`);
1218
+ const maxLtv = new Web3Number(await vesuAdapter.vesuAdapter.getLTVConfig(this.config), 4);
1219
+ const healthFactor = new Web3Number(maxLtv.dividedBy(actualLtv).toFixed(4), 4);
1220
+ logger.info(`healthFactor: ${healthFactor.toNumber()}`);
1221
+ const extendedBalance = await extendedAdapter.getExtendedDepositAmount();
1222
+ if (!extendedBalance) {
1223
+ return [0, 0];
1224
+ }
1225
+ const extendedLeverage = new Web3Number((Number(extendedBalance.marginRatio) * 100).toFixed(4), 4);
1226
+ logger.info(`extendedLeverage: ${extendedLeverage.toNumber()}`);
1227
+ return [healthFactor.toNumber(), extendedLeverage.toNumber()];
1228
+ }
1229
+
1230
+ async netAPY(): Promise<{ net: number; splits: { apy: number; id: string; }[]; }> {
1231
+ const allPositions: PositionInfo[] = [];
1232
+ for (let adapter of this.metadata.additionalInfo.adapters) {
1233
+ if(adapter.adapter.name !== ExtendedAdapter.name){
1234
+ let positions = await adapter.adapter.getPositions();
1235
+ if(positions.length > 0){
1236
+ allPositions.push(...positions);
1237
+ }
1238
+ }
1239
+ }
1240
+ const extendedAdapter =await this.getExtendedAdapter()
1241
+ if(!extendedAdapter){
1242
+ return {
1243
+ net: 0,
1244
+ splits: []
1245
+ }
1246
+ }
1247
+ let vesuPositions = allPositions.filter((item) => item.protocol === Protocols.VESU);
1248
+ vesuPositions.map((item) =>{
1249
+ item.apy.apy = item.apy.apy * 0.1;
1250
+ })
1251
+ const extendedPositions = await extendedAdapter.getAllOpenPositions();
1252
+ const usdcToken = Global.getDefaultTokens().find(token => token.symbol === "USDC");
1253
+ if(!extendedPositions || !usdcToken){
1254
+ return {
1255
+ net: 0,
1256
+ splits: []
1257
+ }
1258
+ }
1259
+ const extendedPosition = extendedPositions[0] || 0;
1260
+ const extendedEquity = (await extendedAdapter.getExtendedDepositAmount())?.equity || 0;
1261
+ const extendedApy = await extendedAdapter.getNetAPY();
1262
+ const totalHoldingsUSDValue = allPositions.reduce((acc, curr) => acc + curr.usdValue, 0) + Number(extendedEquity);
1263
+ console.log(totalHoldingsUSDValue)
1264
+ const extendedPositionSizeMultipliedByApy = Number(extendedPosition.value) * extendedApy;
1265
+ let weightedAPYs = allPositions.reduce((acc, curr) => acc + curr.apy.apy * curr.usdValue, 0) + extendedPositionSizeMultipliedByApy;
1266
+ console.log(weightedAPYs)
1267
+ const netAPY = weightedAPYs / totalHoldingsUSDValue;
1268
+ console.log(netAPY)
1269
+ allPositions.push({
1270
+ tokenInfo: usdcToken,
1271
+ amount: new Web3Number(extendedPosition.size, 0),
1272
+ usdValue: Number(extendedEquity),
1273
+ apy: { apy: extendedApy, type: APYType.BASE },
1274
+ remarks: AUMTypes.FINALISED,
1275
+ protocol: Protocols.EXTENDED
1276
+ })
1277
+ return {
1278
+ net: netAPY,
1279
+ splits: allPositions.map(p => ({apy: p.apy.apy, id: p.remarks ?? ''}))
1280
+ };
1281
+ }
1282
+
1283
+ async getWalletHoldings(): Promise<{
1284
+ tokenInfo: TokenInfo,
1285
+ amount: Web3Number,
1286
+ usdValue: number
1287
+ }[]> {
1288
+ const usdceToken = Global.getDefaultTokens().find(token => token.symbol === "USDCe");
1289
+ const wbtcToken = Global.getDefaultTokens().find(token => token.symbol === "WBTC");
1290
+ const usdcToken = Global.getDefaultTokens().find(token => token.symbol === "USDC");
1291
+ if (!usdceToken || !wbtcToken || !usdcToken) {
1292
+ return [];
1293
+ }
1294
+ const walletAddress = this.metadata.additionalInfo.walletAddress;
1295
+ const usdceWalletBalance = await new ERC20(this.config).balanceOf(
1296
+ usdceToken.address,
1297
+ walletAddress,
1298
+ usdceToken.decimals
1299
+ );
1300
+ const usdcWalletBalance = await new ERC20(this.config).balanceOf(
1301
+ usdcToken.address,
1302
+ walletAddress,
1303
+ usdcToken.decimals
1304
+ );
1305
+ const wbtcWalletBalance = await new ERC20(this.config).balanceOf(
1306
+ wbtcToken.address,
1307
+ walletAddress,
1308
+ wbtcToken.decimals
1309
+ );
1310
+ const price = await this.pricer.getPrice(usdceToken.symbol);
1311
+ const wbtcPrice = await this.pricer.getPrice(wbtcToken.symbol);
1312
+ const usdceUsdValue = Number(usdceWalletBalance.toFixed(usdceToken.decimals)) * price.price;
1313
+ const usdcUsdValue = Number(usdcWalletBalance.toFixed(usdcToken.decimals)) * price.price;
1314
+ const wbtcUsdValue = Number(wbtcWalletBalance.toFixed(wbtcToken.decimals)) * wbtcPrice.price;
1315
+ return [{
1316
+ tokenInfo: usdceToken,
1317
+ amount: usdceWalletBalance,
1318
+ usdValue: usdceUsdValue
1319
+ },
1320
+ {
1321
+ tokenInfo: usdcToken,
1322
+ amount: usdcWalletBalance,
1323
+ usdValue: usdcUsdValue
1324
+ }, {
1325
+ tokenInfo: wbtcToken,
1326
+ amount: wbtcWalletBalance,
1327
+ usdValue: wbtcUsdValue
1328
+ }];
1329
+ }
899
1330
  }
900
1331
 
901
1332
  function getLooperSettings(
@@ -903,9 +1334,14 @@ function getLooperSettings(
903
1334
  underlyingSymbol: string,
904
1335
  vaultSettings: VesuExtendedStrategySettings,
905
1336
  pool1: ContractAddr,
906
- extendedBackendUrl: string,
907
- extendedApiKey: string,
1337
+ extendedBackendReadUrl: string,
1338
+ extendedBackendWriteUrl: string,
908
1339
  vaultIdExtended: number,
1340
+ minimumExtendedMovementAmount: number,
1341
+ minimumVesuMovementAmount: number,
1342
+ minimumExtendedRetriesDelayForOrderStatus: number,
1343
+ minimumExtendedPriceDifferenceForSwapOpen: number,
1344
+ maximumExtendedPriceDifferenceForSwapClosing: number,
909
1345
  ) {
910
1346
  vaultSettings.leafAdapters = [];
911
1347
 
@@ -934,6 +1370,8 @@ function getLooperSettings(
934
1370
  avnuContract: AVNU_MIDDLEWARE,
935
1371
  slippage: 0.01,
936
1372
  baseUrl: AVNU_QUOTE_URL,
1373
+ minimumExtendedPriceDifferenceForSwapOpen: minimumExtendedPriceDifferenceForSwapOpen,
1374
+ maximumExtendedPriceDifferenceForSwapClosing: maximumExtendedPriceDifferenceForSwapClosing,
937
1375
  });
938
1376
 
939
1377
  const extendedAdapter = new ExtendedAdapter({
@@ -943,14 +1381,16 @@ function getLooperSettings(
943
1381
  ],
944
1382
  vaultIdExtended: vaultIdExtended,
945
1383
  extendedContract: EXTENDED_CONTRACT,
946
- extendedBackendUrl: extendedBackendUrl,
947
- extendedApiKey: extendedApiKey,
1384
+ extendedBackendWriteUrl: extendedBackendWriteUrl,
1385
+ extendedBackendReadUrl: extendedBackendReadUrl,
948
1386
  extendedTimeout: 30000,
949
1387
  extendedRetries: 3,
950
1388
  extendedBaseUrl: "https://api.starknet.extended.exchange",
951
1389
  extendedMarketName: "BTC-USD",
952
1390
  extendedPrecision: 5,
953
1391
  avnuAdapter: avnuAdapter,
1392
+ retryDelayForOrderStatus: minimumExtendedRetriesDelayForOrderStatus ?? 3000,
1393
+ minimumExtendedMovementAmount: minimumExtendedMovementAmount ?? 5, //5 usdcs
954
1394
  });
955
1395
 
956
1396
  const vesuMultiplyAdapter = new VesuMultiplyAdapter({
@@ -965,6 +1405,7 @@ function getLooperSettings(
965
1405
  { asset: wbtcToken, isDebt: false },
966
1406
  { asset: usdcToken, isDebt: true },
967
1407
  ],
1408
+ minimumVesuMovementAmount: minimumVesuMovementAmount ?? 5, //5 usdc
968
1409
  });
969
1410
 
970
1411
  const unusedBalanceAdapter = new UnusedBalanceAdapter({
@@ -1007,7 +1448,6 @@ function getLooperSettings(
1007
1448
  vaultSettings.leafAdapters.push(() => extendedAdapter.getSwapFromLegacyLeaf());
1008
1449
  vaultSettings.leafAdapters.push(() => avnuAdapter.getDepositLeaf());
1009
1450
  vaultSettings.leafAdapters.push(() => avnuAdapter.getWithdrawLeaf());
1010
- // Doubt here, should this be usdcToken.address, or wbtcToken.address?
1011
1451
  vaultSettings.leafAdapters.push(
1012
1452
  commonAdapter
1013
1453
  .getApproveAdapter(
@@ -1078,11 +1518,11 @@ export default function VaultDescription(
1078
1518
  }
1079
1519
 
1080
1520
  const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
1081
- vaultAddress: ContractAddr.from("0x520a2e945dd0762e5284fc1b012f62ca04e238e105eb362d5e0ce208928729d"),
1082
- manager: ContractAddr.from("0x6abe24d31cbc16d7c4acb2421a826f96273e225b4a2d168d91e65123da0bfb9"),
1083
- vaultAllocator: ContractAddr.from("0x6e4f716e22efb164ee4a831233e513f45396ad3be4cff3c07386be0226febed"),
1084
- redeemRequestNFT: ContractAddr.from("0x66060e1874e05506b18e6029188ec49bf231a411ad57642311bbdf3cb22e5f"),
1085
- aumOracle: ContractAddr.from("0x301d883b9b45c76132638e39326b3f464c492599623263d405ec0df991e27ab"),
1521
+ vaultAddress: ContractAddr.from("0x058905be22d6a81792df79425dc9641cf3e1b77f36748631b7d7e5d713a32b55"),
1522
+ manager: ContractAddr.from("0x02648d703783feb2d967cf0520314cb5aa800d69a9426f3e3b317395af44de16"),
1523
+ vaultAllocator: ContractAddr.from("0x07d533c838eab6a4d854dd3aea96a55993fccd35821921970d00bde946b63b6f"),
1524
+ redeemRequestNFT: ContractAddr.from("0x01ef91f08fb99729c00f82fc6e0ece37917bcc43952596c19996259dc8adbbba"),
1525
+ aumOracle: ContractAddr.from("0x030b6acfec162f5d6e72b8a4d2798aedce78fb39de78a8f549f7cd277ae8bc8d"),
1086
1526
  leafAdapters: [],
1087
1527
  adapters: [],
1088
1528
  targetHealthFactor: 1.4,
@@ -1096,17 +1536,18 @@ const re7UsdcPrimeDevansh: VesuExtendedStrategySettings = {
1096
1536
  ),
1097
1537
  borrowable_assets: [Global.getDefaultTokens().find(token => token.symbol === "WBTC")!],
1098
1538
  minimumWBTCDifferenceForAvnuSwap: MINIMUM_WBTC_DIFFERENCE_FOR_AVNU_SWAP,
1539
+ walletAddress: WALLET_ADDRESS,
1099
1540
  }
1100
1541
 
1101
- export const VesuExtendedTestStrategies = (extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
1542
+ export const VesuExtendedTestStrategies = (extendedBackendReadUrl: string, extendedBackendWriteUrl: string, vaultIdExtended: number, minimumExtendedMovementAmount: number, minimumVesuMovementAmount: number, minimumExtendedRetriesDelayForOrderStatus: number, minimumExtendedPriceDifferenceForSwapOpen: number, maximumExtendedPriceDifferenceForSwapClosing: number): IStrategyMetadata<VesuExtendedStrategySettings>[] => {
1102
1543
  return [
1103
- getStrategySettingsVesuExtended('WBTC', 'USDC', re7UsdcPrimeDevansh, false, false, extendedBackendUrl, extendedApiKey, vaultIdExtended),
1544
+ getStrategySettingsVesuExtended('WBTC', 'USDC', re7UsdcPrimeDevansh, false, false, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing),
1104
1545
  ]
1105
1546
  }
1106
1547
 
1107
1548
 
1108
1549
 
1109
- function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: string, addresses: VesuExtendedStrategySettings, isPreview: boolean = false, isLST: boolean, extendedBackendUrl: string, extendedApiKey: string, vaultIdExtended: number): IStrategyMetadata<VesuExtendedStrategySettings> {
1550
+ function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: string, addresses: VesuExtendedStrategySettings, isPreview: boolean = false, isLST: boolean, extendedBackendReadUrl: string, extendedBackendWriteUrl: string, vaultIdExtended: number, minimumExtendedMovementAmount: number, minimumVesuMovementAmount: number, minimumExtendedRetriesDelayForOrderStatus: number, minimumExtendedPriceDifferenceForSwapOpen: number, maximumExtendedPriceDifferenceForSwapClosing: number): IStrategyMetadata<VesuExtendedStrategySettings> {
1110
1551
  return {
1111
1552
  name: `Extended Test ${underlyingSymbol}`,
1112
1553
  description: getDescription(lstSymbol, underlyingSymbol),
@@ -1114,7 +1555,7 @@ function getStrategySettingsVesuExtended(lstSymbol: string, underlyingSymbol: st
1114
1555
  launchBlock: 0,
1115
1556
  type: 'Other',
1116
1557
  depositTokens: [Global.getDefaultTokens().find(token => token.symbol === underlyingSymbol)!],
1117
- additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendUrl, extendedApiKey, vaultIdExtended),
1558
+ additionalInfo: getLooperSettings(lstSymbol, underlyingSymbol, addresses, VesuPools.Re7USDCPrime, extendedBackendReadUrl, extendedBackendWriteUrl, vaultIdExtended, minimumExtendedMovementAmount, minimumVesuMovementAmount, minimumExtendedRetriesDelayForOrderStatus, minimumExtendedPriceDifferenceForSwapOpen, maximumExtendedPriceDifferenceForSwapClosing),
1118
1559
  risk: {
1119
1560
  riskFactor: _riskFactor,
1120
1561
  netRisk: