@gearbox-protocol/sdk 14.0.0-next.9 → 14.1.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 (119) hide show
  1. package/dist/cjs/abi/kyc/iDSRegistryService.js +149 -0
  2. package/dist/cjs/abi/kyc/iDSToken.js +71 -0
  3. package/dist/cjs/abi/kyc/iKYCCompressor.js +196 -0
  4. package/dist/cjs/abi/kyc/iKYCFactory.js +122 -0
  5. package/dist/cjs/abi/kyc/iKYCUnderlying.js +401 -0
  6. package/dist/cjs/abi/kyc/iSecuritizeDegenNFT.js +326 -0
  7. package/dist/cjs/abi/kyc/iSecuritizeKYCFactory.js +319 -0
  8. package/dist/cjs/dev/AccountOpener.js +45 -5
  9. package/dist/cjs/rewards/rewards/extra-apy.js +1 -1
  10. package/dist/cjs/sdk/MultichainSDK.js +5 -0
  11. package/dist/cjs/sdk/OnchainSDK.js +55 -6
  12. package/dist/cjs/sdk/accounts/AbstractCreditAccountsService.js +335 -21
  13. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +7 -1
  14. package/dist/cjs/sdk/base/TokensMeta.js +22 -42
  15. package/dist/cjs/sdk/base/token-types.js +9 -0
  16. package/dist/cjs/sdk/chain/chains.js +18 -1
  17. package/dist/cjs/sdk/constants/address-provider.js +3 -0
  18. package/dist/cjs/sdk/market/MarketRegister.js +70 -116
  19. package/dist/cjs/sdk/market/MarketSuite.js +3 -0
  20. package/dist/cjs/sdk/market/index.js +2 -0
  21. package/dist/cjs/sdk/market/kyc/KYCRegistry.js +269 -0
  22. package/dist/cjs/sdk/market/kyc/index.js +26 -0
  23. package/dist/cjs/sdk/market/kyc/securitize/SecuritizeKYCFactory.js +242 -0
  24. package/dist/cjs/sdk/market/kyc/securitize/constants.js +28 -0
  25. package/dist/cjs/sdk/market/kyc/securitize/index.js +26 -0
  26. package/dist/cjs/sdk/market/kyc/securitize/types.js +16 -0
  27. package/dist/cjs/sdk/{accounts/utils.js → market/kyc/types.js} +11 -15
  28. package/dist/cjs/sdk/market/pool/PoolSuite.js +3 -0
  29. package/dist/cjs/sdk/market/pool/PoolV310Contract.js +11 -2
  30. package/dist/cjs/sdk/market/pool/index.js +2 -0
  31. package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +3 -3
  32. package/dist/cjs/sdk/options.js +6 -0
  33. package/dist/cjs/sdk/pools/PoolService.js +104 -12
  34. package/dist/cjs/sdk/utils/viem/executeDelegatedMulticalls.js +38 -0
  35. package/dist/cjs/sdk/utils/viem/index.js +2 -4
  36. package/dist/esm/abi/kyc/iDSRegistryService.js +125 -0
  37. package/dist/esm/abi/kyc/iDSToken.js +47 -0
  38. package/dist/esm/abi/kyc/iKYCCompressor.js +172 -0
  39. package/dist/esm/abi/kyc/iKYCFactory.js +98 -0
  40. package/dist/esm/abi/kyc/iKYCUnderlying.js +377 -0
  41. package/dist/esm/abi/kyc/iSecuritizeDegenNFT.js +302 -0
  42. package/dist/esm/abi/kyc/iSecuritizeKYCFactory.js +295 -0
  43. package/dist/esm/dev/AccountOpener.js +47 -6
  44. package/dist/esm/rewards/rewards/extra-apy.js +1 -1
  45. package/dist/esm/sdk/MultichainSDK.js +5 -0
  46. package/dist/esm/sdk/OnchainSDK.js +58 -7
  47. package/dist/esm/sdk/accounts/AbstractCreditAccountsService.js +336 -22
  48. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +7 -1
  49. package/dist/esm/sdk/base/TokensMeta.js +22 -44
  50. package/dist/esm/sdk/base/token-types.js +6 -0
  51. package/dist/esm/sdk/chain/chains.js +18 -1
  52. package/dist/esm/sdk/constants/address-provider.js +2 -0
  53. package/dist/esm/sdk/market/MarketRegister.js +74 -118
  54. package/dist/esm/sdk/market/MarketSuite.js +3 -0
  55. package/dist/esm/sdk/market/index.js +1 -0
  56. package/dist/esm/sdk/market/kyc/KYCRegistry.js +253 -0
  57. package/dist/esm/sdk/market/kyc/index.js +3 -0
  58. package/dist/esm/sdk/market/kyc/securitize/SecuritizeKYCFactory.js +218 -0
  59. package/dist/esm/sdk/market/kyc/securitize/constants.js +4 -0
  60. package/dist/esm/sdk/market/kyc/securitize/index.js +3 -0
  61. package/dist/esm/sdk/market/kyc/securitize/types.js +0 -0
  62. package/dist/esm/sdk/market/kyc/types.js +9 -0
  63. package/dist/esm/sdk/market/pool/PoolSuite.js +3 -0
  64. package/dist/esm/sdk/market/pool/PoolV310Contract.js +11 -2
  65. package/dist/esm/sdk/market/pool/index.js +1 -0
  66. package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +3 -3
  67. package/dist/esm/sdk/options.js +6 -0
  68. package/dist/esm/sdk/pools/PoolService.js +109 -13
  69. package/dist/esm/sdk/utils/viem/executeDelegatedMulticalls.js +14 -0
  70. package/dist/esm/sdk/utils/viem/index.js +1 -2
  71. package/dist/types/abi/kyc/iDSRegistryService.d.ts +191 -0
  72. package/dist/types/abi/kyc/iDSToken.d.ts +67 -0
  73. package/dist/types/abi/kyc/iKYCCompressor.d.ts +228 -0
  74. package/dist/types/abi/kyc/iKYCFactory.d.ts +139 -0
  75. package/dist/types/abi/kyc/iKYCUnderlying.d.ts +548 -0
  76. package/dist/types/abi/kyc/iSecuritizeDegenNFT.d.ts +404 -0
  77. package/dist/types/abi/kyc/iSecuritizeKYCFactory.d.ts +376 -0
  78. package/dist/types/sdk/OnchainSDK.d.ts +19 -1
  79. package/dist/types/sdk/accounts/AbstractCreditAccountsService.d.ts +59 -6
  80. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +1 -1
  81. package/dist/types/sdk/accounts/types.d.ts +114 -14
  82. package/dist/types/sdk/base/TokensMeta.d.ts +14 -3
  83. package/dist/types/sdk/base/token-types.d.ts +44 -4
  84. package/dist/types/sdk/base/types.d.ts +116 -2
  85. package/dist/types/sdk/chain/chains.d.ts +5 -1
  86. package/dist/types/sdk/constants/address-provider.d.ts +1 -0
  87. package/dist/types/sdk/market/MarketRegister.d.ts +6 -9
  88. package/dist/types/sdk/market/MarketSuite.d.ts +2 -0
  89. package/dist/types/sdk/market/index.d.ts +1 -0
  90. package/dist/types/sdk/market/kyc/KYCRegistry.d.ts +52 -0
  91. package/dist/types/sdk/market/kyc/index.d.ts +3 -0
  92. package/dist/types/sdk/market/kyc/securitize/SecuritizeKYCFactory.d.ts +429 -0
  93. package/dist/types/sdk/market/kyc/securitize/constants.d.ts +1 -0
  94. package/dist/types/sdk/market/kyc/securitize/index.d.ts +3 -0
  95. package/dist/types/sdk/market/kyc/securitize/types.d.ts +136 -0
  96. package/dist/types/sdk/market/kyc/types.d.ts +171 -0
  97. package/dist/types/sdk/market/oracle/PriceOracleBaseContract.d.ts +3 -2
  98. package/dist/types/sdk/market/oracle/types.d.ts +3 -10
  99. package/dist/types/sdk/market/pool/PoolSuite.d.ts +2 -0
  100. package/dist/types/sdk/market/pool/PoolV310Contract.d.ts +6 -2
  101. package/dist/types/sdk/market/pool/index.d.ts +1 -0
  102. package/dist/types/sdk/market/pricefeeds/PriceFeedsRegister.d.ts +1 -1
  103. package/dist/types/sdk/market/types.d.ts +1 -1
  104. package/dist/types/sdk/options.d.ts +1 -0
  105. package/dist/types/sdk/pools/PoolService.d.ts +8 -8
  106. package/dist/types/sdk/pools/types.d.ts +1 -1
  107. package/dist/types/sdk/types/state-human.d.ts +2 -0
  108. package/dist/types/sdk/types/state.d.ts +5 -0
  109. package/dist/types/sdk/utils/viem/executeDelegatedMulticalls.d.ts +28 -0
  110. package/dist/types/sdk/utils/viem/index.d.ts +1 -2
  111. package/package.json +4 -4
  112. package/dist/cjs/sdk/utils/viem/getLogsPaginated.js +0 -62
  113. package/dist/cjs/sdk/utils/viem/getLogsSafe.js +0 -87
  114. package/dist/esm/sdk/accounts/utils.js +0 -14
  115. package/dist/esm/sdk/utils/viem/getLogsPaginated.js +0 -38
  116. package/dist/esm/sdk/utils/viem/getLogsSafe.js +0 -65
  117. package/dist/types/sdk/accounts/utils.d.ts +0 -2
  118. package/dist/types/sdk/utils/viem/getLogsPaginated.d.ts +0 -12
  119. package/dist/types/sdk/utils/viem/getLogsSafe.d.ts +0 -3
@@ -1,3 +1,4 @@
1
+ import { ierc4626AdapterAbi } from "@gearbox-protocol/integrations-v3";
1
2
  import { encodeFunctionData, getContract } from "viem";
2
3
  import {
3
4
  iBotListV310Abi,
@@ -8,6 +9,7 @@ import { peripheryCompressorAbi } from "../../abi/compressors/peripheryCompresso
8
9
  import { rewardsCompressorAbi } from "../../abi/compressors/rewardsCompressor.js";
9
10
  import { iWithdrawalCompressorV310Abi } from "../../abi/IWithdrawalCompressorV310.js";
10
11
  import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
12
+ import { iKYCFactoryAbi } from "../../abi/kyc/iKYCFactory.js";
11
13
  import { SDKConstruct } from "../base/index.js";
12
14
  import { chains } from "../chain/chains.js";
13
15
  import {
@@ -25,7 +27,7 @@ import {
25
27
  getRawPriceUpdates
26
28
  } from "../market/index.js";
27
29
  import { assetsMap } from "../router/index.js";
28
- import { AddressMap, AddressSet } from "../utils/index.js";
30
+ import { AddressMap, AddressSet, hexEq } from "../utils/index.js";
29
31
  import { simulateWithPriceUpdates } from "../utils/viem/index.js";
30
32
  import {
31
33
  extractPriceUpdates,
@@ -71,24 +73,40 @@ class AbstractCreditAccountService extends SDKConstruct {
71
73
  } catch (_e) {
72
74
  return void 0;
73
75
  }
76
+ const marketSuite = this.sdk.marketRegister.findByCreditManager(
77
+ raw.creditManager
78
+ );
79
+ const factory = marketSuite.kycFactory;
80
+ let ca;
81
+ let investor;
74
82
  if (raw.success) {
75
- return raw;
83
+ ca = raw;
84
+ investor = await factory?.getInvestor(raw.creditAccount, false);
85
+ } else {
86
+ const { txs: priceUpdateTxs } = await this.getUpdateForAccount(raw);
87
+ [ca, investor] = await simulateWithPriceUpdates(this.client, {
88
+ priceUpdates: priceUpdateTxs,
89
+ contracts: [
90
+ {
91
+ abi: creditAccountCompressorAbi,
92
+ address: this.#compressor,
93
+ functionName: "getCreditAccountData",
94
+ args: [account]
95
+ },
96
+ ...factory ? [
97
+ {
98
+ abi: iKYCFactoryAbi,
99
+ address: factory.address,
100
+ functionName: "getInvestor",
101
+ args: [raw.creditAccount]
102
+ }
103
+ ] : []
104
+ ],
105
+ blockNumber,
106
+ gas: this.sdk.gasLimit
107
+ });
76
108
  }
77
- const { txs: priceUpdateTxs } = await this.getUpdateForAccount(raw);
78
- const [cad] = await simulateWithPriceUpdates(this.client, {
79
- priceUpdates: priceUpdateTxs,
80
- contracts: [
81
- {
82
- abi: creditAccountCompressorAbi,
83
- address: this.#compressor,
84
- functionName: "getCreditAccountData",
85
- args: [account]
86
- }
87
- ],
88
- blockNumber,
89
- gas: this.sdk.gasLimit
90
- });
91
- return cad;
109
+ return { ...ca, investor };
92
110
  }
93
111
  /**
94
112
  * {@inheritDoc ICreditAccountsService.getCreditAccounts}
@@ -144,6 +162,99 @@ class AbstractCreditAccountService extends SDKConstruct {
144
162
  );
145
163
  return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
146
164
  }
165
+ /**
166
+ * {@inheritDoc ICreditAccountsService.getBorrowerCreditAccounts}
167
+ **/
168
+ async getBorrowerCreditAccounts(borrower, options, blockNumber) {
169
+ const {
170
+ creditManager,
171
+ includeZeroDebt = false,
172
+ maxHealthFactor = MAX_UINT256,
173
+ minHealthFactor = 0n,
174
+ ignoreReservePrices = false
175
+ } = options ?? {};
176
+ const { txs: priceUpdateTxs } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(
177
+ ignoreReservePrices ? { main: true } : void 0
178
+ );
179
+ const investorDataList = await this.sdk.kyc.getInvestorData(borrower);
180
+ const kycAccountAddresses = investorDataList.flatMap(
181
+ (d) => d.creditAccounts.map((ca) => ca.creditAccount)
182
+ );
183
+ const cmFilter = creditManager ? {
184
+ configurators: [],
185
+ creditManagers: [creditManager],
186
+ pools: [],
187
+ underlying: ADDRESS_0X0
188
+ } : {
189
+ configurators: this.marketConfigurators,
190
+ creditManagers: [],
191
+ pools: [],
192
+ underlying: ADDRESS_0X0
193
+ };
194
+ const permissiveFilter = {
195
+ owner: borrower,
196
+ includeZeroDebt: true,
197
+ minHealthFactor: 0n,
198
+ maxHealthFactor: MAX_UINT256,
199
+ reverting: false
200
+ };
201
+ const kycContracts = kycAccountAddresses.map(
202
+ (account) => ({
203
+ abi: creditAccountCompressorAbi,
204
+ address: this.#compressor,
205
+ functionName: "getCreditAccountData",
206
+ args: [account]
207
+ })
208
+ );
209
+ const getCreditAccountsContracts = [false, true].map(
210
+ (reverting) => ({
211
+ abi: creditAccountCompressorAbi,
212
+ address: this.#compressor,
213
+ functionName: "getCreditAccounts",
214
+ args: [cmFilter, { ...permissiveFilter, reverting }, 0n]
215
+ })
216
+ );
217
+ const allContracts = [...kycContracts, ...getCreditAccountsContracts];
218
+ const results = await simulateWithPriceUpdates(this.client, {
219
+ priceUpdates: priceUpdateTxs,
220
+ contracts: allContracts,
221
+ blockNumber,
222
+ gas: this.sdk.gasLimit
223
+ });
224
+ const kycResults = results.slice(
225
+ 0,
226
+ kycAccountAddresses.length
227
+ );
228
+ const normalResults = results.slice(kycAccountAddresses.length);
229
+ const seen = new AddressSet();
230
+ const allCAs = [];
231
+ for (const ca of kycResults) {
232
+ if (!seen.has(ca.creditAccount)) {
233
+ seen.add(ca.creditAccount);
234
+ allCAs.push({ ...ca, investor: borrower });
235
+ }
236
+ }
237
+ for (const [accounts] of normalResults) {
238
+ for (const ca of accounts) {
239
+ if (!seen.has(ca.creditAccount)) {
240
+ seen.add(ca.creditAccount);
241
+ allCAs.push({ ...ca, investor: void 0 });
242
+ }
243
+ }
244
+ }
245
+ const filtered = allCAs.filter((ca) => {
246
+ if (!includeZeroDebt && ca.debt === 0n) return false;
247
+ if (ca.healthFactor < minHealthFactor) return false;
248
+ if (ca.healthFactor > maxHealthFactor) return false;
249
+ if (creditManager && !hexEq(ca.creditManager, creditManager))
250
+ return false;
251
+ return true;
252
+ });
253
+ this.logger?.debug(
254
+ `loaded ${allCAs.length} borrower credit accounts (${kycResults.length} KYC, ${filtered.length} after filter)`
255
+ );
256
+ return filtered.sort((a, b) => Number(a.healthFactor - b.healthFactor));
257
+ }
147
258
  /**
148
259
  * {@inheritDoc ICreditAccountsService.getRewards}
149
260
  **/
@@ -353,6 +464,13 @@ class AbstractCreditAccountService extends SDKConstruct {
353
464
  closePath
354
465
  }) {
355
466
  const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
467
+ await this.sdk.tokensMeta.loadTokenData(cm.underlying);
468
+ const underlying = this.sdk.tokensMeta.mustGet(cm.underlying);
469
+ if (this.sdk.tokensMeta.isKYCUnderlying(underlying)) {
470
+ throw new Error(
471
+ "closeCreditAccount is not supported for KYC underlying credit accounts"
472
+ );
473
+ }
356
474
  const routerCloseResult = closePath || await this.sdk.routerFor(ca).findBestClosePath({
357
475
  creditAccount: ca,
358
476
  creditManager: cm.creditManager,
@@ -458,8 +576,18 @@ class AbstractCreditAccountService extends SDKConstruct {
458
576
  ],
459
577
  {}
460
578
  ) : [];
579
+ const unwrapCalls = collateral && isDecrease ? await this.getKYCUnwrapCalls(
580
+ collateral[0].balance,
581
+ creditAccount.creditManager
582
+ ) || [] : [];
583
+ if (addCollateralCalls.length > 0 && unwrapCalls.length === 0 && collateral && collateral?.[0].token !== creditAccount.underlying) {
584
+ throw new Error(
585
+ "Can't use collateral other than underlying for non KYC market"
586
+ );
587
+ }
461
588
  const operationCalls = [
462
589
  ...addCollateralCalls,
590
+ ...unwrapCalls,
463
591
  this.#prepareChangeDebt(creditAccount.creditFacade, change, isDecrease)
464
592
  ];
465
593
  const calls = await this.prependPriceUpdates(
@@ -667,6 +795,29 @@ class AbstractCreditAccountService extends SDKConstruct {
667
795
  const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
668
796
  return { tx, calls, creditFacade: cm.creditFacade };
669
797
  }
798
+ /**
799
+ * {@inheritDoc ICreditAccountsService.getApprovalAddress}
800
+ **/
801
+ async getApprovalAddress(options) {
802
+ const { creditManager } = options;
803
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
804
+ const marketSuite = this.sdk.marketRegister.findByPool(suite.pool);
805
+ const factory = marketSuite.kycFactory;
806
+ if (factory) {
807
+ return factory.getApprovalAddress(options);
808
+ }
809
+ return suite.creditManager.address;
810
+ }
811
+ /**
812
+ * {@inheritDoc ICreditAccountsService.getOpenAccountRequirements}
813
+ */
814
+ async getOpenAccountRequirements(borrower, creditManager, props) {
815
+ const { kycFactory } = this.sdk.marketRegister.findByCreditManager(creditManager);
816
+ if (!kycFactory) {
817
+ return void 0;
818
+ }
819
+ return kycFactory.getOpenAccountRequirements(borrower, props);
820
+ }
670
821
  /**
671
822
  * {@inheritDoc ICreditAccountsService.openCA}
672
823
  **/
@@ -684,7 +835,8 @@ class AbstractCreditAccountService extends SDKConstruct {
684
835
  calls: openPathCalls,
685
836
  callsAfter,
686
837
  minQuota,
687
- averageQuota
838
+ averageQuota,
839
+ kycOptions
688
840
  } = props;
689
841
  const cmSuite = this.sdk.marketRegister.findCreditManager(creditManager);
690
842
  const cm = cmSuite.creditManager;
@@ -718,7 +870,13 @@ class AbstractCreditAccountService extends SDKConstruct {
718
870
  if (reopenCreditAccount) {
719
871
  tx = await this.multicallTx(cmSuite, reopenCreditAccount, calls);
720
872
  } else {
721
- tx = await this.openCreditAccountTx(cmSuite, to, calls, referralCode);
873
+ tx = await this.openCreditAccountTx(
874
+ cmSuite,
875
+ to,
876
+ calls,
877
+ referralCode,
878
+ kycOptions
879
+ );
722
880
  }
723
881
  tx.value = ethAmount.toString(10);
724
882
  return { calls, tx, creditFacade: cmSuite.creditFacade };
@@ -801,6 +959,131 @@ class AbstractCreditAccountService extends SDKConstruct {
801
959
  return resp;
802
960
  }
803
961
  /**
962
+ * Returns multicall entries to redeem (unwrap) KYC ERC-4626 vault shares into underlying for the given credit manager.
963
+ * Used when withdrawing debt from a KYC market: redeems adapter vault shares so the underlying can be withdrawn.
964
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
965
+ * @param amount - Number of vault shares (adapter tokens) to redeem
966
+ * @param creditManager - Credit manager address
967
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
968
+ */
969
+ async getKYCUnwrapCalls(amount, creditManager) {
970
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
971
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
972
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
973
+ return void 0;
974
+ }
975
+ const adapter = suite.creditManager.adapters.get(meta.addr);
976
+ const adapterAddress = adapter?.address;
977
+ if (!adapterAddress) {
978
+ return void 0;
979
+ }
980
+ const mc = [
981
+ {
982
+ target: adapterAddress,
983
+ callData: encodeFunctionData({
984
+ abi: ierc4626AdapterAbi,
985
+ functionName: "redeem",
986
+ args: [amount, ADDRESS_0X0, ADDRESS_0X0]
987
+ })
988
+ }
989
+ ];
990
+ return mc;
991
+ }
992
+ /**
993
+ * Returns multicall entries to deposit (wrap) underlying into KYC ERC-4626 vault shares for the given credit manager.
994
+ * Used when adding debt on a KYC market: deposits underlying into the adapter vault so shares are minted on the account.
995
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
996
+ * @param amount - Amount of underlying assets to deposit into the vault (in underlying decimals)
997
+ * @param creditManager - Credit manager address
998
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
999
+ */
1000
+ async getKYCWrapCalls(amount, creditManager) {
1001
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
1002
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
1003
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
1004
+ return void 0;
1005
+ }
1006
+ const adapter = suite.creditManager.adapters.get(meta.addr);
1007
+ const adapterAddress = adapter?.address;
1008
+ if (!adapterAddress) {
1009
+ return void 0;
1010
+ }
1011
+ const mc = [
1012
+ {
1013
+ target: adapterAddress,
1014
+ callData: encodeFunctionData({
1015
+ abi: ierc4626AdapterAbi,
1016
+ functionName: "deposit",
1017
+ args: [amount, ADDRESS_0X0]
1018
+ })
1019
+ }
1020
+ ];
1021
+ return mc;
1022
+ }
1023
+ /**
1024
+ * Returns multicall entries to call redeemDiff on the KYC ERC-4626 adapter for the given credit manager.
1025
+ * Redeems the leftover vault shares (e.g. after repaying debt) so the account does not hold excess KYC vault tokens.
1026
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
1027
+ * @param amount - Leftover vault share amount to redeem (in adapter/vault decimals)
1028
+ * @param creditManager - Credit manager address
1029
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
1030
+ */
1031
+ async getRedeemDiffCalls(amount, creditManager) {
1032
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
1033
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
1034
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
1035
+ return void 0;
1036
+ }
1037
+ const adapter = suite.creditManager.adapters.get(meta.addr);
1038
+ const adapterAddress = adapter?.address;
1039
+ if (!adapterAddress) {
1040
+ return void 0;
1041
+ }
1042
+ const mc = [
1043
+ {
1044
+ target: adapterAddress,
1045
+ callData: encodeFunctionData({
1046
+ abi: ierc4626AdapterAbi,
1047
+ functionName: "redeemDiff",
1048
+ args: [amount]
1049
+ })
1050
+ }
1051
+ ];
1052
+ return mc;
1053
+ }
1054
+ /**
1055
+ * Returns multicall entries to call depositDiff on the KYC ERC-4626 adapter for the given credit manager.
1056
+ * Deposits the leftover underlying (e.g. after decreasing debt) into the vault so the account does not hold excess underlying.
1057
+ * Only applies when the credit manager's underlying is KYC-gated and has an ERC-4626 adapter configured.
1058
+ * @param amount - Leftover underlying amount to deposit into the vault (in underlying decimals)
1059
+ * @param creditManager - Credit manager address
1060
+ * @returns Array of MultiCall to pass to credit facade multicall, or undefined if underlying is not KYC or no adapter is configured
1061
+ */
1062
+ async getDepositDiffCalls(amount, creditManager) {
1063
+ const suite = this.sdk.marketRegister.findCreditManager(creditManager);
1064
+ const meta = this.sdk.tokensMeta.mustGet(suite.underlying);
1065
+ if (!this.sdk.tokensMeta.isKYCUnderlying(meta)) {
1066
+ return void 0;
1067
+ }
1068
+ const adapter = suite.creditManager.adapters.get(meta.addr);
1069
+ const adapterAddress = adapter?.address;
1070
+ if (!adapterAddress) {
1071
+ return void 0;
1072
+ }
1073
+ const mc = [
1074
+ {
1075
+ target: adapterAddress,
1076
+ callData: encodeFunctionData({
1077
+ abi: ierc4626AdapterAbi,
1078
+ functionName: "depositDiff",
1079
+ args: [amount]
1080
+ })
1081
+ }
1082
+ ];
1083
+ return mc;
1084
+ }
1085
+ /**
1086
+ * Returns raw txs that are needed to update all price feeds so that all credit accounts (possibly from different markets) compute
804
1087
  * {@inheritDoc ICreditAccountsService.getOnDemandPriceUpdates}
805
1088
  **/
806
1089
  async getOnDemandPriceUpdates(account, ignoreReservePrices) {
@@ -1055,9 +1338,19 @@ class AbstractCreditAccountService extends SDKConstruct {
1055
1338
  * @param to
1056
1339
  * @param calls
1057
1340
  * @param referralCode
1341
+ * @param kycOptions
1058
1342
  * @returns
1059
1343
  */
1060
- async openCreditAccountTx(suite, to, calls, referralCode) {
1344
+ async openCreditAccountTx(suite, to, calls, referralCode, kycOptions) {
1345
+ const marketSuite = this.sdk.marketRegister.findByPool(suite.pool);
1346
+ const factory = marketSuite.kycFactory;
1347
+ if (factory) {
1348
+ return factory.openCreditAccount(
1349
+ suite.creditManager.address,
1350
+ calls,
1351
+ kycOptions
1352
+ );
1353
+ }
1061
1354
  return suite.creditFacade.openCreditAccount(to, calls, referralCode ?? 0n);
1062
1355
  }
1063
1356
  /**
@@ -1065,9 +1358,17 @@ class AbstractCreditAccountService extends SDKConstruct {
1065
1358
  * @param suite
1066
1359
  * @param creditAccount
1067
1360
  * @param calls
1361
+ * @param kycOptions
1068
1362
  * @returns
1069
1363
  */
1070
- async multicallTx(suite, creditAccount, calls) {
1364
+ async multicallTx(suite, creditAccount, calls, kycOptions) {
1365
+ const marketSuite = this.sdk.marketRegister.findByCreditManager(
1366
+ suite.creditManager.address
1367
+ );
1368
+ const factory = marketSuite.kycFactory;
1369
+ if (factory) {
1370
+ return factory.multicall(creditAccount, calls, kycOptions);
1371
+ }
1071
1372
  return suite.creditFacade.multicall(creditAccount, calls);
1072
1373
  }
1073
1374
  /**
@@ -1076,12 +1377,25 @@ class AbstractCreditAccountService extends SDKConstruct {
1076
1377
  * @param creditAccount
1077
1378
  * @param calls
1078
1379
  * @param operation
1380
+ * @param kycOptions
1079
1381
  * @returns
1080
1382
  */
1081
- async closeCreditAccountTx(suite, creditAccount, calls, operation) {
1383
+ async closeCreditAccountTx(suite, creditAccount, calls, operation, kycOptions) {
1384
+ const marketSuite = this.sdk.marketRegister.findByCreditManager(
1385
+ suite.creditManager.address
1386
+ );
1387
+ const factory = marketSuite.kycFactory;
1082
1388
  if (operation === "close") {
1389
+ if (factory) {
1390
+ throw new Error(
1391
+ "CloseOptions=close is not supported for KYC underlying credit accounts"
1392
+ );
1393
+ }
1083
1394
  return suite.creditFacade.closeCreditAccount(creditAccount, calls);
1084
1395
  }
1396
+ if (factory) {
1397
+ return factory.multicall(creditAccount, calls, kycOptions);
1398
+ }
1085
1399
  return suite.creditFacade.multicall(creditAccount, calls);
1086
1400
  }
1087
1401
  }
@@ -90,19 +90,23 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
90
90
  creditAccount: ca,
91
91
  permits,
92
92
  to,
93
- tokensToClaim
93
+ tokensToClaim,
94
+ calls: wrapCalls = []
94
95
  }) {
95
96
  const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
96
97
  const addCollateral = collateralAssets.filter((a) => a.balance > 0);
97
98
  const router = this.sdk.routerFor(ca);
99
+ const unwrapCalls = await this.getRedeemDiffCalls(1n, ca.creditManager) ?? [];
98
100
  const claimPath = await router.findClaimAllRewards({
99
101
  tokensToClaim,
100
102
  creditAccount: ca
101
103
  });
102
104
  const operationCalls = [
103
105
  ...this.prepareAddCollateral(ca.creditFacade, addCollateral, permits),
106
+ ...wrapCalls,
104
107
  ...this.prepareDisableQuotas(ca),
105
108
  ...this.prepareDecreaseDebt(ca),
109
+ ...unwrapCalls,
106
110
  ...claimPath.calls,
107
111
  ...assetsToWithdraw.map(
108
112
  (t) => this.prepareWithdrawToken(ca.creditFacade, t.token, MAX_UINT256, to)
@@ -134,10 +138,12 @@ class CreditAccountServiceV310 extends AbstractCreditAccountService {
134
138
  tokensToClaim,
135
139
  creditAccount: ca
136
140
  });
141
+ const wrapCalls = await this.getDepositDiffCalls(1n, ca.creditManager) ?? [];
137
142
  const addCollateral = collateralAssets.filter((a) => a.balance > 0);
138
143
  const operationCalls = [
139
144
  ...this.prepareAddCollateral(ca.creditFacade, addCollateral, permits),
140
145
  ...claimPath.calls,
146
+ ...wrapCalls,
141
147
  ...assetsToWithdraw.map(
142
148
  (t) => this.prepareWithdrawToken(ca.creditFacade, t.token, MAX_UINT256, to)
143
149
  )
@@ -1,6 +1,3 @@
1
- import {
2
- erc20Abi
3
- } from "viem";
4
1
  import { iStateSerializerAbi } from "../../abi/iStateSerializer.js";
5
2
  import { iVersionAbi } from "../../abi/iVersion.js";
6
3
  import {
@@ -65,6 +62,14 @@ class TokensMeta extends AddressMap {
65
62
  }
66
63
  return !!t.contractType?.startsWith("PHANTOM_TOKEN::");
67
64
  }
65
+ /**
66
+ * Returns true if the token is a KYC underlying token, throws if the token data is not loaded
67
+ * @param t
68
+ * @returns
69
+ */
70
+ isKYCUnderlying(t) {
71
+ return !!t.contractType?.startsWith("KYC_UNDERLYING::");
72
+ }
68
73
  /**
69
74
  * Returns a map of all phantom tokens
70
75
  * Throws if token data is not loaded
@@ -78,6 +83,19 @@ class TokensMeta extends AddressMap {
78
83
  }
79
84
  return result;
80
85
  }
86
+ /**
87
+ * Returns a map of all KYC underlying tokens
88
+ * Throws if token data is not loaded
89
+ */
90
+ get kycUnderlyings() {
91
+ const result = new AddressMap();
92
+ for (const [token, meta] of this.entries()) {
93
+ if (this.isKYCUnderlying(meta)) {
94
+ result.upsert(token, meta);
95
+ }
96
+ }
97
+ return result;
98
+ }
81
99
  formatBN(arg0, arg1, arg2) {
82
100
  const token = typeof arg0 === "object" ? arg0.token : arg0;
83
101
  const amount = typeof arg0 === "object" ? arg0.balance : arg1;
@@ -108,7 +126,7 @@ class TokensMeta extends AddressMap {
108
126
  }
109
127
  /**
110
128
  * Loads token information about phantom tokens
111
- * Other special tokens may be loaded here in the future
129
+ * In future other custom tokens types that do not have compressors might be handled here
112
130
  *
113
131
  * @param tokens - tokens to load data for, defaults to all tokens
114
132
  */
@@ -154,46 +172,6 @@ class TokensMeta extends AddressMap {
154
172
  }
155
173
  return this.mustGet(token);
156
174
  }
157
- async #loadWithoutCompressor(tokens_) {
158
- if (tokens_.size === 0) {
159
- return;
160
- }
161
- const tokens = Array.from(tokens_);
162
- const resp = await this.#client.multicall({
163
- contracts: tokens.flatMap(
164
- (t) => [
165
- {
166
- address: t,
167
- abi: erc20Abi,
168
- functionName: "symbol"
169
- },
170
- {
171
- address: t,
172
- abi: erc20Abi,
173
- functionName: "name"
174
- },
175
- {
176
- address: t,
177
- abi: erc20Abi,
178
- functionName: "decimals"
179
- }
180
- ]
181
- ),
182
- allowFailure: false,
183
- batchSize: 0
184
- });
185
- this.#logger?.debug(
186
- `loaded ${resp.length} basic metadata without compressor`
187
- );
188
- for (let i = 0; i < tokens.length; i++) {
189
- this.upsert(tokens[i], {
190
- addr: tokens[i],
191
- symbol: resp[3 * i],
192
- name: resp[3 * i + 1],
193
- decimals: resp[3 * i + 2]
194
- });
195
- }
196
- }
197
175
  }
198
176
  export {
199
177
  TokensMeta
@@ -7,6 +7,12 @@ const PHANTOM_TOKEN_CONTRACT_TYPES = [
7
7
  "PHANTOM_TOKEN::STAKING_REWARDS",
8
8
  "PHANTOM_TOKEN::UPSHIFT_WITHDRAW"
9
9
  ];
10
+ const KYC_UNDERLYING_DEFAULT = "KYC_UNDERLYING::DEFAULT";
11
+ const KYC_UNDERLYING_ON_DEMAND = "KYC_UNDERLYING::ON_DEMAND";
12
+ const KYC_ON_DEMAND_LP_MONOPOLIZED = "ON_DEMAND_LP::MONOPOLIZED";
10
13
  export {
14
+ KYC_ON_DEMAND_LP_MONOPOLIZED,
15
+ KYC_UNDERLYING_DEFAULT,
16
+ KYC_UNDERLYING_ON_DEMAND,
11
17
  PHANTOM_TOKEN_CONTRACT_TYPES
12
18
  };