@gearbox-protocol/sdk 13.3.3 → 13.4.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/cjs/permissionless/utils/price-update/get-price-update-tx.js +3 -15
  2. package/dist/cjs/sdk/GearboxSDK.js +135 -20
  3. package/dist/cjs/sdk/accounts/AbstractCreditAccountsService.js +196 -340
  4. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +30 -35
  5. package/dist/cjs/sdk/accounts/multicall-utils.js +91 -0
  6. package/dist/cjs/sdk/base/BaseContract.js +26 -6
  7. package/dist/cjs/sdk/base/ChainContractsRegister.js +39 -2
  8. package/dist/cjs/sdk/base/Construct.js +15 -3
  9. package/dist/cjs/sdk/base/TokensMeta.js +23 -0
  10. package/dist/cjs/sdk/constants/address-provider.js +0 -22
  11. package/dist/cjs/sdk/core/AbstractAddressProviderContract.js +15 -0
  12. package/dist/cjs/sdk/market/MarketRegister.js +74 -3
  13. package/dist/cjs/sdk/market/credit/CreditFacadeV310Contract.js +6 -0
  14. package/dist/cjs/sdk/market/oracle/PriceOracleBaseContract.js +31 -50
  15. package/dist/cjs/sdk/market/pricefeeds/PriceFeedRef.js +16 -0
  16. package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +55 -12
  17. package/dist/cjs/sdk/options.js +30 -24
  18. package/dist/cjs/sdk/plugins/BasePlugin.js +24 -0
  19. package/dist/cjs/sdk/pools/AbstractPoolService.js +6 -0
  20. package/dist/cjs/sdk/router/AbstractRouterContract.js +4 -1
  21. package/dist/cjs/sdk/router/RouterV310Contract.js +20 -15
  22. package/dist/cjs/sdk/utils/AddressMap.js +53 -17
  23. package/dist/cjs/sdk/utils/AddressSet.js +9 -0
  24. package/dist/esm/permissionless/utils/price-update/get-price-update-tx.js +6 -20
  25. package/dist/esm/sdk/GearboxSDK.js +135 -20
  26. package/dist/esm/sdk/accounts/AbstractCreditAccountsService.js +204 -342
  27. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +30 -35
  28. package/dist/esm/sdk/accounts/multicall-utils.js +69 -0
  29. package/dist/esm/sdk/base/BaseContract.js +26 -6
  30. package/dist/esm/sdk/base/ChainContractsRegister.js +39 -2
  31. package/dist/esm/sdk/base/Construct.js +15 -3
  32. package/dist/esm/sdk/base/TokensMeta.js +23 -0
  33. package/dist/esm/sdk/constants/address-provider.js +0 -21
  34. package/dist/esm/sdk/core/AbstractAddressProviderContract.js +15 -0
  35. package/dist/esm/sdk/market/MarketRegister.js +74 -3
  36. package/dist/esm/sdk/market/credit/CreditFacadeV310Contract.js +6 -0
  37. package/dist/esm/sdk/market/oracle/PriceOracleBaseContract.js +31 -50
  38. package/dist/esm/sdk/market/pricefeeds/PriceFeedRef.js +16 -0
  39. package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +55 -12
  40. package/dist/esm/sdk/options.js +30 -24
  41. package/dist/esm/sdk/plugins/BasePlugin.js +24 -0
  42. package/dist/esm/sdk/pools/AbstractPoolService.js +6 -0
  43. package/dist/esm/sdk/router/AbstractRouterContract.js +4 -1
  44. package/dist/esm/sdk/router/RouterV310Contract.js +20 -15
  45. package/dist/esm/sdk/utils/AddressMap.js +53 -17
  46. package/dist/esm/sdk/utils/AddressSet.js +9 -0
  47. package/dist/types/permissionless/bindings/price-feed-store.d.ts +1 -2
  48. package/dist/types/permissionless/bindings/types.d.ts +0 -4
  49. package/dist/types/permissionless/utils/price-update/get-price-update-tx.d.ts +1 -3
  50. package/dist/types/sdk/GearboxSDK.d.ts +236 -34
  51. package/dist/types/sdk/accounts/AbstractCreditAccountsService.d.ts +92 -147
  52. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +14 -5
  53. package/dist/types/sdk/accounts/multicall-utils.d.ts +39 -0
  54. package/dist/types/sdk/accounts/types.d.ts +237 -40
  55. package/dist/types/sdk/base/BaseContract.d.ts +67 -6
  56. package/dist/types/sdk/base/ChainContractsRegister.d.ts +51 -2
  57. package/dist/types/sdk/base/Construct.d.ts +31 -0
  58. package/dist/types/sdk/base/PlaceholderContract.d.ts +3 -0
  59. package/dist/types/sdk/base/SDKConstruct.d.ts +10 -0
  60. package/dist/types/sdk/base/TokensMeta.d.ts +59 -2
  61. package/dist/types/sdk/base/types.d.ts +185 -25
  62. package/dist/types/sdk/chain/chains.d.ts +78 -18
  63. package/dist/types/sdk/chain/detectNetwork.d.ts +7 -0
  64. package/dist/types/sdk/constants/address-provider.d.ts +4 -3
  65. package/dist/types/sdk/core/AbstractAddressProviderContract.d.ts +23 -0
  66. package/dist/types/sdk/core/types.d.ts +46 -0
  67. package/dist/types/sdk/market/MarketRegister.d.ts +81 -0
  68. package/dist/types/sdk/market/adapters/PlaceholderAdapterContracts.d.ts +3 -0
  69. package/dist/types/sdk/market/credit/CreditFacadeV310Contract.d.ts +1 -0
  70. package/dist/types/sdk/market/oracle/PriceOracleBaseContract.d.ts +40 -50
  71. package/dist/types/sdk/market/oracle/types.d.ts +78 -59
  72. package/dist/types/sdk/market/pricefeeds/AbstractLPPriceFeed.d.ts +3 -0
  73. package/dist/types/sdk/market/pricefeeds/AbstractPriceFeed.d.ts +3 -0
  74. package/dist/types/sdk/market/pricefeeds/PriceFeedRef.d.ts +22 -2
  75. package/dist/types/sdk/market/pricefeeds/PriceFeedsRegister.d.ts +80 -16
  76. package/dist/types/sdk/market/pricefeeds/getRawPriceUpdates.d.ts +2 -2
  77. package/dist/types/sdk/market/pricefeeds/types.d.ts +75 -11
  78. package/dist/types/sdk/options.d.ts +13 -4
  79. package/dist/types/sdk/plugins/BasePlugin.d.ts +39 -0
  80. package/dist/types/sdk/plugins/types.d.ts +73 -43
  81. package/dist/types/sdk/pools/AbstractPoolService.d.ts +12 -0
  82. package/dist/types/sdk/pools/types.d.ts +75 -6
  83. package/dist/types/sdk/router/AbstractRouterContract.d.ts +21 -2
  84. package/dist/types/sdk/router/RouterV310Contract.d.ts +27 -15
  85. package/dist/types/sdk/router/types.d.ts +47 -70
  86. package/dist/types/sdk/types/state.d.ts +32 -3
  87. package/dist/types/sdk/utils/AddressMap.d.ts +61 -17
  88. package/dist/types/sdk/utils/AddressSet.d.ts +15 -0
  89. package/package.json +4 -2
@@ -1,4 +1,4 @@
1
- import { encodeFunctionData, getAddress, getContract } from "viem";
1
+ import { encodeFunctionData, getContract } from "viem";
2
2
  import {
3
3
  iBotListV310Abi,
4
4
  iCreditFacadeMulticallV310Abi
@@ -21,9 +21,17 @@ import {
21
21
  RAY,
22
22
  VERSION_RANGE_310
23
23
  } from "../constants/index.js";
24
+ import {
25
+ getRawPriceUpdates
26
+ } from "../market/index.js";
24
27
  import { assetsMap } from "../router/index.js";
25
- import { AddressMap } from "../utils/index.js";
28
+ import { AddressMap, AddressSet } from "../utils/index.js";
26
29
  import { simulateWithPriceUpdates } from "../utils/viem/index.js";
30
+ import {
31
+ extractPriceUpdates,
32
+ extractQuotaTokens,
33
+ mergePriceUpdates
34
+ } from "./multicall-utils.js";
27
35
  const COMPRESSORS = {
28
36
  [chains.Mainnet.id]: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023",
29
37
  [chains.Monad.id]: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023"
@@ -46,12 +54,8 @@ class AbstractCreditAccountService extends SDKConstruct {
46
54
  );
47
55
  }
48
56
  /**
49
- * Returns single credit account data, or undefined if it's not found
50
- * Performs all necessary price feed updates under the hood
51
- * @param account
52
- * @param blockNumber
53
- * @returns
54
- */
57
+ * {@inheritDoc ICreditAccountsService.getCreditAccountData}
58
+ **/
55
59
  async getCreditAccountData(account, blockNumber) {
56
60
  let raw;
57
61
  try {
@@ -70,10 +74,7 @@ class AbstractCreditAccountService extends SDKConstruct {
70
74
  if (raw.success) {
71
75
  return raw;
72
76
  }
73
- const { txs: priceUpdateTxs } = await this.getUpdateForAccount({
74
- creditManager: raw.creditManager,
75
- creditAccount: raw
76
- });
77
+ const { txs: priceUpdateTxs } = await this.getUpdateForAccount(raw);
77
78
  const [cad] = await simulateWithPriceUpdates(this.client, {
78
79
  priceUpdates: priceUpdateTxs,
79
80
  contracts: [
@@ -90,13 +91,8 @@ class AbstractCreditAccountService extends SDKConstruct {
90
91
  return cad;
91
92
  }
92
93
  /**
93
- * Methods to get all credit accounts with some optional filtering
94
- * Performs all necessary price feed updates under the hood
95
- *
96
- * @param options
97
- * @param blockNumber
98
- * @returns returned credit accounts are sorted by health factor in ascending order
99
- */
94
+ * {@inheritDoc ICreditAccountsService.getCreditAccounts}
95
+ **/
100
96
  async getCreditAccounts(options, blockNumber) {
101
97
  const {
102
98
  creditManager,
@@ -149,11 +145,8 @@ class AbstractCreditAccountService extends SDKConstruct {
149
145
  return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
150
146
  }
151
147
  /**
152
- * Method to get all claimable rewards for credit account (ex. stkUSDS SKY rewards)
153
- Assosiates rewards by adapter + stakedPhantomToken
154
- * @param {Address} creditAccount - address of credit account to get rewards for
155
- * @returns {Array<Rewards>} list of {@link Rewards} that can be claimed
156
- */
148
+ * {@inheritDoc ICreditAccountsService.getRewards}
149
+ **/
157
150
  async getRewards(creditAccount) {
158
151
  const rewards = await this.client.readContract({
159
152
  abi: rewardsCompressorAbi,
@@ -193,11 +186,8 @@ class AbstractCreditAccountService extends SDKConstruct {
193
186
  return Object.values(r);
194
187
  }
195
188
  /**
196
- * Method to get all connected bots for credit account
197
- * @param {Array<AccountToCheck>} accountsToCheck - list of credit accounts
198
- and their credit managers to check connected bots on
199
- * @returns call result of getConnectedBots for each credit account
200
- */
189
+ * {@inheritDoc ICreditAccountsService.getConnectedBots}
190
+ **/
201
191
  async getConnectedBots(accountsToCheck, legacyMigrationBot, additionalBots) {
202
192
  const allResp = await this.client.multicall({
203
193
  contracts: [
@@ -301,10 +291,8 @@ class AbstractCreditAccountService extends SDKConstruct {
301
291
  return void 0;
302
292
  }
303
293
  /**
304
- * Generates transaction to liquidate credit account
305
- * @param props - {@link FullyLiquidateProps}
306
- * @returns
307
- */
294
+ * {@inheritDoc ICreditAccountsService.fullyLiquidate}
295
+ **/
308
296
  async fullyLiquidate(props) {
309
297
  const {
310
298
  account,
@@ -323,12 +311,12 @@ class AbstractCreditAccountService extends SDKConstruct {
323
311
  keepAssets,
324
312
  debtOnly
325
313
  });
326
- const priceUpdates = await this.getPriceUpdatesForFacade({
327
- creditManager: account.creditManager,
328
- creditAccount: account,
329
- ignoreReservePrices
330
- });
331
- const calls = [...priceUpdates, ...routerCloseResult.calls];
314
+ const calls = await this.prependPriceUpdates(
315
+ account.creditManager,
316
+ routerCloseResult.calls,
317
+ account,
318
+ { ignoreReservePrices }
319
+ );
332
320
  let lossPolicyData;
333
321
  if (applyLossPolicy) {
334
322
  const market = this.sdk.marketRegister.findByCreditManager(
@@ -354,21 +342,8 @@ class AbstractCreditAccountService extends SDKConstruct {
354
342
  };
355
343
  }
356
344
  /**
357
- * Closes credit account or closes credit account and keeps it open with zero debt.
358
- - Ca is closed in the following order: price update -> close path to swap all tokens into underlying ->
359
- -> disable quotas of exiting tokens -> decrease debt -> disable exiting tokens tokens -> withdraw underlying tokenz
360
- * @param {CloseOptions} operation - {@link CloseOptions}: close or zeroDebt
361
- * @param {RouterCASlice} creditAccount - minimal credit account data {@link RouterCASlice} on which operation is performed
362
- * @param {Array<Address>} assetsToWithdraw - tokens to withdraw from credit account.
363
- For credit account closing this is the underlying token, because during the closure,
364
- all tokens on account are swapped into the underlying,
365
- and only the underlying token will remain on the credit account
366
- * @param {Address} to - Wallet address to withdraw underlying to
367
- * @param {number} slippage - Slippage in PERCENTAGE_FORMAT (100% = 10_000) per operation
368
- * @default 50n
369
- * @param {RouterCloseResult | undefined} closePath - result of findBestClosePath method from router; if omited, calls marketRegister.findCreditManager {@link RouterCloseResult}
370
- * @returns All necessary data to execute the transaction (call, credit facade)
371
- */
345
+ * {@inheritDoc ICreditAccountsService.closeCreditAccount}
346
+ **/
372
347
  async closeCreditAccount({
373
348
  operation,
374
349
  assetsToWithdraw,
@@ -383,12 +358,7 @@ class AbstractCreditAccountService extends SDKConstruct {
383
358
  creditManager: cm.creditManager,
384
359
  slippage
385
360
  });
386
- const priceUpdates = await this.getPriceUpdatesForFacade({
387
- creditManager: ca.creditManager,
388
- creditAccount: ca
389
- });
390
- const calls = [
391
- ...operation === "close" ? [] : priceUpdates,
361
+ const operationCalls = [
392
362
  ...routerCloseResult.calls,
393
363
  ...this.prepareDisableQuotas(ca),
394
364
  ...this.prepareDecreaseDebt(ca),
@@ -396,17 +366,13 @@ class AbstractCreditAccountService extends SDKConstruct {
396
366
  (t) => this.prepareWithdrawToken(ca.creditFacade, t, MAX_UINT256, to)
397
367
  )
398
368
  ];
369
+ const calls = operation === "close" ? operationCalls : await this.prependPriceUpdates(ca.creditManager, operationCalls, ca);
399
370
  const tx = operation === "close" ? cm.creditFacade.closeCreditAccount(ca.creditAccount, calls) : cm.creditFacade.multicall(ca.creditAccount, calls);
400
371
  return { tx, calls, routerCloseResult, creditFacade: cm.creditFacade };
401
372
  }
402
373
  /**
403
- * Updates quota of credit account.
404
- - CA quota updated in the following order: price update -> update quotas
405
- * @param {RouterCASlice} creditAccount - minimal credit account data {@link RouterCASlice} on which operation is performed
406
- * @param {Array<Asset>} averageQuota - average quota for desired tokens {@link Asset}
407
- * @param {Array<Asset>} minQuota - minimum quota for desired tokens {@link Asset}
408
- * @returns All necessary data to execute the transaction (call, credit facade)
409
- */
374
+ * {@inheritDoc ICreditAccountsService.updateQuotas}
375
+ **/
410
376
  async updateQuotas({
411
377
  minQuota,
412
378
  averageQuota,
@@ -415,31 +381,21 @@ class AbstractCreditAccountService extends SDKConstruct {
415
381
  const cm = this.sdk.marketRegister.findCreditManager(
416
382
  creditAccount.creditManager
417
383
  );
418
- const priceUpdates = await this.getPriceUpdatesForFacade({
419
- creditManager: creditAccount.creditManager,
384
+ const operationCalls = this.prepareUpdateQuotas(
385
+ creditAccount.creditFacade,
386
+ { minQuota, averageQuota }
387
+ );
388
+ const calls = await this.prependPriceUpdates(
389
+ creditAccount.creditManager,
390
+ operationCalls,
420
391
  creditAccount
421
- });
422
- const calls = [
423
- ...priceUpdates,
424
- ...this.prepareUpdateQuotas(creditAccount.creditFacade, {
425
- minQuota,
426
- averageQuota
427
- })
428
- ];
392
+ );
429
393
  const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
430
394
  return { tx, calls, creditFacade: cm.creditFacade };
431
395
  }
432
396
  /**
433
- * Adds a single collateral to credit account and updates quotas
434
- - Collateral is added in the following order: price update -> add collateral (with permit) -> update quotas
435
- * @param {RouterCASlice} creditAccount - minimal credit account data {@link RouterCASlice} on which operation is performed
436
- * @param {Array<Asset>} averageQuota - average quota for desired token {@link Asset}
437
- * @param {Array<Asset>} minQuota - minimum quota for desired token {@link Asset}
438
- * @param {Asset} asset - asset to add as collateral {@link Asset}
439
- * @param {PermitResult | undefined} permits - permits of collateral asset if it is permittable {@link PermitResult}
440
- * @param {bigint} ethAmount - native token amount to attach to tx
441
- * @returns All necessary data to execute the transaction (call, credit facade)
442
- */
397
+ * {@inheritDoc ICreditAccountsService.addCollateral}
398
+ **/
443
399
  async addCollateral({
444
400
  creditAccount,
445
401
  asset,
@@ -451,13 +407,7 @@ class AbstractCreditAccountService extends SDKConstruct {
451
407
  const cm = this.sdk.marketRegister.findCreditManager(
452
408
  creditAccount.creditManager
453
409
  );
454
- const priceUpdatesCalls = await this.getPriceUpdatesForFacade({
455
- creditManager: creditAccount.creditManager,
456
- creditAccount,
457
- desiredQuotas: averageQuota
458
- });
459
- const calls = [
460
- ...priceUpdatesCalls,
410
+ const operationCalls = [
461
411
  ...this.prepareAddCollateral(
462
412
  creditAccount.creditFacade,
463
413
  [asset],
@@ -468,20 +418,18 @@ class AbstractCreditAccountService extends SDKConstruct {
468
418
  averageQuota
469
419
  })
470
420
  ];
421
+ const calls = await this.prependPriceUpdates(
422
+ creditAccount.creditManager,
423
+ operationCalls,
424
+ creditAccount
425
+ );
471
426
  const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
472
427
  tx.value = ethAmount.toString(10);
473
428
  return { tx, calls, creditFacade: cm.creditFacade };
474
429
  }
475
430
  /**
476
- * Increases or decreases debt of credit account; debt decrease uses token ON CREDIT ACCOUNT
477
- - Debt is changed in the following order: price update -> (enables underlying if it was disabled) -> change debt
478
- * @param {RouterCASlice} creditAccount - minimal credit account data {@link RouterCASlice} on which operation is performed
479
- * @param {bigint} amount - amount to change debt by;
480
- 0 - prohibited value;
481
- negative value for debt decrease;
482
- positive value for debt increase.
483
- * @returns All necessary data to execute the transaction (call, credit facade)
484
- */
431
+ * {@inheritDoc ICreditAccountsService.changeDebt}
432
+ **/
485
433
  async changeDebt({
486
434
  creditAccount,
487
435
  amount,
@@ -495,10 +443,6 @@ class AbstractCreditAccountService extends SDKConstruct {
495
443
  const cm = this.sdk.marketRegister.findCreditManager(
496
444
  creditAccount.creditManager
497
445
  );
498
- const priceUpdatesCalls = await this.getPriceUpdatesForFacade({
499
- creditManager: creditAccount.creditManager,
500
- creditAccount
501
- });
502
446
  const addCollateralCalls = addCollateral && isDecrease ? this.prepareAddCollateral(
503
447
  creditAccount.creditFacade,
504
448
  [
@@ -509,23 +453,21 @@ class AbstractCreditAccountService extends SDKConstruct {
509
453
  ],
510
454
  {}
511
455
  ) : [];
512
- const calls = [
513
- ...priceUpdatesCalls,
456
+ const operationCalls = [
514
457
  ...addCollateralCalls,
515
458
  this.#prepareChangeDebt(creditAccount.creditFacade, change, isDecrease)
516
459
  ];
460
+ const calls = await this.prependPriceUpdates(
461
+ creditAccount.creditManager,
462
+ operationCalls,
463
+ creditAccount
464
+ );
517
465
  const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
518
466
  return { tx, calls, creditFacade: cm.creditFacade };
519
467
  }
520
468
  /**
521
- * Executes swap specified by given calls, update quotas of affected tokens
522
- - Swap is executed in the following order: price update -> execute swap path -> update quotas
523
- * @param {RouterCASlice} creditAccount - minimal credit account data {@link RouterCASlice} on which operation is performed
524
- * @param {Array<Asset>} averageQuota - average quota for desired token {@link Asset}
525
- * @param {Array<Asset>} minQuota - minimum quota for desired token {@link Asset}
526
- * @param {Array<MultiCall>} calls - array of MultiCall from router methods getSingleSwap or getAllSwaps {@link MultiCall}
527
- * @returns All necessary data to execute the transaction (call, credit facade)
528
- */
469
+ * {@inheritDoc ICreditAccountsService.executeSwap}
470
+ **/
529
471
  async executeSwap({
530
472
  creditAccount,
531
473
  calls: swapCalls,
@@ -536,27 +478,24 @@ class AbstractCreditAccountService extends SDKConstruct {
536
478
  const cm = this.sdk.marketRegister.findCreditManager(
537
479
  creditAccount.creditManager
538
480
  );
539
- const priceUpdatesCalls = await this.getPriceUpdatesForFacade({
540
- creditManager: creditAccount.creditManager,
541
- creditAccount,
542
- desiredQuotas: averageQuota
543
- });
544
- const calls = [
545
- ...priceUpdatesCalls,
481
+ const operationCalls = [
546
482
  ...swapCalls,
547
483
  ...this.prepareUpdateQuotas(creditAccount.creditFacade, {
548
484
  minQuota,
549
485
  averageQuota
550
486
  })
551
487
  ];
488
+ const calls = await this.prependPriceUpdates(
489
+ creditAccount.creditManager,
490
+ operationCalls,
491
+ creditAccount
492
+ );
552
493
  const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
553
494
  return { tx, calls, creditFacade: cm.creditFacade };
554
495
  }
555
496
  /**
556
- * Preview delayed withdrawal for given token
557
- * @param props - {@link PreviewDelayedWithdrawalProps}
558
- * @returns
559
- */
497
+ * {@inheritDoc ICreditAccountsService.previewDelayedWithdrawal}
498
+ **/
560
499
  async previewDelayedWithdrawal({
561
500
  creditAccount,
562
501
  amount,
@@ -580,10 +519,8 @@ class AbstractCreditAccountService extends SDKConstruct {
580
519
  return resp;
581
520
  }
582
521
  /**
583
- * Get claimable and pending withdrawals of an account
584
- * @param props - {@link GetPendingWithdrawalsProps}
585
- * @returns
586
- */
522
+ * {@inheritDoc ICreditAccountsService.getPendingWithdrawals}
523
+ **/
587
524
  async getPendingWithdrawals({
588
525
  creditAccount
589
526
  }) {
@@ -609,11 +546,8 @@ class AbstractCreditAccountService extends SDKConstruct {
609
546
  return respResult;
610
547
  }
611
548
  /**
612
- * Start delayed withdrawal for given token
613
- - Withdrawal is executed in the following order: price update -> execute withdraw calls -> update quotas
614
- * @param props - {@link StartDelayedWithdrawalProps}
615
- * @returns
616
- */
549
+ * {@inheritDoc ICreditAccountsService.startDelayedWithdrawal}
550
+ **/
617
551
  async startDelayedWithdrawal({
618
552
  creditAccount,
619
553
  minQuota,
@@ -650,13 +584,7 @@ class AbstractCreditAccountService extends SDKConstruct {
650
584
  args: []
651
585
  })
652
586
  };
653
- const priceUpdatesCalls = await this.getPriceUpdatesForFacade({
654
- creditManager: creditAccount.creditManager,
655
- creditAccount,
656
- desiredQuotas: averageQuota
657
- });
658
- const calls = [
659
- ...priceUpdatesCalls,
587
+ const operationCalls = [
660
588
  storeExpectedBalances,
661
589
  ...preview.requestCalls,
662
590
  compareBalances,
@@ -665,15 +593,17 @@ class AbstractCreditAccountService extends SDKConstruct {
665
593
  averageQuota
666
594
  })
667
595
  ];
596
+ const calls = await this.prependPriceUpdates(
597
+ creditAccount.creditManager,
598
+ operationCalls,
599
+ creditAccount
600
+ );
668
601
  const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
669
602
  return { tx, calls, creditFacade: cm.creditFacade };
670
603
  }
671
604
  /**
672
- * Claim tokens with delayed withdrawal
673
- - Claim is executed in the following order: price update -> execute claim calls -> update quotas
674
- * @param props - {@link ClaimDelayedProps}
675
- * @returns
676
- */
605
+ * {@inheritDoc ICreditAccountsService.claimDelayed}
606
+ **/
677
607
  async claimDelayed({
678
608
  creditAccount,
679
609
  minQuota,
@@ -714,49 +644,27 @@ class AbstractCreditAccountService extends SDKConstruct {
714
644
  args: []
715
645
  })
716
646
  };
717
- const priceUpdatesCalls = zeroDebt ? [] : await this.getPriceUpdatesForFacade({
718
- creditManager: creditAccount.creditManager,
719
- creditAccount,
720
- desiredQuotas: averageQuota
721
- });
722
647
  const quotaCalls = zeroDebt ? [] : this.prepareUpdateQuotas(creditAccount.creditFacade, {
723
648
  minQuota,
724
649
  averageQuota
725
650
  });
726
- const calls = [
727
- ...priceUpdatesCalls,
651
+ const operationCalls = [
728
652
  storeExpectedBalances,
729
653
  ...claimableNow.claimCalls,
730
654
  compareBalances,
731
655
  ...quotaCalls
732
656
  ];
657
+ const calls = zeroDebt ? operationCalls : await this.prependPriceUpdates(
658
+ creditAccount.creditManager,
659
+ operationCalls,
660
+ creditAccount
661
+ );
733
662
  const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
734
663
  return { tx, calls, creditFacade: cm.creditFacade };
735
664
  }
736
665
  /**
737
- * Executes swap specified by given calls, update quotas of affected tokens
738
- - Open credit account is executed in the following order: price update -> increase debt -> add collateral ->
739
- -> update quotas -> (optionally: execute swap path for trading/strategy) ->
740
- -> (optionally: withdraw debt for lending)
741
- - Basic open credit account: price update -> increase debt -> add collateral -> update quotas
742
- - Lending: price update -> increase debt -> add collateral -> update quotas -> withdraw debt
743
- - Strategy/trading: price update -> increase debt -> add collateral -> update quotas -> execute swap path
744
- - In strategy is possible situation when collateral is added, but not swapped; the only swapped value in this case will be debt
745
- * @param {bigint} ethAmount - native token amount to attach to tx
746
- * @param {Address} creditManager - address of credit manager to open credit account on
747
- * @param {Array<Asset>} collateral - array of collateral which can be just directly added or swapped using the path {@link Asset}
748
- * @param {Record<Address, PermitResult>} permits - permits of collateral tokens (in any permittable token is present) {@link PermitResult}
749
- * @param {bigint} debt - debt to open credit account with
750
- * @param {boolean} withdrawDebt - flag to withdraw debt to wallet after opening credit account;
751
- used for borrowing functionality
752
- * @param {bigint} referralCode - referral code to open credit account with
753
- * @param {Address} to - wallet address to transfer credit account to\
754
- * @param {Array<MultiCall>} calls - array of MultiCall from router methods findOpenStrategyPath {@link MultiCall}.
755
- Used for trading and strategy functionality
756
- * @param {Array<Asset>} averageQuota - average quota for tokens after open {@link Asset}
757
- * @param {Array<Asset>} minQuota - minimum quota for tokens after open {@link Asset}
758
- * @returns All necessary data to execute the transaction (call, credit facade)
759
- */
666
+ * {@inheritDoc ICreditAccountsService.openCA}
667
+ **/
760
668
  async openCA({
761
669
  ethAmount,
762
670
  creditManager,
@@ -772,12 +680,7 @@ class AbstractCreditAccountService extends SDKConstruct {
772
680
  }) {
773
681
  const cmSuite = this.sdk.marketRegister.findCreditManager(creditManager);
774
682
  const cm = cmSuite.creditManager;
775
- const priceUpdatesCalls = await this.getPriceUpdatesForFacade({
776
- creditManager: cm.address,
777
- desiredQuotas: averageQuota
778
- });
779
- const calls = [
780
- ...priceUpdatesCalls,
683
+ const operationCalls = [
781
684
  this.#prepareIncreaseDebt(cm.creditFacade, debt),
782
685
  ...this.prepareAddCollateral(cm.creditFacade, collateral, permits),
783
686
  ...openPathCalls,
@@ -787,15 +690,14 @@ class AbstractCreditAccountService extends SDKConstruct {
787
690
  averageQuota
788
691
  })
789
692
  ];
693
+ const calls = await this.prependPriceUpdates(cm.address, operationCalls);
790
694
  const tx = cmSuite.creditFacade.openCreditAccount(to, calls, referralCode);
791
695
  tx.value = ethAmount.toString(10);
792
696
  return { calls, tx, creditFacade: cmSuite.creditFacade };
793
697
  }
794
698
  /**
795
- * Returns borrow rate with 4 digits precision (10000 = 100%)
796
- * @param ca
797
- * @returns
798
- */
699
+ * {@inheritDoc ICreditAccountsService.getBorrowRate}
700
+ **/
799
701
  getBorrowRate(ca) {
800
702
  const { creditManager } = this.sdk.marketRegister.findCreditManager(
801
703
  ca.creditManager
@@ -821,9 +723,8 @@ class AbstractCreditAccountService extends SDKConstruct {
821
723
  return r + qr;
822
724
  }
823
725
  /**
824
- * Returns optimal HF for partial liquidation with 4 digits precision (10000 = 100%)
825
- * @param ca
826
- */
726
+ * {@inheritDoc ICreditAccountsService.getOptimalHFForPartialLiquidation}
727
+ **/
827
728
  getOptimalHFForPartialLiquidation(ca) {
828
729
  const borrowRate = this.getBorrowRate(ca);
829
730
  return PERCENTAGE_FACTOR + (borrowRate < 100n ? borrowRate : 100n);
@@ -872,112 +773,146 @@ class AbstractCreditAccountService extends SDKConstruct {
872
773
  return resp;
873
774
  }
874
775
  /**
875
- * Returns raw txs that are needed to update all price feeds so that all credit accounts (possibly from different markets) compute
776
+ * {@inheritDoc ICreditAccountsService.getOnDemandPriceUpdates}
777
+ **/
778
+ async getOnDemandPriceUpdates(account, ignoreReservePrices) {
779
+ const { creditManager, creditAccount } = account;
780
+ const cm = this.sdk.marketRegister.findCreditManager(creditManager);
781
+ const update = await this.getUpdateForAccount(account, ignoreReservePrices);
782
+ this.logger?.debug(
783
+ { account: creditAccount, manager: cm.name },
784
+ `getting on demand price updates from ${update.txs.length} txs`
785
+ );
786
+ return getRawPriceUpdates(update);
787
+ }
788
+ /**
789
+ * Analyzes a multicall array and prepends necessary on-demand price feed updates.
876
790
  *
877
- * This can be used by batch liquidator
878
- * @param accounts
879
- * @returns
791
+ * Deduplicates existing `onDemandPriceUpdates` calls
792
+ *
793
+ * @param creditManager - Address of the credit manager
794
+ * @param calls - The multicall array to prepend price updates to
795
+ * @param ca - Credit account slice, undefined when opening a new account
796
+ * @param options - Optional settings for price update generation
797
+ * @returns A new array with a single consolidated price update call prepended,
798
+ * followed by the non-price-update calls in their original order
880
799
  */
881
- async getUpdateForAccounts(accounts) {
882
- const tokensByPool = /* @__PURE__ */ new Map();
883
- const oracleByPool = /* @__PURE__ */ new Map();
884
- for (const acc of accounts) {
885
- const market = this.sdk.marketRegister.findByCreditManager(
886
- acc.creditManager
887
- );
888
- const pool = market.pool.pool.address;
889
- oracleByPool.set(pool, market.priceOracle);
890
- for (const t of acc.tokens) {
891
- if (t.balance > 10n) {
892
- const tokens = tokensByPool.get(pool) ?? /* @__PURE__ */ new Set();
800
+ async prependPriceUpdates(creditManager, calls, ca, options) {
801
+ const market = this.sdk.marketRegister.findByCreditManager(creditManager);
802
+ const cm = this.sdk.marketRegister.findCreditManager(creditManager).creditManager;
803
+ const { priceUpdates: existingUpdates, remainingCalls } = extractPriceUpdates(calls);
804
+ const tokens = new AddressSet([
805
+ cm.underlying,
806
+ // underlying - always included
807
+ ...extractQuotaTokens(calls)
808
+ // tokens from `updateQuota` calls
809
+ ]);
810
+ if (ca) {
811
+ for (const t of ca.tokens) {
812
+ const isEnabled = (t.mask & ca.enabledTokensMask) !== 0n;
813
+ if (t.balance > 10n && isEnabled) {
893
814
  tokens.add(t.token);
894
- tokensByPool.set(pool, tokens);
895
815
  }
896
816
  }
897
817
  }
898
- const priceFeeds = [];
899
- for (const [pool, oracle] of oracleByPool.entries()) {
900
- const tokens = Array.from(tokensByPool.get(pool) ?? []);
901
- priceFeeds.push(...oracle.priceFeedsForTokens(tokens));
818
+ const ignoreReservePrices = options?.ignoreReservePrices;
819
+ const priceFeeds = market.priceOracle.priceFeedsForTokens(Array.from(tokens), {
820
+ main: true,
821
+ reserve: !ignoreReservePrices
822
+ });
823
+ const tStr = tokens.map((t) => this.labelAddress(t)).join(", ");
824
+ const remark = ignoreReservePrices ? " main" : "";
825
+ this.logger?.debug(
826
+ { account: ca?.creditAccount, manager: cm.name },
827
+ `prependPriceUpdates for ${tStr} from ${priceFeeds.length}${remark} price feeds`
828
+ );
829
+ const generatedUpdates = await this.sdk.priceFeeds.generatePriceFeedsUpdates(priceFeeds);
830
+ const merged = mergePriceUpdates(existingUpdates, generatedUpdates);
831
+ if (merged.length === 0) {
832
+ return remainingCalls;
902
833
  }
903
- return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(priceFeeds);
834
+ return [
835
+ {
836
+ target: cm.creditFacade,
837
+ callData: encodeFunctionData({
838
+ abi: iCreditFacadeMulticallV310Abi,
839
+ functionName: "onDemandPriceUpdates",
840
+ args: [merged]
841
+ })
842
+ },
843
+ ...remainingCalls
844
+ ];
904
845
  }
905
- async getUpdateForAccount(options) {
906
- const { creditManager, creditAccount, desiredQuotas, ignoreReservePrices } = options;
907
- const quotaRecord = desiredQuotas ? assetsMap(desiredQuotas) : desiredQuotas;
908
- const caBalancesRecord = creditAccount ? assetsMap(creditAccount.tokens) : creditAccount;
846
+ async getUpdateForAccount(account, ignoreReservePrices) {
847
+ const { creditManager, creditAccount, enabledTokensMask } = account;
909
848
  const market = this.sdk.marketRegister.findByCreditManager(creditManager);
910
849
  const cm = this.sdk.marketRegister.findCreditManager(creditManager).creditManager;
911
- const tokens = /* @__PURE__ */ new Set([getAddress(cm.underlying)]);
912
- for (const t of cm.collateralTokens) {
913
- if (creditAccount && caBalancesRecord && quotaRecord) {
914
- const balanceAsset = caBalancesRecord.get(t);
915
- const balance = balanceAsset?.balance || 0n;
916
- const mask = balanceAsset?.mask || 0n;
917
- const isEnabled = (mask & creditAccount.enabledTokensMask) !== 0n;
918
- const quotaAsset = quotaRecord.get(t);
919
- const quotaBalance = quotaAsset?.balance || 0n;
920
- if (balance > 10n && isEnabled || quotaBalance > 0) {
921
- tokens.add(getAddress(t));
922
- }
923
- } else if (creditAccount && caBalancesRecord) {
924
- const balanceAsset = caBalancesRecord.get(t);
925
- const balance = balanceAsset?.balance || 0n;
926
- const mask = balanceAsset?.mask || 0n;
927
- const isEnabled = (mask & creditAccount.enabledTokensMask) !== 0n;
928
- if (balance > 10n && isEnabled) {
929
- tokens.add(getAddress(t));
930
- }
931
- } else if (quotaRecord) {
932
- const quotaAsset = quotaRecord.get(t);
933
- const quotaBalance = quotaAsset?.balance || 0n;
934
- if (quotaBalance > 0) {
935
- tokens.add(getAddress(t));
936
- }
850
+ const tokens = new AddressSet([cm.underlying]);
851
+ for (const t of account.tokens) {
852
+ const isEnabled = (t.mask & enabledTokensMask) !== 0n;
853
+ if (t.balance > 10n && isEnabled) {
854
+ tokens.add(t.token);
937
855
  }
938
856
  }
939
857
  const priceFeeds = market.priceOracle.priceFeedsForTokens(Array.from(tokens), {
940
858
  main: true,
941
859
  reserve: !ignoreReservePrices
942
860
  });
943
- const tStr = Array.from(tokens).map((t) => this.labelAddress(t)).join(", ");
861
+ const tStr = tokens.map((t) => this.labelAddress(t)).join(", ");
944
862
  const remark = ignoreReservePrices ? " main" : "";
945
863
  this.logger?.debug(
946
- { account: creditAccount?.creditAccount, manager: cm.name },
864
+ { account: creditAccount, manager: cm.name },
947
865
  `generating price feed updates for ${tStr} from ${priceFeeds.length}${remark} price feeds`
948
866
  );
949
867
  return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(priceFeeds);
950
868
  }
951
869
  /**
952
- * Returns account price updates that can be used in credit facade multicall or liquidator calls
953
- * @param options
954
- * @returns
870
+ * Executes a multicall on a credit account, automatically prepending
871
+ * necessary on-demand price feed updates.
872
+ *
873
+ * @param creditAccount - Credit account to execute multicall on
874
+ * @param calls - Array of multicall operations (price updates will be inferred)
875
+ * @param options - Optional settings for price update generation
876
+ * @returns Raw transaction ready to be signed and sent
955
877
  */
956
- async getOnDemandPriceUpdates(options) {
957
- const { creditManager, creditAccount } = options;
958
- const market = this.sdk.marketRegister.findByCreditManager(creditManager);
959
- const cm = this.sdk.marketRegister.findCreditManager(creditManager);
960
- const update = await this.getUpdateForAccount(options);
961
- this.logger?.debug(
962
- { account: creditAccount?.creditAccount, manager: cm.name },
963
- `getting on demand price updates from ${update.txs.length} txs`
878
+ async multicall(creditAccount, calls, options) {
879
+ const cm = this.sdk.marketRegister.findCreditManager(
880
+ creditAccount.creditManager
881
+ );
882
+ const callsWithPrices = await this.prependPriceUpdates(
883
+ creditAccount.creditManager,
884
+ calls,
885
+ creditAccount,
886
+ options
964
887
  );
965
- return market.priceOracle.onDemandPriceUpdates(
966
- cm.creditFacade.address,
967
- update
888
+ return cm.creditFacade.multicall(
889
+ creditAccount.creditAccount,
890
+ callsWithPrices
968
891
  );
969
892
  }
970
893
  /**
971
- * Returns price updates in format that is accepted by various credit facade methods (multicall, close/liquidate, etc...).
972
- * - If there are desiredQuotas and creditAccount update quotaBalance > 0 || (balance > 10n && isEnabled). Is used when account has both: balances and quota buys.
973
- * - If there is creditAccount update balance > 10n && isEnabled. Is used in credit account actions when quota is not being bought.
974
- * - If there is desiredQuotas update quotaBalance > 0. Is used on credit account opening, when quota is bought for the first time.
975
- * @param acc
976
- * @returns
894
+ * Executes a bot multicall on a credit account, automatically prepending
895
+ * necessary on-demand price feed updates.
896
+ *
897
+ * @param creditAccount - Credit account to execute bot multicall on
898
+ * @param calls - Array of multicall operations (price updates will be inferred)
899
+ * @param options - Optional settings for price update generation
900
+ * @returns Raw transaction ready to be signed and sent
977
901
  */
978
- async getPriceUpdatesForFacade(options) {
979
- const updates = await this.getOnDemandPriceUpdates(options);
980
- return updates.multicall;
902
+ async botMulticall(creditAccount, calls, options) {
903
+ const cm = this.sdk.marketRegister.findCreditManager(
904
+ creditAccount.creditManager
905
+ );
906
+ const callsWithPrices = await this.prependPriceUpdates(
907
+ creditAccount.creditManager,
908
+ calls,
909
+ creditAccount,
910
+ options
911
+ );
912
+ return cm.creditFacade.botMulticall(
913
+ creditAccount.creditAccount,
914
+ callsWithPrices
915
+ );
981
916
  }
982
917
  prepareDisableQuotas(ca) {
983
918
  const calls = [];
@@ -1099,79 +1034,6 @@ class AbstractCreditAccountService extends SDKConstruct {
1099
1034
  )[0];
1100
1035
  }
1101
1036
  }
1102
- const iMellowClaimerAdapterAbi = [
1103
- {
1104
- type: "function",
1105
- name: "getMultiVaultSubvaultIndices",
1106
- inputs: [{ name: "multiVault", type: "address", internalType: "address" }],
1107
- outputs: [
1108
- {
1109
- name: "subvaultIndices",
1110
- type: "uint256[]",
1111
- internalType: "uint256[]"
1112
- },
1113
- {
1114
- name: "withdrawalIndices",
1115
- type: "uint256[][]",
1116
- internalType: "uint256[][]"
1117
- }
1118
- ],
1119
- stateMutability: "view"
1120
- },
1121
- {
1122
- type: "function",
1123
- name: "getUserSubvaultIndices",
1124
- inputs: [
1125
- { name: "multiVault", type: "address", internalType: "address" },
1126
- { name: "user", type: "address", internalType: "address" }
1127
- ],
1128
- outputs: [
1129
- {
1130
- name: "subvaultIndices",
1131
- type: "uint256[]",
1132
- internalType: "uint256[]"
1133
- },
1134
- {
1135
- name: "withdrawalIndices",
1136
- type: "uint256[][]",
1137
- internalType: "uint256[][]"
1138
- }
1139
- ],
1140
- stateMutability: "view"
1141
- },
1142
- {
1143
- type: "function",
1144
- name: "multiAccept",
1145
- inputs: [
1146
- { name: "multiVault", type: "address", internalType: "address" },
1147
- {
1148
- name: "subvaultIndices",
1149
- type: "uint256[]",
1150
- internalType: "uint256[]"
1151
- },
1152
- { name: "indices", type: "uint256[][]", internalType: "uint256[][]" }
1153
- ],
1154
- outputs: [{ name: "", type: "bool", internalType: "bool" }],
1155
- stateMutability: "nonpayable"
1156
- },
1157
- {
1158
- type: "function",
1159
- name: "multiAcceptAndClaim",
1160
- inputs: [
1161
- { name: "multiVault", type: "address", internalType: "address" },
1162
- {
1163
- name: "subvaultIndices",
1164
- type: "uint256[]",
1165
- internalType: "uint256[]"
1166
- },
1167
- { name: "indices", type: "uint256[][]", internalType: "uint256[][]" },
1168
- { name: "", type: "address", internalType: "address" },
1169
- { name: "maxAssets", type: "uint256", internalType: "uint256" }
1170
- ],
1171
- outputs: [{ name: "", type: "bool", internalType: "bool" }],
1172
- stateMutability: "nonpayable"
1173
- }
1174
- ];
1175
1037
  export {
1176
1038
  AbstractCreditAccountService,
1177
1039
  getWithdrawalCompressorAddress