@gearbox-protocol/sdk 14.1.1 → 14.2.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 (40) hide show
  1. package/dist/cjs/dev/claimDSToken.js +208 -0
  2. package/dist/cjs/plugins/accounts/AccountsPlugin.js +1 -2
  3. package/dist/cjs/sdk/OnchainSDK.js +12 -0
  4. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +1448 -23
  5. package/dist/cjs/sdk/accounts/index.js +0 -4
  6. package/dist/cjs/sdk/market/credit/CreditFacadeV310Contract.js +6 -0
  7. package/dist/cjs/sdk/market/kyc/securitize/SecuritizeKYCFactory.js +19 -2
  8. package/dist/cjs/sdk/market/kyc/securitize/types.js +20 -0
  9. package/dist/cjs/sdk/market/oracle/PriceOracleV310Contract.js +26 -0
  10. package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +3 -0
  11. package/dist/esm/dev/claimDSToken.js +187 -0
  12. package/dist/esm/plugins/accounts/AccountsPlugin.js +2 -7
  13. package/dist/esm/sdk/OnchainSDK.js +14 -0
  14. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +1466 -23
  15. package/dist/esm/sdk/accounts/index.js +0 -2
  16. package/dist/esm/sdk/accounts/multicall-utils.js +1 -5
  17. package/dist/esm/sdk/market/credit/CreditFacadeV310Contract.js +6 -0
  18. package/dist/esm/sdk/market/kyc/securitize/SecuritizeKYCFactory.js +21 -2
  19. package/dist/esm/sdk/market/kyc/securitize/types.js +12 -0
  20. package/dist/esm/sdk/market/oracle/PriceOracleV310Contract.js +26 -0
  21. package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +3 -0
  22. package/dist/types/dev/claimDSToken.d.ts +34 -0
  23. package/dist/types/sdk/OnchainSDK.d.ts +10 -0
  24. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +181 -3
  25. package/dist/types/sdk/accounts/index.d.ts +0 -2
  26. package/dist/types/sdk/accounts/types.d.ts +56 -0
  27. package/dist/types/sdk/market/credit/CreditFacadeV310Contract.d.ts +2 -0
  28. package/dist/types/sdk/market/kyc/securitize/SecuritizeKYCFactory.d.ts +1 -1
  29. package/dist/types/sdk/market/kyc/securitize/types.d.ts +37 -22
  30. package/dist/types/sdk/market/oracle/PriceOracleBaseContract.d.ts +5 -0
  31. package/dist/types/sdk/market/oracle/PriceOracleV310Contract.d.ts +4 -0
  32. package/dist/types/sdk/market/oracle/types.d.ts +9 -0
  33. package/dist/types/sdk/pools/types.d.ts +19 -0
  34. package/package.json +1 -1
  35. package/dist/cjs/sdk/accounts/AbstractCreditAccountsService.js +0 -1411
  36. package/dist/cjs/sdk/accounts/createCreditAccountService.js +0 -35
  37. package/dist/esm/sdk/accounts/AbstractCreditAccountsService.js +0 -1405
  38. package/dist/esm/sdk/accounts/createCreditAccountService.js +0 -11
  39. package/dist/types/sdk/accounts/AbstractCreditAccountsService.d.ts +0 -226
  40. package/dist/types/sdk/accounts/createCreditAccountService.d.ts +0 -9
@@ -1,1405 +0,0 @@
1
- import { ierc4626AdapterAbi } from "@gearbox-protocol/integrations-v3";
2
- import { encodeFunctionData, getContract } from "viem";
3
- import {
4
- iBotListV310Abi,
5
- iCreditFacadeMulticallV310Abi
6
- } from "../../abi/310/generated.js";
7
- import { creditAccountCompressorAbi } from "../../abi/compressors/creditAccountCompressor.js";
8
- import { peripheryCompressorAbi } from "../../abi/compressors/peripheryCompressor.js";
9
- import { rewardsCompressorAbi } from "../../abi/compressors/rewardsCompressor.js";
10
- import { iWithdrawalCompressorV310Abi } from "../../abi/IWithdrawalCompressorV310.js";
11
- import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
12
- import { iKYCFactoryAbi } from "../../abi/kyc/iKYCFactory.js";
13
- import { SDKConstruct } from "../base/index.js";
14
- import { chains } from "../chain/chains.js";
15
- import {
16
- ADDRESS_0X0,
17
- AP_CREDIT_ACCOUNT_COMPRESSOR,
18
- AP_PERIPHERY_COMPRESSOR,
19
- AP_REWARDS_COMPRESSOR,
20
- MAX_UINT256,
21
- MIN_INT96,
22
- PERCENTAGE_FACTOR,
23
- RAY,
24
- VERSION_RANGE_310
25
- } from "../constants/index.js";
26
- import {
27
- getRawPriceUpdates
28
- } from "../market/index.js";
29
- import { assetsMap } from "../router/index.js";
30
- import { AddressMap, AddressSet, hexEq } from "../utils/index.js";
31
- import { simulateWithPriceUpdates } from "../utils/viem/index.js";
32
- import {
33
- extractPriceUpdates,
34
- extractQuotaTokens,
35
- mergePriceUpdates
36
- } from "./multicall-utils.js";
37
- const COMPRESSORS = {
38
- [chains.Mainnet.id]: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023",
39
- [chains.Monad.id]: "0x36F3d0Bb73CBC2E94fE24dF0f26a689409cF9023"
40
- };
41
- function getWithdrawalCompressorAddress(chainId) {
42
- return COMPRESSORS[chainId];
43
- }
44
- class AbstractCreditAccountService extends SDKConstruct {
45
- #compressor;
46
- #batchSize;
47
- constructor(sdk, options) {
48
- super(sdk);
49
- [this.#compressor] = sdk.addressProvider.mustGetLatest(
50
- AP_CREDIT_ACCOUNT_COMPRESSOR,
51
- VERSION_RANGE_310
52
- );
53
- this.#batchSize = options?.batchSize;
54
- this.logger?.debug(
55
- `credit account compressor address: ${this.#compressor}`
56
- );
57
- }
58
- /**
59
- * {@inheritDoc ICreditAccountsService.getCreditAccountData}
60
- **/
61
- async getCreditAccountData(account, blockNumber) {
62
- let raw;
63
- try {
64
- raw = await this.client.readContract({
65
- abi: creditAccountCompressorAbi,
66
- address: this.#compressor,
67
- functionName: "getCreditAccountData",
68
- args: [account],
69
- blockNumber,
70
- // @ts-expect-error
71
- gas: this.sdk.gasLimit
72
- });
73
- } catch (_e) {
74
- return void 0;
75
- }
76
- const marketSuite = this.sdk.marketRegister.findByCreditManager(
77
- raw.creditManager
78
- );
79
- const factory = marketSuite.kycFactory;
80
- let ca;
81
- let investor;
82
- if (raw.success) {
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
- });
108
- }
109
- return { ...ca, investor };
110
- }
111
- /**
112
- * {@inheritDoc ICreditAccountsService.getCreditAccounts}
113
- **/
114
- async getCreditAccounts(options, blockNumber) {
115
- const {
116
- creditManager,
117
- includeZeroDebt = false,
118
- maxHealthFactor = MAX_UINT256,
119
- minHealthFactor = 0n,
120
- owner = ADDRESS_0X0,
121
- ignoreReservePrices = false
122
- } = options ?? {};
123
- const arg0 = creditManager ?? {
124
- configurators: this.marketConfigurators,
125
- creditManagers: [],
126
- pools: [],
127
- underlying: ADDRESS_0X0
128
- };
129
- const caFilter = {
130
- owner,
131
- includeZeroDebt,
132
- minHealthFactor,
133
- maxHealthFactor,
134
- reverting: false
135
- };
136
- const { txs: priceUpdateTxs } = await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(
137
- ignoreReservePrices ? { main: true } : void 0
138
- );
139
- const allCAs = [];
140
- let revertingOffset = 0;
141
- for (const reverting of [false, true]) {
142
- let offset = 0n;
143
- revertingOffset = allCAs.length;
144
- do {
145
- const [accounts, newOffset] = await this.#getCreditAccounts(
146
- this.#batchSize ? [
147
- arg0,
148
- { ...caFilter, reverting },
149
- offset,
150
- BigInt(this.#batchSize)
151
- // limit
152
- ] : [arg0, { ...caFilter, reverting }, offset],
153
- priceUpdateTxs,
154
- blockNumber
155
- );
156
- allCAs.push(...accounts);
157
- offset = newOffset;
158
- } while (offset !== 0n);
159
- }
160
- this.logger?.debug(
161
- `loaded ${allCAs.length} credit accounts (${allCAs.length - revertingOffset} reverting)`
162
- );
163
- return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
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
- }
258
- /**
259
- * {@inheritDoc ICreditAccountsService.getRewards}
260
- **/
261
- async getRewards(creditAccount) {
262
- const rewards = await this.client.readContract({
263
- abi: rewardsCompressorAbi,
264
- address: this.rewardCompressor,
265
- functionName: "getRewards",
266
- args: [creditAccount]
267
- });
268
- const callData = encodeFunctionData({
269
- abi: iBaseRewardPoolAbi,
270
- functionName: "getReward",
271
- args: []
272
- });
273
- const r = rewards.reduce((acc, r2) => {
274
- const adapter = r2.adapter.toLowerCase();
275
- const stakedPhantomToken = r2.stakedPhantomToken.toLowerCase();
276
- const rewardToken = r2.rewardToken.toLowerCase();
277
- const key = [adapter, stakedPhantomToken].join("-");
278
- if (!acc[key]) {
279
- acc[key] = {
280
- adapter,
281
- stakedPhantomToken,
282
- calls: [
283
- {
284
- target: adapter,
285
- callData
286
- }
287
- ],
288
- rewards: []
289
- };
290
- }
291
- acc[key].rewards.push({
292
- token: rewardToken,
293
- balance: r2.amount
294
- });
295
- return acc;
296
- }, {});
297
- return Object.values(r);
298
- }
299
- /**
300
- * {@inheritDoc ICreditAccountsService.getConnectedBots}
301
- **/
302
- async getConnectedBots(accountsToCheck, legacyMigrationBot, additionalBots) {
303
- const allResp = await this.client.multicall({
304
- contracts: [
305
- ...accountsToCheck.map((o) => {
306
- const pool = this.sdk.marketRegister.findByCreditManager(
307
- o.creditManager
308
- );
309
- return {
310
- abi: peripheryCompressorAbi,
311
- address: this.peripheryCompressor,
312
- functionName: "getConnectedBots",
313
- args: [pool.configurator.address, o.creditAccount]
314
- };
315
- }),
316
- ...legacyMigrationBot ? accountsToCheck.map((ca) => {
317
- const cm = this.sdk.marketRegister.findCreditManager(
318
- ca.creditManager
319
- );
320
- return {
321
- abi: iBotListV310Abi,
322
- address: cm.creditFacade.botList,
323
- functionName: "getBotStatus",
324
- args: [legacyMigrationBot, ca.creditAccount]
325
- };
326
- }) : [],
327
- ...accountsToCheck.flatMap((ca) => {
328
- const cm = this.sdk.marketRegister.findCreditManager(
329
- ca.creditManager
330
- );
331
- return additionalBots.map((bot) => {
332
- return {
333
- abi: iBotListV310Abi,
334
- address: cm.creditFacade.botList,
335
- functionName: "getBotStatus",
336
- args: [bot, ca.creditAccount]
337
- };
338
- });
339
- })
340
- ],
341
- allowFailure: true,
342
- batchSize: 0
343
- });
344
- const legacyStart = 0;
345
- const legacyEnd = accountsToCheck.length;
346
- const legacy = allResp.slice(
347
- legacyStart,
348
- legacyEnd
349
- );
350
- const migrationStart = legacyEnd;
351
- const migrationEnd = legacyMigrationBot ? migrationStart + accountsToCheck.length : migrationStart;
352
- const migrationResp = allResp.slice(
353
- migrationStart,
354
- migrationEnd
355
- );
356
- const additionalStart = migrationEnd;
357
- const additionalResp = allResp.slice(
358
- additionalStart
359
- );
360
- return {
361
- legacy,
362
- additionalBots: this.#getActiveBots(
363
- accountsToCheck,
364
- additionalBots,
365
- additionalResp
366
- ),
367
- legacyMigration: this.#getActiveMigrationBots(
368
- accountsToCheck,
369
- legacyMigrationBot,
370
- migrationResp
371
- )
372
- };
373
- }
374
- #getActiveBots(accountsToCheck, bots, result) {
375
- if (result.length !== bots.length * accountsToCheck.length) {
376
- console.error(
377
- "result length mismatch",
378
- result.length,
379
- bots.length * accountsToCheck.length
380
- );
381
- }
382
- const botsByCAIndex = accountsToCheck.reduce((acc, _, index) => {
383
- const r = result.slice(index * bots.length, (index + 1) * bots.length);
384
- acc.push({
385
- result: r
386
- });
387
- return acc;
388
- }, []);
389
- return botsByCAIndex;
390
- }
391
- #getActiveMigrationBots(accountsToCheck, bot, result) {
392
- if (bot) {
393
- if (result.length !== accountsToCheck.length) {
394
- console.error(
395
- "result length mismatch for migration bots",
396
- result.length,
397
- accountsToCheck.length
398
- );
399
- }
400
- return { result, botAddress: bot };
401
- }
402
- return void 0;
403
- }
404
- /**
405
- * {@inheritDoc ICreditAccountsService.fullyLiquidate}
406
- **/
407
- async fullyLiquidate(props) {
408
- const {
409
- account,
410
- to,
411
- slippage = 50n,
412
- keepAssets,
413
- ignoreReservePrices,
414
- applyLossPolicy,
415
- debtOnly
416
- } = props;
417
- const cm = this.sdk.marketRegister.findCreditManager(account.creditManager);
418
- const routerCloseResult = await this.sdk.routerFor(account).findBestClosePath({
419
- creditAccount: account,
420
- creditManager: cm.creditManager,
421
- slippage,
422
- keepAssets,
423
- debtOnly
424
- });
425
- const calls = await this.prependPriceUpdates(
426
- account.creditManager,
427
- routerCloseResult.calls,
428
- account,
429
- { ignoreReservePrices }
430
- );
431
- let lossPolicyData;
432
- if (applyLossPolicy) {
433
- const market = this.sdk.marketRegister.findByCreditManager(
434
- account.creditManager
435
- );
436
- lossPolicyData = await market.lossPolicy.getLiquidationData(
437
- account.creditAccount
438
- );
439
- this.logger?.debug({ lossPolicyData }, "loss policy data");
440
- }
441
- const tx = cm.creditFacade.liquidateCreditAccount(
442
- account.creditAccount,
443
- to,
444
- calls,
445
- lossPolicyData
446
- );
447
- return {
448
- tx,
449
- calls,
450
- routerCloseResult,
451
- lossPolicyData,
452
- creditFacade: cm.creditFacade
453
- };
454
- }
455
- /**
456
- * {@inheritDoc ICreditAccountsService.closeCreditAccount}
457
- **/
458
- async closeCreditAccount({
459
- operation,
460
- assetsToWithdraw,
461
- creditAccount: ca,
462
- to,
463
- slippage = 50n,
464
- closePath
465
- }) {
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
- }
474
- const routerCloseResult = closePath || await this.sdk.routerFor(ca).findBestClosePath({
475
- creditAccount: ca,
476
- creditManager: cm.creditManager,
477
- slippage
478
- });
479
- const operationCalls = [
480
- ...routerCloseResult.calls,
481
- ...this.prepareDisableQuotas(ca),
482
- ...this.prepareDecreaseDebt(ca),
483
- ...assetsToWithdraw.map(
484
- (t) => this.prepareWithdrawToken(ca.creditFacade, t, MAX_UINT256, to)
485
- )
486
- ];
487
- const calls = operation === "close" ? operationCalls : await this.prependPriceUpdates(ca.creditManager, operationCalls, ca);
488
- const tx = await this.closeCreditAccountTx(
489
- cm,
490
- ca.creditAccount,
491
- calls,
492
- operation
493
- );
494
- return { tx, calls, routerCloseResult, creditFacade: cm.creditFacade };
495
- }
496
- /**
497
- * {@inheritDoc ICreditAccountsService.updateQuotas}
498
- **/
499
- async updateQuotas({
500
- minQuota,
501
- averageQuota,
502
- creditAccount
503
- }) {
504
- const cm = this.sdk.marketRegister.findCreditManager(
505
- creditAccount.creditManager
506
- );
507
- const operationCalls = this.prepareUpdateQuotas(
508
- creditAccount.creditFacade,
509
- { minQuota, averageQuota }
510
- );
511
- const calls = await this.prependPriceUpdates(
512
- creditAccount.creditManager,
513
- operationCalls,
514
- creditAccount
515
- );
516
- const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
517
- return { tx, calls, creditFacade: cm.creditFacade };
518
- }
519
- /**
520
- * {@inheritDoc ICreditAccountsService.addCollateral}
521
- **/
522
- async addCollateral({
523
- creditAccount,
524
- asset,
525
- permit,
526
- ethAmount,
527
- minQuota,
528
- averageQuota
529
- }) {
530
- const cm = this.sdk.marketRegister.findCreditManager(
531
- creditAccount.creditManager
532
- );
533
- const operationCalls = [
534
- ...this.prepareAddCollateral(
535
- creditAccount.creditFacade,
536
- [asset],
537
- permit ? { [asset.token]: permit } : {}
538
- ),
539
- ...this.prepareUpdateQuotas(creditAccount.creditFacade, {
540
- minQuota,
541
- averageQuota
542
- })
543
- ];
544
- const calls = await this.prependPriceUpdates(
545
- creditAccount.creditManager,
546
- operationCalls,
547
- creditAccount
548
- );
549
- const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
550
- tx.value = ethAmount.toString(10);
551
- return { tx, calls, creditFacade: cm.creditFacade };
552
- }
553
- /**
554
- * {@inheritDoc ICreditAccountsService.changeDebt}
555
- **/
556
- async changeDebt({
557
- creditAccount,
558
- amount,
559
- collateral
560
- }) {
561
- if (amount === 0n) {
562
- throw new Error("debt increase or decrease must be non-zero");
563
- }
564
- const isDecrease = amount < 0n;
565
- const change = amount > 0n ? amount : -amount;
566
- const cm = this.sdk.marketRegister.findCreditManager(
567
- creditAccount.creditManager
568
- );
569
- const addCollateralCalls = collateral && isDecrease ? this.prepareAddCollateral(
570
- creditAccount.creditFacade,
571
- [
572
- {
573
- token: collateral[0].token,
574
- balance: collateral[0].balance
575
- }
576
- ],
577
- {}
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
- }
588
- const operationCalls = [
589
- ...addCollateralCalls,
590
- ...unwrapCalls,
591
- this.#prepareChangeDebt(creditAccount.creditFacade, change, isDecrease)
592
- ];
593
- const calls = await this.prependPriceUpdates(
594
- creditAccount.creditManager,
595
- operationCalls,
596
- creditAccount
597
- );
598
- const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
599
- return { tx, calls, creditFacade: cm.creditFacade };
600
- }
601
- /**
602
- * {@inheritDoc ICreditAccountsService.executeSwap}
603
- **/
604
- async executeSwap({
605
- creditAccount,
606
- calls: swapCalls,
607
- minQuota,
608
- averageQuota
609
- }) {
610
- if (swapCalls.length === 0) throw new Error("No path to execute");
611
- const cm = this.sdk.marketRegister.findCreditManager(
612
- creditAccount.creditManager
613
- );
614
- const operationCalls = [
615
- ...swapCalls,
616
- ...this.prepareUpdateQuotas(creditAccount.creditFacade, {
617
- minQuota,
618
- averageQuota
619
- })
620
- ];
621
- const calls = await this.prependPriceUpdates(
622
- creditAccount.creditManager,
623
- operationCalls,
624
- creditAccount
625
- );
626
- const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
627
- return { tx, calls, creditFacade: cm.creditFacade };
628
- }
629
- /**
630
- * {@inheritDoc ICreditAccountsService.previewDelayedWithdrawal}
631
- **/
632
- async previewDelayedWithdrawal({
633
- creditAccount,
634
- amount,
635
- token
636
- }) {
637
- const compressor = getWithdrawalCompressorAddress(this.sdk.chainId);
638
- if (!compressor)
639
- throw new Error(
640
- `No compressor for current chain ${this.sdk.networkType}`
641
- );
642
- const contract = getContract({
643
- address: compressor,
644
- abi: iWithdrawalCompressorV310Abi,
645
- client: this.client
646
- });
647
- const resp = await contract.read.getWithdrawalRequestResult([
648
- creditAccount,
649
- token,
650
- amount
651
- ]);
652
- return resp;
653
- }
654
- /**
655
- * {@inheritDoc ICreditAccountsService.getPendingWithdrawals}
656
- **/
657
- async getPendingWithdrawals({
658
- creditAccount
659
- }) {
660
- const compressor = getWithdrawalCompressorAddress(this.sdk.chainId);
661
- if (!compressor)
662
- throw new Error(
663
- `No compressor for current chain ${this.sdk.networkType}`
664
- );
665
- const contract = getContract({
666
- address: compressor,
667
- abi: iWithdrawalCompressorV310Abi,
668
- client: this.client
669
- });
670
- const resp = await contract.read.getCurrentWithdrawals([creditAccount]);
671
- const claimableNow = resp?.[0] || [];
672
- const pendingResult = [...resp?.[1] || []].sort(
673
- (a, b) => a.claimableAt < b.claimableAt ? -1 : 1
674
- );
675
- const respResult = {
676
- claimableNow: [...claimableNow],
677
- pending: pendingResult
678
- };
679
- return respResult;
680
- }
681
- /**
682
- * {@inheritDoc ICreditAccountsService.startDelayedWithdrawal}
683
- **/
684
- async startDelayedWithdrawal({
685
- creditAccount,
686
- minQuota,
687
- averageQuota,
688
- preview
689
- }) {
690
- const cm = this.sdk.marketRegister.findCreditManager(
691
- creditAccount.creditManager
692
- );
693
- const record = preview.outputs.reduce((acc, o) => {
694
- const token = o.token.toLowerCase();
695
- acc[token] = (acc[token] || 0n) + o.amount;
696
- return acc;
697
- }, {});
698
- const balances = Object.entries(record).filter(([, a]) => a > 10n);
699
- const storeExpectedBalances = {
700
- target: cm.creditFacade.address,
701
- callData: encodeFunctionData({
702
- abi: iCreditFacadeMulticallV310Abi,
703
- functionName: "storeExpectedBalances",
704
- args: [
705
- balances.map(([token, amount]) => ({
706
- token,
707
- amount: amount > 10n ? amount - 10n : 0n
708
- }))
709
- ]
710
- })
711
- };
712
- const compareBalances = {
713
- target: cm.creditFacade.address,
714
- callData: encodeFunctionData({
715
- abi: iCreditFacadeMulticallV310Abi,
716
- functionName: "compareBalances",
717
- args: []
718
- })
719
- };
720
- const operationCalls = [
721
- storeExpectedBalances,
722
- ...preview.requestCalls,
723
- compareBalances,
724
- ...this.prepareUpdateQuotas(creditAccount.creditFacade, {
725
- minQuota,
726
- averageQuota
727
- })
728
- ];
729
- const calls = await this.prependPriceUpdates(
730
- creditAccount.creditManager,
731
- operationCalls,
732
- creditAccount
733
- );
734
- const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
735
- return { tx, calls, creditFacade: cm.creditFacade };
736
- }
737
- /**
738
- * {@inheritDoc ICreditAccountsService.claimDelayed}
739
- **/
740
- async claimDelayed({
741
- creditAccount,
742
- minQuota,
743
- averageQuota,
744
- claimableNow
745
- }) {
746
- const zeroDebt = creditAccount.debt === 0n;
747
- const cm = this.sdk.marketRegister.findCreditManager(
748
- creditAccount.creditManager
749
- );
750
- const record = claimableNow.outputs.reduce(
751
- (acc, o) => {
752
- const token = o.token.toLowerCase();
753
- acc[token] = (acc[token] || 0n) + o.amount;
754
- return acc;
755
- },
756
- {}
757
- );
758
- const balances = Object.entries(record).filter(([, a]) => a > 10n);
759
- const storeExpectedBalances = {
760
- target: cm.creditFacade.address,
761
- callData: encodeFunctionData({
762
- abi: iCreditFacadeMulticallV310Abi,
763
- functionName: "storeExpectedBalances",
764
- args: [
765
- balances.map(([token, amount]) => ({
766
- token,
767
- amount: amount > 10n ? amount - 10n : 0n
768
- }))
769
- ]
770
- })
771
- };
772
- const compareBalances = {
773
- target: cm.creditFacade.address,
774
- callData: encodeFunctionData({
775
- abi: iCreditFacadeMulticallV310Abi,
776
- functionName: "compareBalances",
777
- args: []
778
- })
779
- };
780
- const quotaCalls = zeroDebt ? [] : this.prepareUpdateQuotas(creditAccount.creditFacade, {
781
- minQuota,
782
- averageQuota
783
- });
784
- const operationCalls = [
785
- storeExpectedBalances,
786
- ...claimableNow.claimCalls,
787
- compareBalances,
788
- ...quotaCalls
789
- ];
790
- const calls = zeroDebt ? operationCalls : await this.prependPriceUpdates(
791
- creditAccount.creditManager,
792
- operationCalls,
793
- creditAccount
794
- );
795
- const tx = await this.multicallTx(cm, creditAccount.creditAccount, calls);
796
- return { tx, calls, creditFacade: cm.creditFacade };
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
- }
821
- /**
822
- * {@inheritDoc ICreditAccountsService.openCA}
823
- **/
824
- async openCA(props) {
825
- const {
826
- ethAmount,
827
- creditManager,
828
- reopenCreditAccount,
829
- collateral,
830
- permits,
831
- debt,
832
- withdrawToken,
833
- referralCode,
834
- to,
835
- calls: openPathCalls,
836
- callsAfter,
837
- minQuota,
838
- averageQuota,
839
- kycOptions
840
- } = props;
841
- const cmSuite = this.sdk.marketRegister.findCreditManager(creditManager);
842
- const cm = cmSuite.creditManager;
843
- let tokenToWithdraw;
844
- if (withdrawToken === true) {
845
- tokenToWithdraw = cm.underlying;
846
- } else if (typeof withdrawToken === "string") {
847
- tokenToWithdraw = withdrawToken;
848
- }
849
- const operationCalls = [
850
- this.#prepareIncreaseDebt(cm.creditFacade, debt),
851
- ...this.prepareAddCollateral(cm.creditFacade, collateral, permits),
852
- ...openPathCalls,
853
- // path from underlying to withdrawal token
854
- ...tokenToWithdraw ? [
855
- this.prepareWithdrawToken(
856
- cm.creditFacade,
857
- tokenToWithdraw,
858
- MAX_UINT256,
859
- to
860
- )
861
- ] : [],
862
- ...this.prepareUpdateQuotas(cm.creditFacade, {
863
- minQuota,
864
- averageQuota
865
- }),
866
- ...callsAfter ?? []
867
- ];
868
- const calls = await this.prependPriceUpdates(cm.address, operationCalls);
869
- let tx;
870
- if (reopenCreditAccount) {
871
- tx = await this.multicallTx(cmSuite, reopenCreditAccount, calls);
872
- } else {
873
- tx = await this.openCreditAccountTx(
874
- cmSuite,
875
- to,
876
- calls,
877
- referralCode,
878
- kycOptions
879
- );
880
- }
881
- tx.value = ethAmount.toString(10);
882
- return { calls, tx, creditFacade: cmSuite.creditFacade };
883
- }
884
- /**
885
- * {@inheritDoc ICreditAccountsService.getBorrowRate}
886
- **/
887
- getBorrowRate(ca) {
888
- const { creditManager } = this.sdk.marketRegister.findCreditManager(
889
- ca.creditManager
890
- );
891
- const { pool } = this.sdk.marketRegister.findByCreditManager(
892
- ca.creditManager
893
- );
894
- const { feeInterest } = creditManager;
895
- const { baseInterestRate } = pool.pool;
896
- const baseRateWithFee = baseInterestRate * (BigInt(feeInterest) + PERCENTAGE_FACTOR);
897
- const totalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
898
- const r = ca.debt * baseRateWithFee / (totalDebt * RAY);
899
- const caTokens = new AddressMap(ca.tokens.map((t) => [t.token, t]));
900
- let qr = 0n;
901
- for (const t of creditManager.collateralTokens) {
902
- const b = caTokens.get(t);
903
- if (b) {
904
- qr += b.quota * BigInt(pool.pqk.quotas.get(t)?.rate ?? 0);
905
- }
906
- }
907
- qr = qr * (BigInt(feeInterest) + PERCENTAGE_FACTOR) / PERCENTAGE_FACTOR;
908
- qr /= totalDebt;
909
- return r + qr;
910
- }
911
- /**
912
- * {@inheritDoc ICreditAccountsService.getOptimalHFForPartialLiquidation}
913
- **/
914
- getOptimalHFForPartialLiquidation(ca) {
915
- const borrowRate = this.getBorrowRate(ca);
916
- return PERCENTAGE_FACTOR + (borrowRate < 100n ? borrowRate : 100n);
917
- }
918
- /**
919
- * Internal wrapper for CreditAccountCompressor.getCreditAccounts + price updates wrapped into multicall
920
- * @param args
921
- * @param priceUpdateTxs
922
- * @param blockNumber
923
- * @returns
924
- */
925
- async #getCreditAccounts(args, priceUpdateTxs, blockNumber) {
926
- let resp;
927
- if (priceUpdateTxs?.length) {
928
- [resp] = await simulateWithPriceUpdates(this.client, {
929
- priceUpdates: priceUpdateTxs,
930
- contracts: [
931
- {
932
- abi: creditAccountCompressorAbi,
933
- address: this.#compressor,
934
- functionName: "getCreditAccounts",
935
- args
936
- }
937
- ],
938
- blockNumber,
939
- gas: this.sdk.gasLimit
940
- });
941
- } else {
942
- resp = await this.client.readContract({
943
- abi: creditAccountCompressorAbi,
944
- address: this.#compressor,
945
- functionName: "getCreditAccounts",
946
- args,
947
- blockNumber,
948
- // @ts-expect-error
949
- gas: this.sdk.gasLimit
950
- });
951
- }
952
- this.logger?.debug(
953
- {
954
- accounts: resp[0]?.length ?? 0,
955
- nextOffset: Number(resp[1])
956
- },
957
- "got credit accounts"
958
- );
959
- return resp;
960
- }
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
1087
- * {@inheritDoc ICreditAccountsService.getOnDemandPriceUpdates}
1088
- **/
1089
- async getOnDemandPriceUpdates(account, ignoreReservePrices) {
1090
- const { creditManager, creditAccount } = account;
1091
- const cm = this.sdk.marketRegister.findCreditManager(creditManager);
1092
- const update = await this.getUpdateForAccount(account, ignoreReservePrices);
1093
- this.logger?.debug(
1094
- { account: creditAccount, manager: cm.name },
1095
- `getting on demand price updates from ${update.txs.length} txs`
1096
- );
1097
- return getRawPriceUpdates(update);
1098
- }
1099
- /**
1100
- * Analyzes a multicall array and prepends necessary on-demand price feed updates.
1101
- *
1102
- * Deduplicates existing `onDemandPriceUpdates` calls
1103
- *
1104
- * @param creditManager - Address of the credit manager
1105
- * @param calls - The multicall array to prepend price updates to
1106
- * @param ca - Credit account slice, undefined when opening a new account
1107
- * @param options - Optional settings for price update generation
1108
- * @returns A new array with a single consolidated price update call prepended,
1109
- * followed by the non-price-update calls in their original order
1110
- */
1111
- async prependPriceUpdates(creditManager, calls, ca, options) {
1112
- const market = this.sdk.marketRegister.findByCreditManager(creditManager);
1113
- const cm = this.sdk.marketRegister.findCreditManager(creditManager).creditManager;
1114
- const { priceUpdates: existingUpdates, remainingCalls } = extractPriceUpdates(calls);
1115
- const tokens = new AddressSet([
1116
- cm.underlying,
1117
- // underlying - always included
1118
- ...extractQuotaTokens(calls)
1119
- // tokens from `updateQuota` calls
1120
- ]);
1121
- if (ca) {
1122
- for (const t of ca.tokens) {
1123
- const isEnabled = (t.mask & ca.enabledTokensMask) !== 0n;
1124
- if (t.balance > 10n && isEnabled) {
1125
- tokens.add(t.token);
1126
- }
1127
- }
1128
- }
1129
- const ignoreReservePrices = options?.ignoreReservePrices;
1130
- const priceFeeds = market.priceOracle.priceFeedsForTokens(Array.from(tokens), {
1131
- main: true,
1132
- reserve: !ignoreReservePrices
1133
- });
1134
- const tStr = tokens.map((t) => this.labelAddress(t)).join(", ");
1135
- const remark = ignoreReservePrices ? " main" : "";
1136
- this.logger?.debug(
1137
- { account: ca?.creditAccount, manager: cm.name },
1138
- `prependPriceUpdates for ${tStr} from ${priceFeeds.length}${remark} price feeds`
1139
- );
1140
- const generatedUpdates = await this.sdk.priceFeeds.generatePriceFeedsUpdates(priceFeeds);
1141
- const merged = mergePriceUpdates(existingUpdates, generatedUpdates);
1142
- if (merged.length === 0) {
1143
- return remainingCalls;
1144
- }
1145
- return [
1146
- {
1147
- target: cm.creditFacade,
1148
- callData: encodeFunctionData({
1149
- abi: iCreditFacadeMulticallV310Abi,
1150
- functionName: "onDemandPriceUpdates",
1151
- args: [merged]
1152
- })
1153
- },
1154
- ...remainingCalls
1155
- ];
1156
- }
1157
- async getUpdateForAccount(account, ignoreReservePrices) {
1158
- const { creditManager, creditAccount, enabledTokensMask } = account;
1159
- const market = this.sdk.marketRegister.findByCreditManager(creditManager);
1160
- const cm = this.sdk.marketRegister.findCreditManager(creditManager).creditManager;
1161
- const tokens = new AddressSet([cm.underlying]);
1162
- for (const t of account.tokens) {
1163
- const isEnabled = (t.mask & enabledTokensMask) !== 0n;
1164
- if (t.balance > 10n && isEnabled) {
1165
- tokens.add(t.token);
1166
- }
1167
- }
1168
- const priceFeeds = market.priceOracle.priceFeedsForTokens(Array.from(tokens), {
1169
- main: true,
1170
- reserve: !ignoreReservePrices
1171
- });
1172
- const tStr = tokens.map((t) => this.labelAddress(t)).join(", ");
1173
- const remark = ignoreReservePrices ? " main" : "";
1174
- this.logger?.debug(
1175
- { account: creditAccount, manager: cm.name },
1176
- `generating price feed updates for ${tStr} from ${priceFeeds.length}${remark} price feeds`
1177
- );
1178
- return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(priceFeeds);
1179
- }
1180
- /**
1181
- * {@inheritDoc ICreditAccountsService.multicall}
1182
- */
1183
- async multicall(creditAccount, calls, options) {
1184
- const cm = this.sdk.marketRegister.findCreditManager(
1185
- creditAccount.creditManager
1186
- );
1187
- const callsWithPrices = await this.prependPriceUpdates(
1188
- creditAccount.creditManager,
1189
- calls,
1190
- creditAccount,
1191
- options
1192
- );
1193
- return cm.creditFacade.multicall(
1194
- creditAccount.creditAccount,
1195
- callsWithPrices
1196
- );
1197
- }
1198
- /**
1199
- * {@inheritDoc ICreditAccountsService.botMulticall}
1200
- */
1201
- async botMulticall(creditAccount, calls, options) {
1202
- const cm = this.sdk.marketRegister.findCreditManager(
1203
- creditAccount.creditManager
1204
- );
1205
- const callsWithPrices = await this.prependPriceUpdates(
1206
- creditAccount.creditManager,
1207
- calls,
1208
- creditAccount,
1209
- options
1210
- );
1211
- return cm.creditFacade.botMulticall(
1212
- creditAccount.creditAccount,
1213
- callsWithPrices
1214
- );
1215
- }
1216
- prepareDisableQuotas(ca) {
1217
- const calls = [];
1218
- for (const { token, quota } of ca.tokens) {
1219
- if (quota > 0n) {
1220
- calls.push({
1221
- target: ca.creditFacade,
1222
- callData: encodeFunctionData({
1223
- abi: iCreditFacadeMulticallV310Abi,
1224
- functionName: "updateQuota",
1225
- args: [token, MIN_INT96, 0n]
1226
- })
1227
- });
1228
- }
1229
- }
1230
- return calls;
1231
- }
1232
- prepareUpdateQuotas(creditFacade, { averageQuota, minQuota }) {
1233
- const minRecord = assetsMap(minQuota);
1234
- const calls = averageQuota.map((q) => {
1235
- const minAsset = minRecord.get(q.token);
1236
- const min = minAsset && minAsset?.balance > 0 ? minAsset.balance : 0n;
1237
- return {
1238
- target: creditFacade,
1239
- callData: encodeFunctionData({
1240
- abi: iCreditFacadeMulticallV310Abi,
1241
- functionName: "updateQuota",
1242
- args: [q.token, q.balance, min]
1243
- })
1244
- };
1245
- });
1246
- return calls;
1247
- }
1248
- prepareDecreaseDebt(ca) {
1249
- if (ca.debt > 0n) {
1250
- return [
1251
- {
1252
- target: ca.creditFacade,
1253
- callData: encodeFunctionData({
1254
- abi: iCreditFacadeMulticallV310Abi,
1255
- functionName: "decreaseDebt",
1256
- args: [MAX_UINT256]
1257
- })
1258
- }
1259
- ];
1260
- }
1261
- return [];
1262
- }
1263
- prepareWithdrawToken(creditFacade, token, amount, to) {
1264
- return {
1265
- target: creditFacade,
1266
- callData: encodeFunctionData({
1267
- abi: iCreditFacadeMulticallV310Abi,
1268
- functionName: "withdrawCollateral",
1269
- args: [token, amount, to]
1270
- })
1271
- };
1272
- }
1273
- #prepareIncreaseDebt(creditFacade, debt) {
1274
- return {
1275
- target: creditFacade,
1276
- callData: encodeFunctionData({
1277
- abi: iCreditFacadeMulticallV310Abi,
1278
- functionName: "increaseDebt",
1279
- args: [debt]
1280
- })
1281
- };
1282
- }
1283
- #prepareChangeDebt(creditFacade, change, isDecrease) {
1284
- return {
1285
- target: creditFacade,
1286
- callData: encodeFunctionData({
1287
- abi: iCreditFacadeMulticallV310Abi,
1288
- functionName: isDecrease ? "decreaseDebt" : "increaseDebt",
1289
- args: [change]
1290
- })
1291
- };
1292
- }
1293
- prepareAddCollateral(creditFacade, assets, permits) {
1294
- const calls = assets.map(({ token, balance }) => {
1295
- const p = permits[token];
1296
- if (p) {
1297
- return {
1298
- target: creditFacade,
1299
- callData: encodeFunctionData({
1300
- abi: iCreditFacadeMulticallV310Abi,
1301
- functionName: "addCollateralWithPermit",
1302
- args: [token, balance, p.deadline, p.v, p.r, p.s]
1303
- })
1304
- };
1305
- }
1306
- return {
1307
- target: creditFacade,
1308
- callData: encodeFunctionData({
1309
- abi: iCreditFacadeMulticallV310Abi,
1310
- functionName: "addCollateral",
1311
- args: [token, balance]
1312
- })
1313
- };
1314
- });
1315
- return calls;
1316
- }
1317
- /**
1318
- * Returns addresses of market configurators
1319
- */
1320
- get marketConfigurators() {
1321
- return this.sdk.marketRegister.marketConfigurators.map((mc) => mc.address);
1322
- }
1323
- get rewardCompressor() {
1324
- return this.sdk.addressProvider.mustGetLatest(
1325
- AP_REWARDS_COMPRESSOR,
1326
- VERSION_RANGE_310
1327
- )[0];
1328
- }
1329
- get peripheryCompressor() {
1330
- return this.sdk.addressProvider.mustGetLatest(
1331
- AP_PERIPHERY_COMPRESSOR,
1332
- VERSION_RANGE_310
1333
- )[0];
1334
- }
1335
- /**
1336
- * Wrapper that selects between credit facade and KYC factory
1337
- * @param suite
1338
- * @param to
1339
- * @param calls
1340
- * @param referralCode
1341
- * @param kycOptions
1342
- * @returns
1343
- */
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
- }
1354
- return suite.creditFacade.openCreditAccount(to, calls, referralCode ?? 0n);
1355
- }
1356
- /**
1357
- * Wrapper that selects between credit facade and KYC factory
1358
- * @param suite
1359
- * @param creditAccount
1360
- * @param calls
1361
- * @param kycOptions
1362
- * @returns
1363
- */
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
- }
1372
- return suite.creditFacade.multicall(creditAccount, calls);
1373
- }
1374
- /**
1375
- * Wrapper that selects between credit facade and KYC factory
1376
- * @param suite
1377
- * @param creditAccount
1378
- * @param calls
1379
- * @param operation
1380
- * @param kycOptions
1381
- * @returns
1382
- */
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;
1388
- if (operation === "close") {
1389
- if (factory) {
1390
- throw new Error(
1391
- "CloseOptions=close is not supported for KYC underlying credit accounts"
1392
- );
1393
- }
1394
- return suite.creditFacade.closeCreditAccount(creditAccount, calls);
1395
- }
1396
- if (factory) {
1397
- return factory.multicall(creditAccount, calls, kycOptions);
1398
- }
1399
- return suite.creditFacade.multicall(creditAccount, calls);
1400
- }
1401
- }
1402
- export {
1403
- AbstractCreditAccountService,
1404
- getWithdrawalCompressorAddress
1405
- };