@gearbox-protocol/sdk 13.1.0 → 13.2.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/cjs/abi/310/iSecuritizeDegenNFT.js +263 -0
  2. package/dist/cjs/abi/310/iSecuritizeKYCFactory.js +278 -0
  3. package/dist/cjs/{sdk/pools/PoolServiceV310.js → abi/iStateSerializer.js} +14 -8
  4. package/dist/cjs/dev/AccountOpener.js +45 -5
  5. package/dist/cjs/sdk/accounts/AbstractCreditAccountsService.js +462 -104
  6. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +16 -5
  7. package/dist/cjs/sdk/base/ChainContractsRegister.js +1 -1
  8. package/dist/cjs/sdk/base/TokensMeta.js +255 -32
  9. package/dist/cjs/sdk/base/index.js +2 -0
  10. package/dist/cjs/sdk/{constants/phantom-tokens.js → base/token-types.js} +9 -3
  11. package/dist/cjs/sdk/chain/chains.js +2 -1
  12. package/dist/cjs/sdk/constants/index.js +0 -2
  13. package/dist/cjs/sdk/market/MarketRegister.js +2 -2
  14. package/dist/cjs/sdk/market/MarketSuite.js +6 -0
  15. package/dist/cjs/{plugins/zappers/extraZappers.js → sdk/market/ZapperRegister.js} +110 -6
  16. package/dist/cjs/sdk/market/index.js +3 -1
  17. package/dist/cjs/sdk/market/pool/PoolSuite.js +3 -0
  18. package/dist/cjs/sdk/market/pool/PoolV310Contract.js +17 -2
  19. package/dist/cjs/sdk/market/pool/SecuritizeKYCFactory.js +97 -0
  20. package/dist/cjs/sdk/market/pool/index.js +4 -0
  21. package/dist/cjs/sdk/pools/PoolService.js +391 -0
  22. package/dist/cjs/sdk/pools/index.js +2 -4
  23. package/dist/cjs/sdk/utils/AddressMap.js +1 -1
  24. package/dist/cjs/sdk/utils/viem/sendRawTx.js +16 -0
  25. package/dist/esm/abi/310/iSecuritizeDegenNFT.js +239 -0
  26. package/dist/esm/abi/310/iSecuritizeKYCFactory.js +254 -0
  27. package/dist/esm/abi/iStateSerializer.js +12 -0
  28. package/dist/esm/dev/AccountOpener.js +47 -6
  29. package/dist/esm/sdk/accounts/AbstractCreditAccountsService.js +462 -104
  30. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +16 -5
  31. package/dist/esm/sdk/base/ChainContractsRegister.js +1 -1
  32. package/dist/esm/sdk/base/TokensMeta.js +261 -32
  33. package/dist/esm/sdk/base/index.js +1 -0
  34. package/dist/esm/sdk/{constants/phantom-tokens.js → base/token-types.js} +4 -0
  35. package/dist/esm/sdk/chain/chains.js +2 -1
  36. package/dist/esm/sdk/constants/index.js +0 -1
  37. package/dist/esm/sdk/market/MarketRegister.js +2 -2
  38. package/dist/esm/sdk/market/MarketSuite.js +6 -0
  39. package/dist/esm/{plugins/zappers/extraZappers.js → sdk/market/ZapperRegister.js} +109 -2
  40. package/dist/esm/sdk/market/index.js +1 -0
  41. package/dist/esm/sdk/market/pool/PoolSuite.js +3 -0
  42. package/dist/esm/sdk/market/pool/PoolV310Contract.js +17 -2
  43. package/dist/esm/sdk/market/pool/SecuritizeKYCFactory.js +73 -0
  44. package/dist/esm/sdk/market/pool/index.js +2 -0
  45. package/dist/esm/sdk/pools/PoolService.js +371 -0
  46. package/dist/esm/sdk/pools/index.js +1 -2
  47. package/dist/esm/sdk/utils/AddressMap.js +1 -1
  48. package/dist/esm/sdk/utils/viem/sendRawTx.js +19 -1
  49. package/dist/types/abi/310/iSecuritizeDegenNFT.d.ts +324 -0
  50. package/dist/types/abi/310/iSecuritizeKYCFactory.d.ts +322 -0
  51. package/dist/types/abi/iStateSerializer.d.ts +11 -0
  52. package/dist/types/sdk/accounts/AbstractCreditAccountsService.d.ts +123 -27
  53. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +1 -1
  54. package/dist/types/sdk/accounts/types.d.ts +108 -8
  55. package/dist/types/sdk/base/TokensMeta.d.ts +34 -18
  56. package/dist/types/sdk/base/index.d.ts +1 -0
  57. package/dist/types/sdk/base/token-types.d.ts +33 -0
  58. package/dist/types/sdk/base/types.d.ts +0 -1
  59. package/dist/types/sdk/chain/chains.d.ts +1 -1
  60. package/dist/types/sdk/constants/index.d.ts +0 -1
  61. package/dist/types/sdk/market/MarketRegister.d.ts +2 -2
  62. package/dist/types/sdk/market/MarketSuite.d.ts +3 -0
  63. package/dist/types/sdk/market/ZapperRegister.d.ts +17 -0
  64. package/dist/types/sdk/market/index.d.ts +1 -0
  65. package/dist/types/sdk/market/pool/PoolSuite.d.ts +2 -0
  66. package/dist/types/sdk/market/pool/PoolV310Contract.d.ts +6 -2
  67. package/dist/types/sdk/market/pool/SecuritizeKYCFactory.d.ts +345 -0
  68. package/dist/types/sdk/market/pool/index.d.ts +2 -0
  69. package/dist/types/sdk/market/types.d.ts +10 -0
  70. package/dist/types/sdk/pools/PoolService.d.ts +14 -0
  71. package/dist/types/sdk/pools/index.d.ts +1 -2
  72. package/dist/types/sdk/pools/types.d.ts +84 -63
  73. package/dist/types/sdk/utils/AddressMap.d.ts +1 -1
  74. package/dist/types/sdk/utils/viem/sendRawTx.d.ts +5 -1
  75. package/package.json +1 -1
  76. package/dist/cjs/plugins/zappers/ZappersPlugin.js +0 -144
  77. package/dist/cjs/plugins/zappers/index.js +0 -26
  78. package/dist/cjs/plugins/zappers/package.json +0 -1
  79. package/dist/cjs/sdk/pools/AbstractPoolService.js +0 -137
  80. package/dist/cjs/sdk/pools/createPoolService.js +0 -35
  81. package/dist/esm/plugins/zappers/ZappersPlugin.js +0 -126
  82. package/dist/esm/plugins/zappers/index.js +0 -3
  83. package/dist/esm/plugins/zappers/package.json +0 -1
  84. package/dist/esm/sdk/pools/AbstractPoolService.js +0 -113
  85. package/dist/esm/sdk/pools/PoolServiceV310.js +0 -6
  86. package/dist/esm/sdk/pools/createPoolService.js +0 -11
  87. package/dist/types/plugins/zappers/ZappersPlugin.d.ts +0 -18
  88. package/dist/types/plugins/zappers/extraZappers.d.ts +0 -6
  89. package/dist/types/plugins/zappers/index.d.ts +0 -3
  90. package/dist/types/plugins/zappers/types.d.ts +0 -12
  91. package/dist/types/sdk/constants/phantom-tokens.d.ts +0 -2
  92. package/dist/types/sdk/pools/AbstractPoolService.d.ts +0 -9
  93. package/dist/types/sdk/pools/PoolServiceV310.d.ts +0 -4
  94. package/dist/types/sdk/pools/createPoolService.d.ts +0 -3
  95. /package/dist/cjs/{plugins/zappers → sdk/market}/types.js +0 -0
  96. /package/dist/esm/{plugins/zappers → sdk/market}/types.js +0 -0
@@ -28,6 +28,7 @@ const COMPRESSORS = {
28
28
  [chains.Mainnet.id]: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023",
29
29
  [chains.Monad.id]: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023"
30
30
  };
31
+ const INVESTORS = new AddressMap([], "investors");
31
32
  function getWithdrawalCompressorAddress(chainId) {
32
33
  return COMPRESSORS[chainId];
33
34
  }
@@ -89,6 +90,23 @@ class AbstractCreditAccountService extends SDKConstruct {
89
90
  });
90
91
  return cad;
91
92
  }
93
+ /**
94
+ * Returns credit account data for a single account with the investor address resolved.
95
+ * Loads CA via getCreditAccountData; for KYC underlyings fetches the investor from the KYC factory's getInvestor(creditAccount), otherwise uses the account owner.
96
+ * @param account - Credit account address
97
+ * @param blockNumber - Optional block number for the read
98
+ * @returns CreditAccountDataWithInvestor (CA data + investor address), or undefined if the account is not found
99
+ */
100
+ async getCreditAccountDataWithInvestor(account, blockNumber) {
101
+ const ca = await this.getCreditAccountData(account, blockNumber);
102
+ if (!ca) return ca;
103
+ const marketSuite = this.sdk.marketRegister.findByCreditManager(
104
+ ca.creditManager
105
+ );
106
+ const factory = await marketSuite.getKYCFactory();
107
+ const investor = factory ? await factory.getInvestor(ca.creditAccount, true) : void 0;
108
+ return { ...ca, investor: investor ?? ca.owner };
109
+ }
92
110
  /**
93
111
  * Methods to get all credit accounts with some optional filtering
94
112
  * Performs all necessary price feed updates under the hood
@@ -97,7 +115,7 @@ class AbstractCreditAccountService extends SDKConstruct {
97
115
  * @param blockNumber
98
116
  * @returns returned credit accounts are sorted by health factor in ascending order
99
117
  */
100
- async getCreditAccounts(options, blockNumber) {
118
+ async getCreditAccounts(options, blockNumber, priceUpdate) {
101
119
  const {
102
120
  creditManager,
103
121
  includeZeroDebt = false,
@@ -119,7 +137,7 @@ class AbstractCreditAccountService extends SDKConstruct {
119
137
  maxHealthFactor,
120
138
  reverting: false
121
139
  };
122
- const { txs: priceUpdateTxs } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(
140
+ const { txs: priceUpdateTxs } = priceUpdate ?? await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(
123
141
  ignoreReservePrices ? { main: true } : void 0
124
142
  );
125
143
  const allCAs = [];
@@ -148,6 +166,75 @@ class AbstractCreditAccountService extends SDKConstruct {
148
166
  );
149
167
  return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
150
168
  }
169
+ /**
170
+ * Returns all credit accounts matching the filter, with investor set on each item.
171
+ * Delegates to getCreditAccounts; when options.owner is set, also loads KYC credit accounts for that owner and merges them into the list. Result is sorted by health factor ascending.
172
+ * @param options - Filter options (owner, creditManager, health factor, etc.)
173
+ * @param blockNumber - Optional block number for the read
174
+ * @returns Array of credit accounts (with investor field), sorted by health factor ascending
175
+ */
176
+ async getCreditAccountsWithInvestor(options, blockNumber) {
177
+ const { owner, ignoreReservePrices = false } = options ?? {};
178
+ const priceUpdate = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(
179
+ ignoreReservePrices ? { main: true } : void 0
180
+ );
181
+ const { txs: priceUpdateTxs } = priceUpdate;
182
+ const [common, kyc] = await Promise.all([
183
+ this.getCreditAccounts(options, blockNumber),
184
+ owner ? this.getKYCCreditAccountsOfOwner(owner, priceUpdateTxs, blockNumber) : void 0
185
+ ]);
186
+ const allCAs = common.map(
187
+ (ca) => ({
188
+ ...ca,
189
+ investor: owner || ca.owner
190
+ })
191
+ );
192
+ allCAs.push(...kyc || []);
193
+ return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
194
+ }
195
+ async getKYCCreditAccountsOfOwner(owner, priceUpdateTxs, blockNumber) {
196
+ const suites = this.marketConfigurators.map((mc) => {
197
+ const suite = this.sdk.marketRegister.markets.find(
198
+ (m) => m.configurator.address === mc
199
+ );
200
+ return suite;
201
+ });
202
+ const kycCAAddresses = await this.getKYCCaOfInvestor(owner, suites);
203
+ const kycCAs = await this.loadSpecifiedAccounts(
204
+ kycCAAddresses,
205
+ priceUpdateTxs,
206
+ blockNumber
207
+ );
208
+ return kycCAs.map((ca) => ({
209
+ ...ca,
210
+ investor: owner
211
+ }));
212
+ }
213
+ /**
214
+ * Loads credit account data for the given addresses using simulateWithPriceUpdates.
215
+ * Applies the provided price update txs before reading, so returned data is consistent with up-to-date prices.
216
+ * @param accounts - Credit account addresses to load
217
+ * @param priceUpdateTxs - Price feed update txs to simulate before the read (e.g. from generatePriceFeedsUpdateTxs)
218
+ * @param blockNumber - Optional block number for the read
219
+ * @returns Array of CreditAccountData in the same order as accounts (throws if any getCreditAccountData call reverts)
220
+ */
221
+ async loadSpecifiedAccounts(accounts, priceUpdateTxs, blockNumber) {
222
+ if (accounts.length === 0) return [];
223
+ const list = await simulateWithPriceUpdates(this.client, {
224
+ priceUpdates: priceUpdateTxs,
225
+ contracts: accounts.map(
226
+ (account) => ({
227
+ abi: creditAccountCompressorAbi,
228
+ address: this.#compressor,
229
+ functionName: "getCreditAccountData",
230
+ args: [account]
231
+ })
232
+ ),
233
+ blockNumber,
234
+ gas: this.sdk.gasLimit
235
+ });
236
+ return list;
237
+ }
151
238
  /**
152
239
  * Method to get all claimable rewards for credit account (ex. stkUSDS SKY rewards)
153
240
  Assosiates rewards by adapter + stakedPhantomToken
@@ -378,6 +465,13 @@ class AbstractCreditAccountService extends SDKConstruct {
378
465
  closePath
379
466
  }) {
380
467
  const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
468
+ await this.sdk.tokensMeta.loadTokenData(cm.underlying);
469
+ const underlying = this.sdk.tokensMeta.mustGet(cm.underlying);
470
+ if (this.sdk.tokensMeta.isKYCUnderlying(underlying)) {
471
+ throw new Error(
472
+ "closeCreditAccount is not supported for KYC underlying credit accounts"
473
+ );
474
+ }
381
475
  const routerCloseResult = closePath || await this.sdk.routerFor(ca).findBestClosePath({
382
476
  creditAccount: ca,
383
477
  creditManager: cm.creditManager,
@@ -396,7 +490,12 @@ class AbstractCreditAccountService extends SDKConstruct {
396
490
  (t) => this.prepareWithdrawToken(ca.creditFacade, t, MAX_UINT256, to)
397
491
  )
398
492
  ];
399
- const tx = operation === "close" ? cm.creditFacade.closeCreditAccount(ca.creditAccount, calls) : cm.creditFacade.multicall(ca.creditAccount, calls);
493
+ const tx = await this.closeCreditAccountTx(
494
+ cm,
495
+ ca.creditAccount,
496
+ calls,
497
+ operation
498
+ );
400
499
  return { tx, calls, routerCloseResult, creditFacade: cm.creditFacade };
401
500
  }
402
501
  /**
@@ -426,7 +525,7 @@ class AbstractCreditAccountService extends SDKConstruct {
426
525
  averageQuota
427
526
  })
428
527
  ];
429
- const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
528
+ const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
430
529
  return { tx, calls, creditFacade: cm.creditFacade };
431
530
  }
432
531
  /**
@@ -468,7 +567,7 @@ class AbstractCreditAccountService extends SDKConstruct {
468
567
  averageQuota
469
568
  })
470
569
  ];
471
- const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
570
+ const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
472
571
  tx.value = ethAmount.toString(10);
473
572
  return { tx, calls, creditFacade: cm.creditFacade };
474
573
  }
@@ -485,7 +584,7 @@ class AbstractCreditAccountService extends SDKConstruct {
485
584
  async changeDebt({
486
585
  creditAccount,
487
586
  amount,
488
- addCollateral
587
+ collateral
489
588
  }) {
490
589
  if (amount === 0n) {
491
590
  throw new Error("debt increase or decrease must be non-zero");
@@ -499,22 +598,32 @@ class AbstractCreditAccountService extends SDKConstruct {
499
598
  creditManager: creditAccount.creditManager,
500
599
  creditAccount
501
600
  });
502
- const addCollateralCalls = addCollateral && isDecrease ? this.prepareAddCollateral(
601
+ const addCollateralCalls = collateral && isDecrease ? this.prepareAddCollateral(
503
602
  creditAccount.creditFacade,
504
603
  [
505
604
  {
506
- token: creditAccount.underlying,
507
- balance: change
605
+ token: collateral[0].token,
606
+ balance: collateral[0].balance
508
607
  }
509
608
  ],
510
609
  {}
511
610
  ) : [];
611
+ const unwrapCalls = collateral && isDecrease ? await this.getKYCUnwrapCalls(
612
+ collateral[0].balance,
613
+ creditAccount.creditManager
614
+ ) || [] : [];
615
+ if (addCollateralCalls.length > 0 && unwrapCalls.length === 0 && collateral && collateral?.[0].token !== creditAccount.underlying) {
616
+ throw new Error(
617
+ "Can't use collateral other than underlying for non KYC market"
618
+ );
619
+ }
512
620
  const calls = [
513
621
  ...priceUpdatesCalls,
514
622
  ...addCollateralCalls,
623
+ ...unwrapCalls,
515
624
  this.#prepareChangeDebt(creditAccount.creditFacade, change, isDecrease)
516
625
  ];
517
- const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
626
+ const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
518
627
  return { tx, calls, creditFacade: cm.creditFacade };
519
628
  }
520
629
  /**
@@ -549,7 +658,7 @@ class AbstractCreditAccountService extends SDKConstruct {
549
658
  averageQuota
550
659
  })
551
660
  ];
552
- const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
661
+ const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
553
662
  return { tx, calls, creditFacade: cm.creditFacade };
554
663
  }
555
664
  /**
@@ -665,7 +774,7 @@ class AbstractCreditAccountService extends SDKConstruct {
665
774
  averageQuota
666
775
  })
667
776
  ];
668
- const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
777
+ const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
669
778
  return { tx, calls, creditFacade: cm.creditFacade };
670
779
  }
671
780
  /**
@@ -730,48 +839,63 @@ class AbstractCreditAccountService extends SDKConstruct {
730
839
  compareBalances,
731
840
  ...quotaCalls
732
841
  ];
733
- const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
842
+ const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
734
843
  return { tx, calls, creditFacade: cm.creditFacade };
735
844
  }
845
+ /**
846
+ * Returns address to which approval should be given on collateral token
847
+ * It's credit manager for classical markets and special wallet for KYC markets
848
+ * @param options - {@link GetApprovalAddressProps}
849
+ * @returns
850
+ **/
851
+ async getApprovalAddress(options) {
852
+ const { creditManager } = options;
853
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
854
+ const marketSuite = this.sdk.marketRegister.findByPool(suite.pool);
855
+ const factory = await marketSuite.getKYCFactory();
856
+ if (factory) {
857
+ if ("creditAccount" in options) {
858
+ return factory.getWallet(options.creditAccount);
859
+ }
860
+ return factory.precomputeWalletAddress(creditManager, options.borrower);
861
+ }
862
+ return suite.creditManager.address;
863
+ }
736
864
  /**
737
865
  * 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}
866
+ * - Open credit account is executed in the following order: price update -> increase debt -> add collateral ->
867
+ * -> update quotas -> (optionally: execute swap path for trading/strategy) ->
868
+ * -> (optionally: withdraw debt for lending)
869
+ *- Basic open credit account: price update -> increase debt -> add collateral -> update quotas
870
+ *- Lending: price update -> increase debt -> add collateral -> update quotas -> withdraw debt
871
+ *- Strategy/trading: price update -> increase debt -> add collateral -> update quotas -> execute swap path
872
+ *- In strategy is possible situation when collateral is added, but not swapped; the only swapped value in this case will be debt
758
873
  * @returns All necessary data to execute the transaction (call, credit facade)
759
- */
760
- async openCA({
761
- ethAmount,
762
- creditManager,
763
- collateral,
764
- permits,
765
- debt,
766
- withdrawDebt,
767
- referralCode,
768
- to,
769
- calls: openPathCalls,
770
- minQuota,
771
- averageQuota
772
- }) {
874
+ **/
875
+ async openCA(props) {
876
+ const {
877
+ ethAmount,
878
+ creditManager,
879
+ reopenCreditAccount,
880
+ collateral,
881
+ permits,
882
+ debt,
883
+ withdrawToken,
884
+ referralCode,
885
+ to,
886
+ calls: openPathCalls,
887
+ callsAfter,
888
+ minQuota,
889
+ averageQuota
890
+ } = props;
773
891
  const cmSuite = this.sdk.marketRegister.findCreditManager(creditManager);
774
892
  const cm = cmSuite.creditManager;
893
+ let tokenToWithdraw;
894
+ if (withdrawToken === true) {
895
+ tokenToWithdraw = cm.underlying;
896
+ } else if (typeof withdrawToken === "string") {
897
+ tokenToWithdraw = withdrawToken;
898
+ }
775
899
  const priceUpdatesCalls = await this.getPriceUpdatesForFacade({
776
900
  creditManager: cm.address,
777
901
  desiredQuotas: averageQuota
@@ -781,13 +905,27 @@ class AbstractCreditAccountService extends SDKConstruct {
781
905
  this.#prepareIncreaseDebt(cm.creditFacade, debt),
782
906
  ...this.prepareAddCollateral(cm.creditFacade, collateral, permits),
783
907
  ...openPathCalls,
784
- ...withdrawDebt ? [this.prepareWithdrawToken(cm.creditFacade, cm.underlying, debt, to)] : [],
908
+ // путь из underlying в withdrawal token
909
+ ...tokenToWithdraw ? [
910
+ this.prepareWithdrawToken(
911
+ cm.creditFacade,
912
+ tokenToWithdraw,
913
+ MAX_UINT256,
914
+ to
915
+ )
916
+ ] : [],
785
917
  ...this.prepareUpdateQuotas(cm.creditFacade, {
786
918
  minQuota,
787
919
  averageQuota
788
- })
920
+ }),
921
+ ...callsAfter ?? []
789
922
  ];
790
- const tx = cmSuite.creditFacade.openCreditAccount(to, calls, referralCode);
923
+ let tx;
924
+ if (reopenCreditAccount) {
925
+ tx = await this.multicallTx(cmSuite, reopenCreditAccount, calls);
926
+ } else {
927
+ tx = await this.openCreditAccountTx(cmSuite, to, calls, referralCode);
928
+ }
791
929
  tx.value = ethAmount.toString(10);
792
930
  return { calls, tx, creditFacade: cmSuite.creditFacade };
793
931
  }
@@ -871,6 +1009,130 @@ class AbstractCreditAccountService extends SDKConstruct {
871
1009
  );
872
1010
  return resp;
873
1011
  }
1012
+ /**
1013
+ * Returns multicall entries to redeem (unwrap) KYC ERC-4626 vault shares into underlying for the given credit manager.
1014
+ * Used when withdrawing debt from a KYC market: redeems adapter vault shares so the underlying can be withdrawn.
1015
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
1016
+ * @param amount - Number of vault shares (adapter tokens) to redeem
1017
+ * @param creditManager - Credit manager address
1018
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
1019
+ */
1020
+ async getKYCUnwrapCalls(amount, creditManager) {
1021
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
1022
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
1023
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
1024
+ return void 0;
1025
+ }
1026
+ const adapter = suite.creditManager.adapters.get(meta.addr);
1027
+ const adapterAddress = adapter?.address;
1028
+ if (!adapterAddress) {
1029
+ return void 0;
1030
+ }
1031
+ const mc = [
1032
+ {
1033
+ target: adapterAddress,
1034
+ callData: encodeFunctionData({
1035
+ abi: ierc4626AdapterAbi,
1036
+ functionName: "redeem",
1037
+ args: [amount, ADDRESS_0X0, ADDRESS_0X0]
1038
+ })
1039
+ }
1040
+ ];
1041
+ return mc;
1042
+ }
1043
+ /**
1044
+ * Returns multicall entries to deposit (wrap) underlying into KYC ERC-4626 vault shares for the given credit manager.
1045
+ * Used when adding debt on a KYC market: deposits underlying into the adapter vault so shares are minted on the account.
1046
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
1047
+ * @param amount - Amount of underlying assets to deposit into the vault (in underlying decimals)
1048
+ * @param creditManager - Credit manager address
1049
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
1050
+ */
1051
+ async getKYCWrapCalls(amount, creditManager) {
1052
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
1053
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
1054
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
1055
+ return void 0;
1056
+ }
1057
+ const adapter = suite.creditManager.adapters.get(meta.addr);
1058
+ const adapterAddress = adapter?.address;
1059
+ if (!adapterAddress) {
1060
+ return void 0;
1061
+ }
1062
+ const mc = [
1063
+ {
1064
+ target: adapterAddress,
1065
+ callData: encodeFunctionData({
1066
+ abi: ierc4626AdapterAbi,
1067
+ functionName: "deposit",
1068
+ args: [amount, ADDRESS_0X0]
1069
+ })
1070
+ }
1071
+ ];
1072
+ return mc;
1073
+ }
1074
+ /**
1075
+ * Returns multicall entries to call redeemDiff on the KYC ERC-4626 adapter for the given credit manager.
1076
+ * Redeems the leftover vault shares (e.g. after repaying debt) so the account does not hold excess KYC vault tokens.
1077
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
1078
+ * @param amount - Leftover vault share amount to redeem (in adapter/vault decimals)
1079
+ * @param creditManager - Credit manager address
1080
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
1081
+ */
1082
+ async getRedeemDiffCalls(amount, creditManager) {
1083
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
1084
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
1085
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
1086
+ return void 0;
1087
+ }
1088
+ const adapter = suite.creditManager.adapters.get(meta.addr);
1089
+ const adapterAddress = adapter?.address;
1090
+ if (!adapterAddress) {
1091
+ return void 0;
1092
+ }
1093
+ const mc = [
1094
+ {
1095
+ target: adapterAddress,
1096
+ callData: encodeFunctionData({
1097
+ abi: ierc4626AdapterAbi,
1098
+ functionName: "redeemDiff",
1099
+ args: [amount]
1100
+ })
1101
+ }
1102
+ ];
1103
+ return mc;
1104
+ }
1105
+ /**
1106
+ * Returns multicall entries to call depositDiff on the KYC ERC-4626 adapter for the given credit manager.
1107
+ * Deposits the leftover underlying (e.g. after decreasing debt) into the vault so the account does not hold excess underlying.
1108
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
1109
+ * @param amount - Leftover underlying amount to deposit into the vault (in underlying decimals)
1110
+ * @param creditManager - Credit manager address
1111
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
1112
+ */
1113
+ async getDepositDiffCalls(amount, creditManager) {
1114
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
1115
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
1116
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
1117
+ return void 0;
1118
+ }
1119
+ const adapter = suite.creditManager.adapters.get(meta.addr);
1120
+ const adapterAddress = adapter?.address;
1121
+ if (!adapterAddress) {
1122
+ return void 0;
1123
+ }
1124
+ const mc = [
1125
+ {
1126
+ target: adapterAddress,
1127
+ callData: encodeFunctionData({
1128
+ abi: ierc4626AdapterAbi,
1129
+ functionName: "depositDiff",
1130
+ args: [amount]
1131
+ })
1132
+ }
1133
+ ];
1134
+ return mc;
1135
+ }
874
1136
  /**
875
1137
  * Returns raw txs that are needed to update all price feeds so that all credit accounts (possibly from different markets) compute
876
1138
  *
@@ -1098,78 +1360,174 @@ class AbstractCreditAccountService extends SDKConstruct {
1098
1360
  VERSION_RANGE_310
1099
1361
  )[0];
1100
1362
  }
1363
+ /**
1364
+ * Wrapper that selects between credit facade and KYC factory
1365
+ * @param suite
1366
+ * @param to
1367
+ * @param calls
1368
+ * @param referralCode
1369
+ * @returns
1370
+ */
1371
+ async openCreditAccountTx(suite, to, calls, referralCode) {
1372
+ const marketSuite = this.sdk.marketRegister.findByPool(suite.pool);
1373
+ const factory = await marketSuite.getKYCFactory();
1374
+ if (factory) {
1375
+ const tokensToRegister = await factory.getDSTokens();
1376
+ return factory.openCreditAccount(
1377
+ suite.creditManager.address,
1378
+ calls,
1379
+ tokensToRegister
1380
+ );
1381
+ }
1382
+ return suite.creditFacade.openCreditAccount(to, calls, referralCode ?? 0n);
1383
+ }
1384
+ /**
1385
+ * Wrapper that selects between credit facade and KYC factory
1386
+ * @param suite
1387
+ * @param creditAccount
1388
+ * @param calls
1389
+ * @returns
1390
+ */
1391
+ async multicallTx(suite, creditAccount, calls) {
1392
+ const marketSuite = this.sdk.marketRegister.findByCreditManager(
1393
+ suite.creditManager.address
1394
+ );
1395
+ const factory = await marketSuite.getKYCFactory();
1396
+ if (factory) {
1397
+ const tokensToRegister = [];
1398
+ return factory.multicall(creditAccount, calls, tokensToRegister);
1399
+ }
1400
+ return suite.creditFacade.multicall(creditAccount, calls);
1401
+ }
1402
+ /**
1403
+ * Wrapper that selects between credit facade and KYC factory
1404
+ * @param suite
1405
+ * @param creditAccount
1406
+ * @param calls
1407
+ * @param operation
1408
+ * @returns
1409
+ */
1410
+ async closeCreditAccountTx(suite, creditAccount, calls, operation) {
1411
+ const marketSuite = this.sdk.marketRegister.findByCreditManager(
1412
+ suite.creditManager.address
1413
+ );
1414
+ const factory = await marketSuite.getKYCFactory();
1415
+ if (operation === "close") {
1416
+ if (factory) {
1417
+ throw new Error(
1418
+ "CloseOptions=close is not supported for KYC underlying credit accounts"
1419
+ );
1420
+ }
1421
+ return suite.creditFacade.closeCreditAccount(creditAccount, calls);
1422
+ }
1423
+ if (factory) {
1424
+ const tokensToRegister = [];
1425
+ return factory.multicall(creditAccount, calls, tokensToRegister);
1426
+ }
1427
+ return suite.creditFacade.multicall(creditAccount, calls);
1428
+ }
1429
+ /**
1430
+ * Returns all KYC credit account addresses for an investor across the given market suites.
1431
+ * Resolves KYC factory per suite, then multicalls each factory's getCreditAccounts(investor).
1432
+ * @param investor - Owner address to query
1433
+ * @param suites - Market suites (KYC factories are resolved for each; undefined entries are skipped)
1434
+ * @returns Flat array of credit account addresses from all KYC markets
1435
+ */
1436
+ async getKYCCaOfInvestor(investor, suites) {
1437
+ if (suites.length === 0 || investor === ADDRESS_0X0) return [];
1438
+ const factories = await Promise.all(
1439
+ suites.map((suite) => suite ? suite.getKYCFactory() : void 0)
1440
+ );
1441
+ const safeFactories = factories.reduce(
1442
+ (acc, v) => {
1443
+ if (v) {
1444
+ acc.push(v);
1445
+ }
1446
+ return acc;
1447
+ },
1448
+ []
1449
+ );
1450
+ const allResp = await this.client.multicall({
1451
+ contracts: [
1452
+ ...safeFactories.map((factory) => {
1453
+ return {
1454
+ abi: factory.abi,
1455
+ address: factory.address,
1456
+ functionName: "getCreditAccounts",
1457
+ args: [investor]
1458
+ };
1459
+ })
1460
+ ],
1461
+ allowFailure: true,
1462
+ batchSize: 0
1463
+ });
1464
+ const caLists = safeFactories.reduce((acc, _, index) => {
1465
+ const response = allResp[index];
1466
+ acc.push(...response.result || []);
1467
+ return acc;
1468
+ }, []);
1469
+ return caLists;
1470
+ }
1101
1471
  }
1102
- const iMellowClaimerAdapterAbi = [
1472
+ const ierc4626AdapterAbi = [
1103
1473
  {
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
- }
1474
+ inputs: [
1475
+ { name: "assets", type: "uint256", internalType: "uint256" },
1476
+ { name: "receiver", type: "address", internalType: "address" }
1118
1477
  ],
1119
- stateMutability: "view"
1478
+ name: "deposit",
1479
+ outputs: [{ name: "useSafePrices", type: "bool", internalType: "bool" }],
1480
+ stateMutability: "nonpayable",
1481
+ type: "function"
1120
1482
  },
1121
1483
  {
1122
- type: "function",
1123
- name: "getUserSubvaultIndices",
1124
1484
  inputs: [
1125
- { name: "multiVault", type: "address", internalType: "address" },
1126
- { name: "user", type: "address", internalType: "address" }
1485
+ { name: "shares", type: "uint256", internalType: "uint256" },
1486
+ { name: "receiver", type: "address", internalType: "address" },
1487
+ { name: "owner", type: "address", internalType: "address" }
1127
1488
  ],
1128
- outputs: [
1489
+ name: "redeem",
1490
+ outputs: [{ name: "useSafePrices", type: "bool", internalType: "bool" }],
1491
+ stateMutability: "nonpayable",
1492
+ type: "function"
1493
+ },
1494
+ {
1495
+ inputs: [
1129
1496
  {
1130
- name: "subvaultIndices",
1131
- type: "uint256[]",
1132
- internalType: "uint256[]"
1133
- },
1497
+ name: "leftoverAmount",
1498
+ type: "uint256",
1499
+ internalType: "uint256"
1500
+ }
1501
+ ],
1502
+ name: "redeemDiff",
1503
+ outputs: [
1134
1504
  {
1135
- name: "withdrawalIndices",
1136
- type: "uint256[][]",
1137
- internalType: "uint256[][]"
1505
+ name: "useSafePrices",
1506
+ type: "bool",
1507
+ internalType: "bool"
1138
1508
  }
1139
1509
  ],
1140
- stateMutability: "view"
1510
+ stateMutability: "nonpayable",
1511
+ type: "function"
1141
1512
  },
1142
1513
  {
1143
- type: "function",
1144
- name: "multiAccept",
1145
1514
  inputs: [
1146
- { name: "multiVault", type: "address", internalType: "address" },
1147
1515
  {
1148
- name: "subvaultIndices",
1149
- type: "uint256[]",
1150
- internalType: "uint256[]"
1151
- },
1152
- { name: "indices", type: "uint256[][]", internalType: "uint256[][]" }
1516
+ name: "leftoverAmount",
1517
+ type: "uint256",
1518
+ internalType: "uint256"
1519
+ }
1153
1520
  ],
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" },
1521
+ name: "depositDiff",
1522
+ outputs: [
1162
1523
  {
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" }
1524
+ name: "useSafePrices",
1525
+ type: "bool",
1526
+ internalType: "bool"
1527
+ }
1170
1528
  ],
1171
- outputs: [{ name: "", type: "bool", internalType: "bool" }],
1172
- stateMutability: "nonpayable"
1529
+ stateMutability: "nonpayable",
1530
+ type: "function"
1173
1531
  }
1174
1532
  ];
1175
1533
  export {