@gearbox-protocol/sdk 14.12.0-next.73 → 14.12.0-next.75

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 (91) hide show
  1. package/dist/cjs/dev/AccountOpener.js +2 -5
  2. package/dist/cjs/plugins/accounts-counter/AccountsCounterPlugin.js +1 -1
  3. package/dist/cjs/sdk/accounts/CreditAccountsServiceV310.js +118 -974
  4. package/dist/cjs/sdk/accounts/credit-account-compressor/CreditAccountCompressor.js +280 -0
  5. package/dist/cjs/sdk/accounts/credit-account-compressor/CreditAccountCompressorV310Contract.js +141 -0
  6. package/dist/cjs/sdk/accounts/credit-account-compressor/index.js +6 -0
  7. package/dist/cjs/sdk/accounts/credit-account-compressor/types.js +1 -0
  8. package/dist/cjs/sdk/accounts/index.js +5 -4
  9. package/dist/cjs/sdk/accounts/intents/operations/unwrap-rwa-collateral/index.js +1 -1
  10. package/dist/cjs/sdk/accounts/intents/operations/wrap-rwa-collateral/index.js +1 -1
  11. package/dist/cjs/sdk/accounts/intents/testing/sdk-mock.js +2 -2
  12. package/dist/cjs/sdk/accounts/liquidations/LiquidationsService.js +3 -3
  13. package/dist/cjs/sdk/accounts/liquidations/constants.js +0 -2
  14. package/dist/cjs/sdk/accounts/liquidations/index.js +0 -2
  15. package/dist/cjs/sdk/constants/index.js +1 -0
  16. package/dist/cjs/sdk/constants/math.js +5 -0
  17. package/dist/cjs/sdk/index.js +12 -4
  18. package/dist/cjs/sdk/market/MarketRegister.js +10 -0
  19. package/dist/cjs/sdk/market/credit/CreditFacadeV310Contract.js +181 -0
  20. package/dist/cjs/sdk/market/credit/CreditSuite.js +107 -1
  21. package/dist/cjs/sdk/{accounts → market/credit}/dominantCollateral.js +18 -4
  22. package/dist/cjs/sdk/market/credit/index.js +3 -0
  23. package/dist/cjs/sdk/market/index.js +3 -0
  24. package/dist/cjs/sdk/market/math.js +59 -0
  25. package/dist/cjs/sdk/market/oracle/PriceOracleBaseContract.js +41 -1
  26. package/dist/cjs/sdk/market/oracle/PriceOracleV310Contract.js +0 -30
  27. package/dist/cjs/sdk/market/pricefeeds/PriceFeedsRegister.js +1 -1
  28. package/dist/cjs/sdk/opportunities/index.js +4 -0
  29. package/dist/esm/dev/AccountOpener.js +2 -5
  30. package/dist/esm/plugins/accounts-counter/AccountsCounterPlugin.js +1 -1
  31. package/dist/esm/sdk/accounts/CreditAccountsServiceV310.js +121 -977
  32. package/dist/esm/sdk/accounts/credit-account-compressor/CreditAccountCompressor.js +279 -0
  33. package/dist/esm/sdk/accounts/credit-account-compressor/CreditAccountCompressorV310Contract.js +141 -0
  34. package/dist/esm/sdk/accounts/credit-account-compressor/index.js +4 -0
  35. package/dist/esm/sdk/accounts/credit-account-compressor/types.js +1 -0
  36. package/dist/esm/sdk/accounts/index.js +4 -3
  37. package/dist/esm/sdk/accounts/intents/operations/unwrap-rwa-collateral/index.js +1 -1
  38. package/dist/esm/sdk/accounts/intents/operations/wrap-rwa-collateral/index.js +1 -1
  39. package/dist/esm/sdk/accounts/intents/testing/sdk-mock.js +2 -2
  40. package/dist/esm/sdk/accounts/liquidations/LiquidationsService.js +2 -2
  41. package/dist/esm/sdk/accounts/liquidations/constants.js +1 -2
  42. package/dist/esm/sdk/accounts/liquidations/index.js +1 -2
  43. package/dist/esm/sdk/constants/index.js +2 -2
  44. package/dist/esm/sdk/constants/math.js +5 -1
  45. package/dist/esm/sdk/index.js +6 -5
  46. package/dist/esm/sdk/market/MarketRegister.js +10 -0
  47. package/dist/esm/sdk/market/credit/CreditFacadeV310Contract.js +181 -0
  48. package/dist/esm/sdk/market/credit/CreditSuite.js +108 -2
  49. package/dist/esm/sdk/{accounts → market/credit}/dominantCollateral.js +18 -5
  50. package/dist/esm/sdk/market/credit/index.js +2 -1
  51. package/dist/esm/sdk/market/index.js +2 -1
  52. package/dist/esm/sdk/market/math.js +56 -1
  53. package/dist/esm/sdk/market/oracle/PriceOracleBaseContract.js +41 -1
  54. package/dist/esm/sdk/market/oracle/PriceOracleV310Contract.js +1 -31
  55. package/dist/esm/sdk/market/pricefeeds/PriceFeedsRegister.js +1 -1
  56. package/dist/esm/sdk/opportunities/index.js +2 -2
  57. package/dist/types/plugins/accounts/AccountsPlugin.d.ts +1 -1
  58. package/dist/types/sdk/OnchainSDK.d.ts +1 -1
  59. package/dist/types/sdk/accounts/CreditAccountsServiceV310.d.ts +23 -124
  60. package/dist/types/sdk/accounts/credit-account-compressor/CreditAccountCompressor.d.ts +60 -0
  61. package/dist/types/sdk/accounts/credit-account-compressor/CreditAccountCompressorV310Contract.d.ts +879 -0
  62. package/dist/types/sdk/accounts/credit-account-compressor/index.d.ts +4 -0
  63. package/dist/types/sdk/accounts/credit-account-compressor/types.d.ts +164 -0
  64. package/dist/types/sdk/accounts/index.d.ts +7 -5
  65. package/dist/types/sdk/accounts/liquidations/constants.d.ts +1 -2
  66. package/dist/types/sdk/accounts/liquidations/index.d.ts +1 -2
  67. package/dist/types/sdk/accounts/types.d.ts +46 -457
  68. package/dist/types/sdk/base/index.d.ts +2 -2
  69. package/dist/types/sdk/base/types.d.ts +6 -1
  70. package/dist/types/sdk/constants/index.d.ts +2 -2
  71. package/dist/types/sdk/constants/math.d.ts +5 -1
  72. package/dist/types/sdk/index.d.ts +16 -14
  73. package/dist/types/sdk/market/MarketRegister.d.ts +7 -0
  74. package/dist/types/sdk/market/credit/CreditFacadeV310Contract.d.ts +47 -2
  75. package/dist/types/sdk/market/credit/CreditSuite.d.ts +24 -2
  76. package/dist/types/sdk/{accounts → market/credit}/dominantCollateral.d.ts +13 -6
  77. package/dist/types/sdk/market/credit/index.d.ts +3 -2
  78. package/dist/types/sdk/market/credit/types.d.ts +112 -2
  79. package/dist/types/sdk/market/index.d.ts +4 -3
  80. package/dist/types/sdk/market/math.d.ts +60 -1
  81. package/dist/types/sdk/market/oracle/PriceOracleBaseContract.d.ts +15 -4
  82. package/dist/types/sdk/market/oracle/PriceOracleV310Contract.d.ts +0 -10
  83. package/dist/types/sdk/market/oracle/index.d.ts +2 -2
  84. package/dist/types/sdk/market/oracle/types.d.ts +30 -14
  85. package/dist/types/sdk/market/rwa/securitize/SecuritizeRWAFactory.d.ts +1 -1
  86. package/dist/types/sdk/market/rwa/types.d.ts +1 -1
  87. package/dist/types/sdk/opportunities/index.d.ts +2 -2
  88. package/package.json +1 -1
  89. package/dist/cjs/sdk/accounts/constants.js +0 -12
  90. package/dist/esm/sdk/accounts/constants.js +0 -11
  91. package/dist/types/sdk/accounts/constants.d.ts +0 -11
@@ -1,8 +1,11 @@
1
+ import { AssetsMap } from "../../utils/AssetsMap.js";
1
2
  import { ADDRESS_0X0 } from "../../constants/addresses.js";
3
+ import { MAX_UINT256, MIN_INT96 } from "../../constants/math.js";
2
4
  import "../../constants/index.js";
3
5
  import { fmtBinaryMask, formatBNvalue, formatTimestamp } from "../../utils/formatter.js";
4
6
  import "../../utils/index.js";
5
7
  import { CreditFacadeV310BaseContract } from "./CreditFacadeV310BaseContract.js";
8
+ import { encodeFunctionData } from "viem";
6
9
  //#region src/sdk/market/credit/CreditFacadeV310Contract.ts
7
10
  var CreditFacadeV310Contract = class extends CreditFacadeV310BaseContract {
8
11
  underlying;
@@ -107,6 +110,184 @@ var CreditFacadeV310Contract = class extends CreditFacadeV310BaseContract {
107
110
  ]
108
111
  });
109
112
  }
113
+ /**
114
+ * {@inheritDoc ICreditFacadeContract.prepareIncreaseDebt}
115
+ */
116
+ prepareIncreaseDebt(amount) {
117
+ return {
118
+ target: this.address,
119
+ callData: encodeFunctionData({
120
+ abi: this.abi,
121
+ functionName: "increaseDebt",
122
+ args: [amount]
123
+ })
124
+ };
125
+ }
126
+ /**
127
+ * {@inheritDoc ICreditFacadeContract.prepareChangeDebt}
128
+ */
129
+ prepareChangeDebt(change, isDecrease) {
130
+ return {
131
+ target: this.address,
132
+ callData: encodeFunctionData({
133
+ abi: this.abi,
134
+ functionName: isDecrease ? "decreaseDebt" : "increaseDebt",
135
+ args: [change]
136
+ })
137
+ };
138
+ }
139
+ /**
140
+ * {@inheritDoc ICreditFacadeContract.prepareDecreaseDebtFull}
141
+ */
142
+ prepareDecreaseDebtFull() {
143
+ return {
144
+ target: this.address,
145
+ callData: encodeFunctionData({
146
+ abi: this.abi,
147
+ functionName: "decreaseDebt",
148
+ args: [MAX_UINT256]
149
+ })
150
+ };
151
+ }
152
+ /**
153
+ * {@inheritDoc ICreditFacadeContract.prepareWithdrawCollateral}
154
+ */
155
+ prepareWithdrawCollateral(token, amount, to) {
156
+ return {
157
+ target: this.address,
158
+ callData: encodeFunctionData({
159
+ abi: this.abi,
160
+ functionName: "withdrawCollateral",
161
+ args: [
162
+ token,
163
+ amount,
164
+ to
165
+ ]
166
+ })
167
+ };
168
+ }
169
+ /**
170
+ * {@inheritDoc ICreditFacadeContract.prepareAddCollateral}
171
+ */
172
+ prepareAddCollateral(assets, permits) {
173
+ return assets.map(({ token, balance }) => {
174
+ const p = permits[token];
175
+ if (p) return {
176
+ target: this.address,
177
+ callData: encodeFunctionData({
178
+ abi: this.abi,
179
+ functionName: "addCollateralWithPermit",
180
+ args: [
181
+ token,
182
+ balance,
183
+ p.deadline,
184
+ p.v,
185
+ p.r,
186
+ p.s
187
+ ]
188
+ })
189
+ };
190
+ return {
191
+ target: this.address,
192
+ callData: encodeFunctionData({
193
+ abi: this.abi,
194
+ functionName: "addCollateral",
195
+ args: [token, balance]
196
+ })
197
+ };
198
+ });
199
+ }
200
+ /**
201
+ * {@inheritDoc ICreditFacadeContract.prepareUpdateQuotas}
202
+ */
203
+ prepareUpdateQuotas({ averageQuota, minQuota }) {
204
+ const minRecord = new AssetsMap(minQuota);
205
+ return averageQuota.map((q) => {
206
+ const minBalance = minRecord.get(q.token);
207
+ const min = minBalance && minBalance > 0n ? minBalance : 0n;
208
+ return {
209
+ target: this.address,
210
+ callData: encodeFunctionData({
211
+ abi: this.abi,
212
+ functionName: "updateQuota",
213
+ args: [
214
+ q.token,
215
+ q.balance,
216
+ min
217
+ ]
218
+ })
219
+ };
220
+ });
221
+ }
222
+ /**
223
+ * {@inheritDoc ICreditFacadeContract.prepareDisableQuotas}
224
+ */
225
+ prepareDisableQuotas(tokens) {
226
+ return tokens.filter((t) => t.quota > 0n).map((t) => ({
227
+ target: this.address,
228
+ callData: encodeFunctionData({
229
+ abi: this.abi,
230
+ functionName: "updateQuota",
231
+ args: [
232
+ t.token,
233
+ MIN_INT96,
234
+ 0n
235
+ ]
236
+ })
237
+ }));
238
+ }
239
+ /**
240
+ * {@inheritDoc ICreditFacadeContract.prepareSetBotPermissions}
241
+ */
242
+ prepareSetBotPermissions(bot, permissions) {
243
+ return {
244
+ target: this.address,
245
+ callData: encodeFunctionData({
246
+ abi: this.abi,
247
+ functionName: "setBotPermissions",
248
+ args: [bot, permissions]
249
+ })
250
+ };
251
+ }
252
+ /**
253
+ * {@inheritDoc ICreditFacadeContract.prepareOnDemandPriceUpdates}
254
+ */
255
+ prepareOnDemandPriceUpdates(updates) {
256
+ return {
257
+ target: this.address,
258
+ callData: encodeFunctionData({
259
+ abi: this.abi,
260
+ functionName: "onDemandPriceUpdates",
261
+ args: [updates]
262
+ })
263
+ };
264
+ }
265
+ /**
266
+ * {@inheritDoc ICreditFacadeContract.prepareStoreExpectedBalances}
267
+ */
268
+ prepareStoreExpectedBalances(deltas) {
269
+ return {
270
+ target: this.address,
271
+ callData: encodeFunctionData({
272
+ abi: this.abi,
273
+ functionName: "storeExpectedBalances",
274
+ args: [deltas]
275
+ })
276
+ };
277
+ }
278
+ /**
279
+ * {@inheritDoc ICreditFacadeContract.prepareCompareBalances}
280
+ */
281
+ prepareCompareBalances() {
282
+ return {
283
+ target: this.address,
284
+ callData: encodeFunctionData({
285
+ abi: this.abi,
286
+ functionName: "compareBalances",
287
+ args: []
288
+ })
289
+ };
290
+ }
110
291
  };
111
292
  //#endregion
112
293
  export { CreditFacadeV310Contract };
@@ -1,13 +1,16 @@
1
+ import { AddressMap } from "../../utils/AddressMap.js";
1
2
  import { BigIntMath } from "../../utils/bigint-math.js";
2
3
  import { isSunsetStrategy } from "../../chain/chains.js";
3
- import "../../constants/math.js";
4
+ import { PERCENTAGE_FACTOR, RAY } from "../../constants/math.js";
4
5
  import "../../constants/index.js";
6
+ import "../../utils/index.js";
5
7
  import { SDKConstruct } from "../../base/SDKConstruct.js";
6
8
  import "../../base/index.js";
7
- import { additionalBorrowApyBps, borrowApyBps } from "../math.js";
9
+ import { additionalBorrowApyBps, borrowApyBps, minSeizedAmount, optimalHFForPartialLiquidation, optimalRepaidAmount } from "../math.js";
8
10
  import createCreditConfigurator from "./createCreditConfigurator.js";
9
11
  import createCreditFacade from "./createCreditFacade.js";
10
12
  import createCreditManager from "./createCreditManager.js";
13
+ import { mustGetDominantCollateral } from "./dominantCollateral.js";
11
14
  //#region src/sdk/market/credit/CreditSuite.ts
12
15
  /**
13
16
  * SDK aggregate for one credit-manager branch inside a market.
@@ -115,6 +118,20 @@ var CreditSuite = class extends SDKConstruct {
115
118
  return expirationDate > 0 ? expirationDate : null;
116
119
  }
117
120
  /**
121
+ * Liquidation fee pair in effect right now, resolving {@link isExpired} once
122
+ * for both.
123
+ */
124
+ liquidationFees() {
125
+ const cm = this.creditManager;
126
+ return this.isExpired ? {
127
+ feeLiquidation: cm.feeLiquidationExpired,
128
+ liquidationDiscount: cm.liquidationDiscountExpired
129
+ } : {
130
+ feeLiquidation: cm.feeLiquidation,
131
+ liquidationDiscount: cm.liquidationDiscount
132
+ };
133
+ }
134
+ /**
118
135
  * Whether this suite can be used right now. A paused pool blocks borrowing,
119
136
  * so the suite is unusable even when its own facade is live.
120
137
  */
@@ -199,6 +216,95 @@ var CreditSuite = class extends SDKConstruct {
199
216
  };
200
217
  }
201
218
  /**
219
+ * Everything a partial liquidation of credit account needs, with any parameter the
220
+ * caller pinned down taken as given and the rest derived from current state.
221
+ *
222
+ * @param ca - Credit account to partially liquidate.
223
+ * @param overrides - Parameters to use instead of the derived defaults.
224
+ * @throws If a derived `tokenOut` cannot be picked, or if the seized token is
225
+ * not a collateral token of this credit manager.
226
+ */
227
+ partialLiquidationParams(ca, overrides = {}) {
228
+ const tokenOut = overrides.tokenOut ?? this.#bestTokenOut(ca);
229
+ const optimalHF = overrides.optimalHF ?? this.optimalHFForPartialLiquidation(ca);
230
+ const repaidAmount = overrides.repaidAmount ?? this.#optimalRepaidAmount(ca, tokenOut, optimalHF);
231
+ return {
232
+ tokenOut,
233
+ optimalHF,
234
+ repaidAmount,
235
+ minSeizedAmount: overrides.minSeizedAmount ?? this.#minSeizedAmount(tokenOut, repaidAmount)
236
+ };
237
+ }
238
+ /**
239
+ * Health factor a partial liquidation of `ca` should target, in basis points.
240
+ *
241
+ * @param ca - Credit account to partially liquidate.
242
+ */
243
+ optimalHFForPartialLiquidation(ca) {
244
+ return optimalHFForPartialLiquidation(this.#borrowRate(ca));
245
+ }
246
+ /**
247
+ * Collateral token a partial liquidation seizes by default.
248
+ *
249
+ * Ported from solidity:
250
+ * https://github.com/Gearbox-protocol/router-v3/blob/main/contracts/liquidation/AbstractLiquidator.sol#L270
251
+ */
252
+ #bestTokenOut(ca) {
253
+ return mustGetDominantCollateral(ca, this.market);
254
+ }
255
+ /**
256
+ * Minimum amount of `token` that must be seized when repaying `repaidAmount`
257
+ * of underlying.
258
+ */
259
+ #minSeizedAmount(token, repaidAmount) {
260
+ const { market } = this;
261
+ const tokenAmount = market.priceOracle.convert(market.underlying, token, repaidAmount);
262
+ return minSeizedAmount(tokenAmount, this.liquidationFees().liquidationDiscount);
263
+ }
264
+ /**
265
+ * Amount of underlying to repay to bring `ca`'s health factor close to
266
+ * `optimalHF` by seizing `token`.
267
+ *
268
+ * @throws If `token` is not a collateral token of this credit manager.
269
+ */
270
+ #optimalRepaidAmount(ca, token, optimalHF) {
271
+ const { creditManager: cm, market } = this;
272
+ const { feeLiquidation, liquidationDiscount } = this.liquidationFees();
273
+ const ltTokenOut = cm.liquidationThresholds.get(token);
274
+ if (ltTokenOut === void 0) throw new Error(`token ${this.labelAddress(token)} is not a collateral token in credit manager ${this.labelAddress(cm.address)}`);
275
+ return optimalRepaidAmount({
276
+ totalDebt: ca.debt + ca.accruedInterest + ca.accruedFees,
277
+ twvUnderlying: market.priceOracle.convertFromUSD(market.underlying, ca.twvUSD),
278
+ minDebt: this.creditFacade.minDebt,
279
+ optimalHF,
280
+ discount: BigInt(liquidationDiscount) - BigInt(feeLiquidation),
281
+ ltTokenOut: BigInt(ltTokenOut)
282
+ });
283
+ }
284
+ /**
285
+ * Blended annual cost of credit account's debt, in basis points: base interest weighted
286
+ * by the account's share of its own total debt, plus the quota rates of the
287
+ * collaterals it actually holds, both marked up by the interest fee.
288
+ */
289
+ #borrowRate(ca) {
290
+ const { creditManager } = this;
291
+ const { pool } = this.market;
292
+ const { feeInterest } = creditManager;
293
+ const { baseInterestRate } = pool.pool;
294
+ const baseRateWithFee = baseInterestRate * (BigInt(feeInterest) + PERCENTAGE_FACTOR);
295
+ const totalDebt = ca.debt + ca.accruedInterest + ca.accruedFees;
296
+ const r = ca.debt * baseRateWithFee / (totalDebt * RAY);
297
+ const caTokens = new AddressMap(ca.tokens.map((t) => [t.token, t]));
298
+ let qr = 0n;
299
+ for (const t of creditManager.collateralTokens) {
300
+ const b = caTokens.get(t);
301
+ if (b) qr += b.quota * BigInt(pool.pqk.quotas.get(t)?.rate ?? 0);
302
+ }
303
+ qr = qr * (BigInt(feeInterest) + PERCENTAGE_FACTOR) / PERCENTAGE_FACTOR;
304
+ qr /= totalDebt;
305
+ return r + qr;
306
+ }
307
+ /**
202
308
  * Whether the facade, manager, or configurator has observed logs that require
203
309
  * a credit-suite resync.
204
310
  */
@@ -1,7 +1,8 @@
1
- import { hexEq } from "../utils/hex.js";
2
- import "../utils/index.js";
3
- import "./constants.js";
4
- //#region src/sdk/accounts/dominantCollateral.ts
1
+ import "../../constants/math.js";
2
+ import "../../constants/index.js";
3
+ import { hexEq } from "../../utils/hex.js";
4
+ import "../../utils/index.js";
5
+ //#region src/sdk/market/credit/dominantCollateral.ts
5
6
  /**
6
7
  * The account's dominant collateral: the most valuable enabled non-underlying
7
8
  * token it holds above dust, by USD value.
@@ -28,5 +29,17 @@ function dominantCollateral(account, market) {
28
29
  }
29
30
  return dominant;
30
31
  }
32
+ /**
33
+ * {@link dominantCollateral}, for callers that cannot proceed without one, such
34
+ * as picking the collateral a partial liquidation seizes.
35
+ *
36
+ * @throws If the account holds no enabled non-underlying collateral the oracle
37
+ * can price.
38
+ **/
39
+ function mustGetDominantCollateral(account, market) {
40
+ const collateral = dominantCollateral(account, market);
41
+ if (!collateral) throw new Error(`cannot determine tokenOut for partial liquidation of ${market.sdk.labelAddress(account.creditAccount)}: no enabled non-underlying collateral with value`);
42
+ return collateral;
43
+ }
31
44
  //#endregion
32
- export { dominantCollateral };
45
+ export { dominantCollateral, mustGetDominantCollateral };
@@ -2,6 +2,7 @@ import { CreditConfiguratorV310Contract } from "./CreditConfiguratorV310Contract
2
2
  import { CreditFacadeV310BaseContract, creditFacadeV310Abi as abi } from "./CreditFacadeV310BaseContract.js";
3
3
  import { CreditFacadeV310Contract } from "./CreditFacadeV310Contract.js";
4
4
  import { CreditManagerV310Contract } from "./CreditManagerV310Contract.js";
5
+ import { dominantCollateral, mustGetDominantCollateral } from "./dominantCollateral.js";
5
6
  import { CreditSuite } from "./CreditSuite.js";
6
7
  import "./types.js";
7
- export { CreditConfiguratorV310Contract, CreditFacadeV310BaseContract, CreditFacadeV310Contract, CreditManagerV310Contract, CreditSuite, abi as creditFacadeV310Abi };
8
+ export { CreditConfiguratorV310Contract, CreditFacadeV310BaseContract, CreditFacadeV310Contract, CreditManagerV310Contract, CreditSuite, abi as creditFacadeV310Abi, dominantCollateral, mustGetDominantCollateral };
@@ -5,6 +5,7 @@ import { CreditConfiguratorV310Contract } from "./credit/CreditConfiguratorV310C
5
5
  import { CreditFacadeV310BaseContract, creditFacadeV310Abi as abi } from "./credit/CreditFacadeV310BaseContract.js";
6
6
  import { CreditFacadeV310Contract } from "./credit/CreditFacadeV310Contract.js";
7
7
  import { CreditManagerV310Contract } from "./credit/CreditManagerV310Contract.js";
8
+ import { dominantCollateral, mustGetDominantCollateral } from "./credit/dominantCollateral.js";
8
9
  import { CreditSuite } from "./credit/CreditSuite.js";
9
10
  import "./credit/index.js";
10
11
  import { isUpdatablePriceFeed } from "./pricefeeds/isUpdatablePriceFeed.js";
@@ -58,4 +59,4 @@ import { RWARegistry } from "./rwa/RWARegistry.js";
58
59
  import { RWA_FACTORY_TYPES, isRWAFactory } from "./rwa/types.js";
59
60
  import "./rwa/index.js";
60
61
  import "./types.js";
61
- export { AbstractLPPriceFeedContract, AbstractPriceFeedContract, BalancerStablePriceFeedContract, BalancerWeightedPriceFeedContract, BoundedPriceFeedContract, CompositePriceFeedContract, CreditConfiguratorV310Contract, CreditFacadeV310BaseContract, CreditFacadeV310Contract, CreditManagerV310Contract, CreditSuite, CurveCryptoPriceFeedContract, CurveStablePriceFeedContract, CurveUSDPriceFeedContract, Erc4626PriceFeedContract, ExternalPriceFeedContract, GaugeContract, IERC20ZapperContract, IETHZapperContract, LinearInterestRateModelContract, MarketRegister, MarketSuite, MellowLRTPriceFeedContract, MidasLiquidatorContract, PHANTOM_TOKEN_MIDAS_REDEMPTION, PHANTOM_TOKEN_SECURITIZE_REDEMPTION, PartialPriceFeedInitError, PendleTWAPPTPriceFeed, PlaceholderAdapterContract, PoolSuite, PoolV310Contract, PriceFeedRef, PriceFeedRegister, PriceOracleV310Contract, PythPriceFeed, RWARegistry, RWA_FACTORY_SECURITIZE, RWA_FACTORY_TYPES, RWA_LIQUIDATOR_MIDAS, RWA_LIQUIDATOR_SECURITIZE, RedstonePriceFeedContract, SECURITIZE_REGISTER_VAULT_TYPES, SecuritizeLiquidatorContract, SecuritizeRWAFactory, UnsupportedZapperFunctionError, WstETHPriceFeedContract, YearnPriceFeedContract, ZapperContract, ZeroPriceFeedContract, createAdapter, createPriceOracle, createZapper, abi as creditFacadeV310Abi, fetchPythPayloads, fetchRedstonePayloads, getRawPriceUpdates, isLPPriceFeed, isRWAFactory, isUpdatablePriceFeed };
62
+ export { AbstractLPPriceFeedContract, AbstractPriceFeedContract, BalancerStablePriceFeedContract, BalancerWeightedPriceFeedContract, BoundedPriceFeedContract, CompositePriceFeedContract, CreditConfiguratorV310Contract, CreditFacadeV310BaseContract, CreditFacadeV310Contract, CreditManagerV310Contract, CreditSuite, CurveCryptoPriceFeedContract, CurveStablePriceFeedContract, CurveUSDPriceFeedContract, Erc4626PriceFeedContract, ExternalPriceFeedContract, GaugeContract, IERC20ZapperContract, IETHZapperContract, LinearInterestRateModelContract, MarketRegister, MarketSuite, MellowLRTPriceFeedContract, MidasLiquidatorContract, PHANTOM_TOKEN_MIDAS_REDEMPTION, PHANTOM_TOKEN_SECURITIZE_REDEMPTION, PartialPriceFeedInitError, PendleTWAPPTPriceFeed, PlaceholderAdapterContract, PoolSuite, PoolV310Contract, PriceFeedRef, PriceFeedRegister, PriceOracleV310Contract, PythPriceFeed, RWARegistry, RWA_FACTORY_SECURITIZE, RWA_FACTORY_TYPES, RWA_LIQUIDATOR_MIDAS, RWA_LIQUIDATOR_SECURITIZE, RedstonePriceFeedContract, SECURITIZE_REGISTER_VAULT_TYPES, SecuritizeLiquidatorContract, SecuritizeRWAFactory, UnsupportedZapperFunctionError, WstETHPriceFeedContract, YearnPriceFeedContract, ZapperContract, ZeroPriceFeedContract, createAdapter, createPriceOracle, createZapper, abi as creditFacadeV310Abi, dominantCollateral, fetchPythPayloads, fetchRedstonePayloads, getRawPriceUpdates, isLPPriceFeed, isRWAFactory, isUpdatablePriceFeed, mustGetDominantCollateral };
@@ -129,5 +129,60 @@ function additionalBorrowApyBps(quotaRate, leverage) {
129
129
  if (!Number.isFinite(leverage)) return 0;
130
130
  return Math.round(quotaRate * Math.max(leverage - 1, 0));
131
131
  }
132
+ /**
133
+ * {@link PERCENTAGE_FACTOR} less a 0.1% safety buffer.
134
+ *
135
+ * Partial liquidation amounts are computed off prices that can drift between
136
+ * quoting and execution, so both the seized and the repaid amount are pulled
137
+ * this far away from the boundary the contracts would revert on.
138
+ **/
139
+ const PARTIAL_LIQUIDATION_BUFFER_BPS = 9990n;
140
+ /**
141
+ * Minimum collateral a partial liquidation must seize for a given repayment,
142
+ * derived from the liquidation discount and buffered by
143
+ * {@link PARTIAL_LIQUIDATION_BUFFER_BPS}.
144
+ *
145
+ * @param tokenAmount - Repaid amount converted from underlying into the seized
146
+ * token by the oracle.
147
+ * @param liquidationDiscount - Discount in effect for this account, in basis
148
+ * points (the expired variant once the credit manager has expired).
149
+ **/
150
+ function minSeizedAmount(tokenAmount, liquidationDiscount) {
151
+ return tokenAmount * PARTIAL_LIQUIDATION_BUFFER_BPS / BigInt(liquidationDiscount);
152
+ }
153
+ /**
154
+ * Amount of underlying whose repayment brings the account's health factor close
155
+ * to `optimalHF`, capped so the account keeps at least `minDebt` of debt.
156
+ *
157
+ * Ported from solidity:
158
+ * https://github.com/Gearbox-protocol/router-v3/blob/56e2d515ec6d9bb1e324e71c3708e59710779b24/contracts/liquidation/AbstractLiquidator.sol#L292
159
+ *
160
+ * @returns The repaid amount, or `0n` when the account is already healthy
161
+ * enough or carries less than the minimum debt.
162
+ * @throws If the discounted target health factor does not exceed the seized
163
+ * token's liquidation threshold, in which case no repayment improves the
164
+ * account.
165
+ **/
166
+ function optimalRepaidAmount({ totalDebt, twvUnderlying, minDebt, optimalHF, discount, ltTokenOut }) {
167
+ const denominator = discount * optimalHF / PERCENTAGE_FACTOR - ltTokenOut;
168
+ if (denominator <= 0n) throw new Error("cannot compute optimal repaid amount: invalid liquidation parameters (discount * hfOptimal <= ltTokenOut)");
169
+ const numerator = totalDebt * optimalHF - twvUnderlying * PERCENTAGE_FACTOR;
170
+ if (numerator <= 0n) return 0n;
171
+ const repaidAmount = numerator / denominator * discount / PERCENTAGE_FACTOR;
172
+ if (totalDebt < minDebt) return 0n;
173
+ const surplusDebt = totalDebt - minDebt;
174
+ if (repaidAmount > surplusDebt) return surplusDebt * PARTIAL_LIQUIDATION_BUFFER_BPS / PERCENTAGE_FACTOR;
175
+ return repaidAmount;
176
+ }
177
+ /**
178
+ * Health factor a partial liquidation should target, in basis points: just
179
+ * above 1, by enough to cover up to 1% of borrow cost so the account does not
180
+ * fall back under water immediately.
181
+ *
182
+ * @param borrowRate - Blended borrow rate of the account, in basis points.
183
+ **/
184
+ function optimalHFForPartialLiquidation(borrowRate) {
185
+ return PERCENTAGE_FACTOR + (borrowRate < 100n ? borrowRate : 100n);
186
+ }
132
187
  //#endregion
133
- export { additionalBorrowApyBps, borrowApyBps, healthFactorBps, maxLeverage, positionLeverage, rayToBps, usdToNumber, utilizationBps };
188
+ export { PARTIAL_LIQUIDATION_BUFFER_BPS, additionalBorrowApyBps, borrowApyBps, healthFactorBps, maxLeverage, minSeizedAmount, optimalHFForPartialLiquidation, optimalRepaidAmount, positionLeverage, rayToBps, usdToNumber, utilizationBps };
@@ -1,5 +1,7 @@
1
1
  import { AddressMap } from "../../utils/AddressMap.js";
2
+ import { AddressSet } from "../../utils/AddressSet.js";
2
3
  import { AP_PRICE_FEED_COMPRESSOR } from "../../constants/address-provider.js";
4
+ import "../../constants/math.js";
3
5
  import { VERSION_RANGE_310 } from "../../constants/versions.js";
4
6
  import "../../constants/index.js";
5
7
  import { formatBN } from "../../utils/formatter.js";
@@ -7,8 +9,9 @@ import "../../utils/index.js";
7
9
  import { BaseContract } from "../../base/BaseContract.js";
8
10
  import "../../base/index.js";
9
11
  import { usdToNumber } from "../math.js";
10
- import { PriceFeedRef } from "../pricefeeds/PriceFeedRef.js";
11
12
  import { priceFeedCompressorAbi } from "../../../abi/compressors/priceFeedCompressor.js";
13
+ import { PriceFeedRef } from "../pricefeeds/PriceFeedRef.js";
14
+ import { getRawPriceUpdates } from "../pricefeeds/getRawPriceUpdates.js";
12
15
  import "../pricefeeds/index.js";
13
16
  import PriceFeedAnswerMap from "./PriceFeedAnswerMap.js";
14
17
  import { stringToHex } from "viem";
@@ -58,6 +61,31 @@ var PriceOracleBaseContract = class extends BaseContract {
58
61
  return tokens.flatMap((t) => [main ? this.mainPriceFeeds.get(t)?.priceFeed : void 0, reserve ? this.reservePriceFeeds.get(t)?.priceFeed : void 0]).filter((f) => !!f);
59
62
  }
60
63
  /**
64
+ * {@inheritDoc IPriceOracleContract.priceUpdateTxsForAccount}
65
+ **/
66
+ async priceUpdateTxsForAccount(account, opts) {
67
+ return this.#priceUpdateTxsForTokens(getAccountTokens(account, opts?.extraTokens), opts);
68
+ }
69
+ /**
70
+ * {@inheritDoc IPriceOracleContract.priceUpdatesForAccount}
71
+ **/
72
+ async priceUpdatesForAccount(account, opts) {
73
+ return getRawPriceUpdates(await this.priceUpdateTxsForAccount(account, opts));
74
+ }
75
+ /**
76
+ * {@inheritDoc IPriceOracleContract.priceUpdatesForTokens}
77
+ **/
78
+ async priceUpdatesForTokens(tokens, opts) {
79
+ return getRawPriceUpdates(await this.#priceUpdateTxsForTokens(tokens, opts));
80
+ }
81
+ async #priceUpdateTxsForTokens(tokens, opts) {
82
+ const priceFeeds = this.priceFeedsForTokens(tokens, opts);
83
+ const tStr = tokens.map((t) => this.labelAddress(t)).join(", ");
84
+ const remark = opts?.reserve === false ? " main" : "";
85
+ this.logger?.debug(`generating price feed updates for ${tStr} from ${priceFeeds.length}${remark} price feeds`);
86
+ return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(priceFeeds);
87
+ }
88
+ /**
61
89
  * {@inheritDoc IPriceOracleContract.mainPrice}
62
90
  **/
63
91
  mainPrice(token) {
@@ -261,6 +289,18 @@ var PriceOracleBaseContract = class extends BaseContract {
261
289
  }
262
290
  }
263
291
  };
292
+ /**
293
+ * Tokens of an account that have to be priced: its underlying, every enabled
294
+ * token it holds a non-dust balance of, and any extra tokens the caller adds.
295
+ **/
296
+ function getAccountTokens(account, extraTokens) {
297
+ const tokens = new AddressSet([account.underlying, ...extraTokens ?? []]);
298
+ for (const t of account.tokens) {
299
+ const isEnabled = (t.mask & account.enabledTokensMask) !== 0n;
300
+ if (t.balance > 10n && isEnabled) tokens.add(t.token);
301
+ }
302
+ return tokens.asArray();
303
+ }
264
304
  function formatAnswer({ price, success, updatedAt }, raw = true) {
265
305
  if (!success) return "failed";
266
306
  let priceS = formatBN(price, 8);
@@ -1,9 +1,6 @@
1
- import { iCreditFacadeMulticallV310Abi, iPriceOracleV310Abi } from "../../../abi/310/generated.js";
1
+ import { iPriceOracleV310Abi } from "../../../abi/310/generated.js";
2
2
  import { simulateWithPriceUpdates } from "../../utils/viem/simulateWithPriceUpdates.js";
3
- import { getRawPriceUpdates } from "../pricefeeds/getRawPriceUpdates.js";
4
- import "../pricefeeds/index.js";
5
3
  import { PriceOracleBaseContract } from "./PriceOracleBaseContract.js";
6
- import { encodeFunctionData } from "viem";
7
4
  //#region src/sdk/market/oracle/PriceOracleV310Contract.ts
8
5
  const abi = iPriceOracleV310Abi;
9
6
  var PriceOracleV310Contract = class extends PriceOracleBaseContract {
@@ -15,33 +12,6 @@ var PriceOracleV310Contract = class extends PriceOracleBaseContract {
15
12
  }, data);
16
13
  }
17
14
  /**
18
- * Converts previously obtained price updates into CreditFacade multicall entry
19
- * @param creditFacade
20
- * @param updates
21
- * @returns
22
- */
23
- onDemandPriceUpdates(creditFacade, updates) {
24
- if (!updates) {
25
- this.logger?.debug("empty updates list");
26
- return {
27
- multicall: [],
28
- raw: []
29
- };
30
- }
31
- const raw = getRawPriceUpdates(updates);
32
- return {
33
- raw,
34
- multicall: [{
35
- target: creditFacade,
36
- callData: encodeFunctionData({
37
- abi: iCreditFacadeMulticallV310Abi,
38
- functionName: "onDemandPriceUpdates",
39
- args: [raw]
40
- })
41
- }]
42
- };
43
- }
44
- /**
45
15
  * {@inheritDoc IPriceOracleContract.updateAndConvert}
46
16
  **/
47
17
  async updateAndConvert(from, to, amount) {
@@ -8,6 +8,7 @@ import "../../constants/index.js";
8
8
  import "../../utils/index.js";
9
9
  import { SDKConstruct } from "../../base/SDKConstruct.js";
10
10
  import "../../base/index.js";
11
+ import { priceFeedCompressorAbi } from "../../../abi/compressors/priceFeedCompressor.js";
11
12
  import { PartialPriceFeedInitError } from "./AbstractPriceFeed.js";
12
13
  import { BalancerStablePriceFeedContract } from "./BalancerStablePriceFeed.js";
13
14
  import { BalancerWeightedPriceFeedContract } from "./BalancerWeightedPriceFeed.js";
@@ -21,7 +22,6 @@ import { ExternalPriceFeedContract } from "./ExternalPriceFeed.js";
21
22
  import { getRawPriceUpdates } from "./getRawPriceUpdates.js";
22
23
  import { MellowLRTPriceFeedContract } from "./MellowLRTPriceFeed.js";
23
24
  import { PendleTWAPPTPriceFeed } from "./PendleTWAPPTPriceFeed.js";
24
- import { priceFeedCompressorAbi } from "../../../abi/compressors/priceFeedCompressor.js";
25
25
  import { Hooks } from "../../utils/internal/Hooks.js";
26
26
  import "../../utils/internal/index.js";
27
27
  import { ConstantPriceFeedContract } from "./ConstantPriceFeed.js";
@@ -1,4 +1,4 @@
1
- import { additionalBorrowApyBps, borrowApyBps, healthFactorBps, maxLeverage, positionLeverage, rayToBps, usdToNumber, utilizationBps } from "../market/math.js";
1
+ import { PARTIAL_LIQUIDATION_BUFFER_BPS, additionalBorrowApyBps, borrowApyBps, healthFactorBps, maxLeverage, minSeizedAmount, optimalHFForPartialLiquidation, optimalRepaidAmount, positionLeverage, rayToBps, usdToNumber, utilizationBps } from "../market/math.js";
2
2
  import { MultichainOpportunitiesService } from "./MultichainOpportunitiesService.js";
3
3
  import { OpportunitiesService } from "./OpportunitiesService.js";
4
- export { MultichainOpportunitiesService, OpportunitiesService, additionalBorrowApyBps, borrowApyBps, healthFactorBps, maxLeverage, positionLeverage, rayToBps, usdToNumber, utilizationBps };
4
+ export { MultichainOpportunitiesService, OpportunitiesService, PARTIAL_LIQUIDATION_BUFFER_BPS, additionalBorrowApyBps, borrowApyBps, healthFactorBps, maxLeverage, minSeizedAmount, optimalHFForPartialLiquidation, optimalRepaidAmount, positionLeverage, rayToBps, usdToNumber, utilizationBps };
@@ -1,7 +1,7 @@
1
1
  import { CreditAccountData } from "../../sdk/base/types.js";
2
2
  import { BasePlugin } from "../../sdk/plugins/BasePlugin.js";
3
3
  import { IOnchainSDKPlugin } from "../../sdk/plugins/types.js";
4
- import { GetCreditAccountsOptions } from "../../sdk/accounts/types.js";
4
+ import { GetCreditAccountsOptions } from "../../sdk/accounts/credit-account-compressor/types.js";
5
5
  import "../../sdk/index.js";
6
6
  import { Address } from "viem";
7
7
  //#region src/plugins/accounts/AccountsPlugin.d.ts
@@ -6,10 +6,10 @@ import { VersionRange } from "./constants/versions.js";
6
6
  import "./constants/index.js";
7
7
  import { PluginsMap } from "./plugins/types.js";
8
8
  import "./plugins/index.js";
9
+ import { RWARegistry } from "./market/rwa/RWARegistry.js";
9
10
  import { IRouterContract } from "./router/types.js";
10
11
  import "./router/index.js";
11
12
  import { ICreditAccountsService } from "./accounts/types.js";
12
- import { RWARegistry } from "./market/rwa/RWARegistry.js";
13
13
  import { GearboxStateHuman } from "./types/state-human.js";
14
14
  import { PythOptions } from "./market/pricefeeds/updates/PythUpdater.js";
15
15
  import { RedstoneOptions } from "./market/pricefeeds/updates/RedstoneUpdater.js";