@strkfarm/sdk 2.0.0-dev.7 → 2.0.0-dev.8

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.
@@ -218,11 +218,42 @@ export class VesuExtendedMultiplierStrategy<
218
218
  vesuLeverage: number;
219
219
  }> {
220
220
  try {
221
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest starting`);
221
222
  const vesuAdapter = await this.getVesuAdapter();
222
223
  const extendedAdapter = await this.getExtendedAdapter();
223
- if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
224
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest adapters fetched: vesuAdapter=${!!vesuAdapter}, extendedAdapter=${!!extendedAdapter}, extendedAdapter.client=${!!extendedAdapter?.client}`);
225
+
226
+ if (!vesuAdapter) {
224
227
  logger.error(
225
- `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
228
+ `Vesu adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
229
+ );
230
+ return {
231
+ shouldInvest: false,
232
+ vesuAmount: new Web3Number(0, 0),
233
+ extendedAmount: new Web3Number(0, 0),
234
+ extendedLeverage: 0,
235
+ collateralPrice: 0,
236
+ debtPrice: 0,
237
+ vesuLeverage: 0,
238
+ };
239
+ }
240
+ if (!extendedAdapter) {
241
+ logger.error(
242
+ `Extended adapter not configured in metadata. This is a configuration issue, not a temporary failure.`
243
+ );
244
+ return {
245
+ shouldInvest: false,
246
+ vesuAmount: new Web3Number(0, 0),
247
+ extendedAmount: new Web3Number(0, 0),
248
+ extendedLeverage: 0,
249
+ collateralPrice: 0,
250
+ debtPrice: 0,
251
+ vesuLeverage: 0,
252
+ };
253
+ }
254
+ if (!extendedAdapter.client) {
255
+ logger.error(
256
+ `Extended adapter client not initialized. This may be a temporary initialization failure - check network connectivity and API availability.`
226
257
  );
227
258
  return {
228
259
  shouldInvest: false,
@@ -234,11 +265,65 @@ export class VesuExtendedMultiplierStrategy<
234
265
  vesuLeverage: 0,
235
266
  };
236
267
  }
268
+
269
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest calling getUnusedBalance`);
237
270
  const balance = await this.getUnusedBalance();
271
+
272
+ if (!Number.isFinite(balance.usdValue) || balance.usdValue < 0) {
273
+ logger.error(
274
+ `Invalid balance.usdValue: ${balance.usdValue}. Expected a finite, non-negative number.`
275
+ );
276
+ return {
277
+ shouldInvest: false,
278
+ vesuAmount: new Web3Number(0, 0),
279
+ extendedAmount: new Web3Number(0, 0),
280
+ extendedLeverage: 0,
281
+ collateralPrice: 0,
282
+ debtPrice: 0,
283
+ vesuLeverage: 0,
284
+ };
285
+ }
286
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest balance: ${balance.usdValue}`);
238
287
  const usdcBalanceOnExtended = await extendedAdapter.getExtendedDepositAmount();
288
+
289
+ if (usdcBalanceOnExtended) {
290
+ const availableForWithdrawal = parseFloat(usdcBalanceOnExtended.availableForWithdrawal);
291
+ if (!Number.isFinite(availableForWithdrawal) || availableForWithdrawal < 0) {
292
+ logger.error(
293
+ `Invalid usdcBalanceOnExtended.availableForWithdrawal: ${usdcBalanceOnExtended.availableForWithdrawal}. Expected a finite, non-negative number.`
294
+ );
295
+ return {
296
+ shouldInvest: false,
297
+ vesuAmount: new Web3Number(0, 0),
298
+ extendedAmount: new Web3Number(0, 0),
299
+ extendedLeverage: 0,
300
+ collateralPrice: 0,
301
+ debtPrice: 0,
302
+ vesuLeverage: 0,
303
+ };
304
+ }
305
+ }
306
+
239
307
  /** The LIMIT_BALANCE is the bffer amount to keep in the investing Cycle */
240
308
  const amountToInvest = new Web3Number(balance.usdValue, USDC_TOKEN_DECIMALS).plus(usdcBalanceOnExtended?.availableForWithdrawal ?? 0).multipliedBy(1 - LIMIT_BALANCE);
241
- logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvest.toNumber()}`);
309
+
310
+ const amountToInvestNumber = amountToInvest.toNumber();
311
+ if (!Number.isFinite(amountToInvestNumber)) {
312
+ logger.error(
313
+ `Invalid amountToInvest calculation result: ${amountToInvestNumber}. Calculation may have produced NaN or Infinity.`
314
+ );
315
+ return {
316
+ shouldInvest: false,
317
+ vesuAmount: new Web3Number(0, 0),
318
+ extendedAmount: new Web3Number(0, 0),
319
+ extendedLeverage: 0,
320
+ collateralPrice: 0,
321
+ debtPrice: 0,
322
+ vesuLeverage: 0,
323
+ };
324
+ }
325
+
326
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldInvest amountToInvest: ${amountToInvestNumber}`);
242
327
  if (amountToInvest.lessThan(0)) {
243
328
  return {
244
329
  shouldInvest: false,
@@ -271,6 +356,37 @@ export class VesuExtendedMultiplierStrategy<
271
356
  collateralPrice,
272
357
  debtPrice
273
358
  } = await this.getAssetPrices();
359
+
360
+
361
+ if (!Number.isFinite(collateralPrice.price) || collateralPrice.price <= 0) {
362
+ logger.error(
363
+ `Invalid collateralPrice: ${collateralPrice.price}. Expected a finite, positive number.`
364
+ );
365
+ return {
366
+ shouldInvest: false,
367
+ vesuAmount: new Web3Number(0, 0),
368
+ extendedAmount: new Web3Number(0, 0),
369
+ extendedLeverage: 0,
370
+ collateralPrice: 0,
371
+ debtPrice: 0,
372
+ vesuLeverage: 0,
373
+ };
374
+ }
375
+ if (!Number.isFinite(debtPrice.price) || debtPrice.price <= 0) {
376
+ logger.error(
377
+ `Invalid debtPrice: ${debtPrice.price}. Expected a finite, positive number.`
378
+ );
379
+ return {
380
+ shouldInvest: false,
381
+ vesuAmount: new Web3Number(0, 0),
382
+ extendedAmount: new Web3Number(0, 0),
383
+ extendedLeverage: 0,
384
+ collateralPrice: 0,
385
+ debtPrice: 0,
386
+ vesuLeverage: 0,
387
+ };
388
+ }
389
+
274
390
  const { vesu_amount, extended_amount, extended_leverage, vesu_leverage } =
275
391
  await calculateAmountDistribution(
276
392
  amountToInvest.toNumber(),
@@ -328,13 +444,64 @@ export class VesuExtendedMultiplierStrategy<
328
444
  try {
329
445
  const vesuAdapter = await this.getVesuAdapter();
330
446
  const extendedAdapter = await this.getExtendedAdapter();
331
- let calls: Call[] = [];
332
447
  if (!vesuAdapter || !extendedAdapter || !extendedAdapter.client) {
333
448
  logger.error(
334
449
  `vesu or extended adapter not found: vesuAdapter=${vesuAdapter}, extendedAdapter=${extendedAdapter}`
335
450
  );
336
- return calls;
451
+ return [];
452
+ }
453
+
454
+ const extendedHoldings = await extendedAdapter.getExtendedDepositAmount();
455
+ if (!extendedHoldings) {
456
+ logger.error(`error getting extended holdings: ${extendedHoldings}`);
457
+ return [];
458
+ }
459
+ const usdcAmountInWallet = (await this.getUnusedBalance()).amount;
460
+ const usdcAmountOnExtendedAvailableForWithdrawal = parseFloat(
461
+ extendedHoldings.availableForWithdrawal
462
+ );
463
+
464
+ logger.info(`${VesuExtendedMultiplierStrategy.name}::shouldMoveAssets calculating movements - Extended current: ${usdcAmountOnExtendedAvailableForWithdrawal}, Wallet: ${usdcAmountInWallet.toNumber()}, Target Extended: ${extendedAmount.toNumber()}, Target Vesu: ${vesuAmount.toNumber()}`);
465
+
466
+ let totalExtendedWithdrawal = new Web3Number(0, USDC_TOKEN_DECIMALS);
467
+ let totalExtendedDeposit = new Web3Number(0, USDC_TOKEN_DECIMALS);
468
+
469
+ if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
470
+ totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmount.abs());
337
471
  }
472
+
473
+ // Calculate remaining Extended difference (target vs current)
474
+ // If extendedAmount was negative, we've already accounted for that withdrawal
475
+ // So we calculate based on what Extended will be after that withdrawal
476
+ const extendedTargetAmount = extendedAmount.abs(); // Use absolute value as target
477
+ let projectedExtendedBalance = usdcAmountOnExtendedAvailableForWithdrawal;
478
+
479
+ if (extendedAmount.isNegative()) {
480
+ projectedExtendedBalance = projectedExtendedBalance - extendedAmount.abs().toNumber();
481
+ }
482
+
483
+ const extendedAmountDifference = extendedTargetAmount.minus(projectedExtendedBalance);
484
+ const extendedAmountDifferenceAbs = extendedAmountDifference.abs();
485
+
486
+ // Track additional Extended movements
487
+ if (extendedAmountDifference.lessThan(0)) {
488
+ totalExtendedWithdrawal = totalExtendedWithdrawal.plus(extendedAmountDifferenceAbs);
489
+ } else if (extendedAmountDifference.greaterThan(0)) {
490
+ totalExtendedDeposit = totalExtendedDeposit.plus(extendedAmountDifference);
491
+ }
492
+
493
+ const vesuTargetAmount = vesuAmount.abs();
494
+ const projectedWalletBalance = usdcAmountInWallet
495
+ .plus(totalExtendedWithdrawal)
496
+ .minus(totalExtendedDeposit);
497
+
498
+ let vesuAmountDifference = vesuTargetAmount.minus(projectedWalletBalance);
499
+ const vesuAmountDifferenceAbs = vesuAmountDifference.abs();
500
+
501
+ 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()}`);
502
+ let calls: Call[] = [];
503
+
504
+ // Handle negative extendedAmount (initial withdrawal needed)
338
505
  if (extendedAmount.isNegative() && extendedAmount.abs().greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
339
506
  try {
340
507
  const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
@@ -346,7 +513,6 @@ export class VesuExtendedMultiplierStrategy<
346
513
  extendedAdapter,
347
514
  vesuAdapter
348
515
  );
349
- //If withdrawal succesfull, then do further
350
516
  if (extendedStatus) {
351
517
  calls.push(...extendedCalls);
352
518
  } else {
@@ -357,7 +523,7 @@ export class VesuExtendedMultiplierStrategy<
357
523
  }
358
524
  }
359
525
 
360
- if (vesuAmount.isNegative() && vesuAmount.lessThan(vesuAdapter.minimumVesuMovementAmount)) {
526
+ if (vesuAmount.isNegative() && vesuAmount.abs().greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
361
527
  try {
362
528
  const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
363
529
  {
@@ -377,52 +543,83 @@ export class VesuExtendedMultiplierStrategy<
377
543
  }
378
544
  }
379
545
 
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(extendedAdapter.minimumExtendedMovementAmount)) {
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}`);
546
+ // Handle Extended adjustments based on calculated difference
547
+ if (extendedAmountDifferenceAbs.greaterThan(extendedAdapter.minimumExtendedMovementAmount)) {
548
+ if (extendedAmountDifference.greaterThan(0)) {
549
+ try {
550
+ const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
551
+ {
552
+ to: Protocols.EXTENDED.name,
553
+ from: Protocols.VAULT.name,
554
+ amount: extendedAmountDifference,
555
+ },
556
+ extendedAdapter,
557
+ vesuAdapter
558
+ );
559
+ if (extendedStatus) {
560
+ calls.push(...extendedCalls);
561
+ } else {
562
+ logger.error(`Failed to move assets to extended - operation returned false status`);
563
+ return [];
564
+ }
565
+ } catch (err) {
566
+ logger.error(`Failed moving assets to extended: ${err}`);
567
+ return [];
568
+ }
569
+ } else if (extendedAmountDifference.lessThan(0)) {
570
+ try {
571
+ const { calls: extendedCalls, status: extendedStatus } = await this.moveAssets(
572
+ {
573
+ to: Protocols.VAULT.name,
574
+ from: Protocols.EXTENDED.name,
575
+ amount: extendedAmountDifferenceAbs,
576
+ },
577
+ extendedAdapter,
578
+ vesuAdapter
579
+ );
580
+ if (extendedStatus) {
581
+ calls.push(...extendedCalls);
582
+ } else {
583
+ logger.error(`Failed to withdraw from extended - operation returned false status`);
584
+ return [];
585
+ }
586
+ } catch (err) {
587
+ logger.error(`Failed moving assets from extended to vault: ${err}`);
588
+ return [];
589
+ }
404
590
  }
405
591
  }
406
- if (vesuAmount.minus(usdcAmountInWallet).greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
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
592
+
593
+ // Handle Vesu adjustments based on calculated difference (already adjusted for Extended movements)
594
+ if (vesuAmountDifferenceAbs.greaterThan(vesuAdapter.minimumVesuMovementAmount)) {
595
+ if (vesuAmountDifference.lessThanOrEqualTo(0)) {
596
+ logger.warn(
597
+ `Vesu amount difference is negative or zero: ${vesuAmountDifference.toNumber()}. Skipping operation.`
417
598
  );
418
- if (!vesuStatus) {
599
+ } else {
600
+ // Move assets from Extended to Vault (which will then go to Vesu)
601
+ try {
602
+ const { calls: vesuCalls, status: vesuStatus } = await this.moveAssets(
603
+ {
604
+ to: Protocols.VAULT.name,
605
+ from: Protocols.EXTENDED.name,
606
+ amount: vesuAmountDifference,
607
+ },
608
+ extendedAdapter,
609
+ vesuAdapter
610
+ );
611
+ if (!vesuStatus) {
612
+ logger.error(`Failed to move assets to vesu - operation returned false status`);
613
+ return [];
614
+ }
615
+ calls.push(...vesuCalls);
616
+ } catch (err) {
617
+ logger.error(`Failed moving assets to vault: ${err}`);
419
618
  return [];
420
619
  }
421
- calls.push(...vesuCalls);
422
- } catch (err) {
423
- logger.error(`Failed moving assets to vault: ${err}`);
424
620
  }
425
621
  }
622
+
426
623
  return calls;
427
624
  } catch (err) {
428
625
  logger.error(`Failed moving assets to vesu: ${err}`);
@@ -443,6 +640,42 @@ export class VesuExtendedMultiplierStrategy<
443
640
  status: boolean;
444
641
  }> {
445
642
  try {
643
+ // Validate amount is positive before starting operations
644
+ if (params.amount.lessThanOrEqualTo(0)) {
645
+ logger.error(
646
+ `Invalid amount for moveAssets: ${params.amount.toNumber()}. Amount must be positive.`
647
+ );
648
+ return {
649
+ calls: [],
650
+ status: false
651
+ };
652
+ }
653
+
654
+ // Check minimum movement amounts before starting operations
655
+ const amountAbs = params.amount.abs();
656
+ if (params.from === Protocols.EXTENDED.name || params.to === Protocols.EXTENDED.name) {
657
+ if (amountAbs.lessThanOrEqualTo(extendedAdapter.minimumExtendedMovementAmount)) {
658
+ logger.warn(
659
+ `Amount ${amountAbs.toNumber()} is below minimum Extended movement amount ${extendedAdapter.minimumExtendedMovementAmount}. Skipping operation.`
660
+ );
661
+ return {
662
+ calls: [],
663
+ status: false
664
+ };
665
+ }
666
+ }
667
+ if (params.from === Protocols.VESU.name || params.to === Protocols.VESU.name) {
668
+ if (amountAbs.lessThanOrEqualTo(vesuAdapter.minimumVesuMovementAmount)) {
669
+ logger.warn(
670
+ `Amount ${amountAbs.toNumber()} is below minimum Vesu movement amount ${vesuAdapter.minimumVesuMovementAmount}. Skipping operation.`
671
+ );
672
+ return {
673
+ calls: [],
674
+ status: false
675
+ };
676
+ }
677
+ }
678
+
446
679
  const avnuAdapter = await this.getAvnuAdapter();
447
680
  if (!avnuAdapter) {
448
681
  logger.error(`avnu adapter not found: ${avnuAdapter}`);
@@ -503,12 +736,13 @@ export class VesuExtendedMultiplierStrategy<
503
736
  )
504
737
  if (!openLongPosition) {
505
738
  logger.error(`error opening long position: ${openLongPosition}`);
506
- return {
507
- calls: [],
508
- status: false
509
- };
510
739
  }
511
740
  await new Promise(resolve => setTimeout(resolve, 5000));
741
+ const updatedHoldings = await extendedAdapter.getExtendedDepositAmount();
742
+ if (!updatedHoldings || new Web3Number(updatedHoldings.availableForWithdrawal, USDC_TOKEN_DECIMALS).lessThan(params.amount.abs())) {
743
+ logger.error(`Insufficient balance after opening position. Available: ${updatedHoldings?.availableForWithdrawal}, Needed: ${params.amount.abs()}`);
744
+ return { calls: [], status: false };
745
+ }
512
746
  }
513
747
  const withdrawalFromExtended =
514
748
  await extendedAdapter.withdrawFromExtended(params.amount);