@gearbox-protocol/sdk 17.9.0 → 17.10.1-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 (90) hide show
  1. package/dist/cjs/dev/AccountOpener.js +3 -3
  2. package/dist/cjs/onchain/accounts/index.js +2 -0
  3. package/dist/cjs/onchain/accounts/intents/guards.js +4 -2
  4. package/dist/cjs/onchain/accounts/intents/index.js +41 -7
  5. package/dist/cjs/onchain/accounts/intents/math.js +3 -44
  6. package/dist/cjs/onchain/accounts/intents/maxBorrow.js +7 -1
  7. package/dist/cjs/onchain/accounts/intents/open-strategy.js +12 -7
  8. package/dist/cjs/onchain/accounts/intents/plan.js +4 -4
  9. package/dist/cjs/onchain/accounts/intents/realize.js +11 -5
  10. package/dist/cjs/onchain/accounts/intents/strategyLimits.js +159 -0
  11. package/dist/cjs/onchain/accounts/intents/tail.js +5 -1
  12. package/dist/cjs/onchain/accounts/intents/testing/market.js +5 -1
  13. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +5 -0
  14. package/dist/cjs/onchain/accounts/intents/utils/index.js +2 -0
  15. package/dist/cjs/onchain/accounts/intents/utils/quotas-for-update.js +69 -0
  16. package/dist/cjs/onchain/accounts/quota-utils.js +15 -0
  17. package/dist/cjs/onchain/chain/chains.js +12 -0
  18. package/dist/cjs/onchain/chain/index.js +1 -0
  19. package/dist/cjs/onchain/index.js +3 -0
  20. package/dist/cjs/onchain/market/oracle/PriceOracleBaseContract.js +8 -6
  21. package/dist/cjs/onchain/validation/checks/checkBorrowLimit.js +2 -3
  22. package/dist/cjs/onchain/validation/checks/checkDebtLimits.js +3 -4
  23. package/dist/cjs/onchain/validation/checks/checkQuotaLimit.js +2 -1
  24. package/dist/esm/dev/AccountOpener.js +2 -2
  25. package/dist/esm/dev/withdrawalUtils.js +1 -1
  26. package/dist/esm/history/trace/extractTransfers.js +1 -1
  27. package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +2 -2
  28. package/dist/esm/onchain/accounts/index.js +2 -2
  29. package/dist/esm/onchain/accounts/intents/guards.js +4 -2
  30. package/dist/esm/onchain/accounts/intents/index.js +41 -7
  31. package/dist/esm/onchain/accounts/intents/math.js +5 -45
  32. package/dist/esm/onchain/accounts/intents/maxBorrow.js +7 -1
  33. package/dist/esm/onchain/accounts/intents/open-strategy.js +13 -8
  34. package/dist/esm/onchain/accounts/intents/plan.js +4 -4
  35. package/dist/esm/onchain/accounts/intents/realize.js +12 -6
  36. package/dist/esm/onchain/accounts/intents/strategyLimits.js +158 -0
  37. package/dist/esm/onchain/accounts/intents/tail.js +5 -1
  38. package/dist/esm/onchain/accounts/intents/testing/market.js +5 -1
  39. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +5 -0
  40. package/dist/esm/onchain/accounts/intents/utils/index.js +2 -2
  41. package/dist/esm/onchain/accounts/intents/utils/quotas-for-update.js +70 -3
  42. package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +1 -1
  43. package/dist/esm/onchain/accounts/quota-utils.js +14 -1
  44. package/dist/esm/onchain/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
  45. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
  46. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
  47. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
  48. package/dist/esm/onchain/base/TokensMeta.js +3 -3
  49. package/dist/esm/onchain/chain/chains.js +12 -1
  50. package/dist/esm/onchain/chain/index.js +2 -2
  51. package/dist/esm/onchain/core/createAddressProvider.js +1 -1
  52. package/dist/esm/onchain/index.js +3 -3
  53. package/dist/esm/onchain/market/adapters/contracts/AccountMigratorAdapterContract.js +1 -1
  54. package/dist/esm/onchain/market/adapters/contracts/ERC4626AdapterContract.js +1 -1
  55. package/dist/esm/onchain/market/credit/CreditFacadeV310BaseContract.js +1 -1
  56. package/dist/esm/onchain/market/oracle/PriceOracleBaseContract.js +8 -6
  57. package/dist/esm/onchain/market/pool/PoolV310Contract.js +1 -1
  58. package/dist/esm/onchain/market/rwa/createDegenNFT.js +1 -1
  59. package/dist/esm/onchain/market/zapper/IETHZapperContract.js +1 -1
  60. package/dist/esm/onchain/market/zapper/ZapperContract.js +1 -1
  61. package/dist/esm/onchain/preview/preview/previewPoolPositionOperation.js +2 -2
  62. package/dist/esm/onchain/utils/viem/simulateWithPriceUpdates.js +1 -1
  63. package/dist/esm/onchain/validation/checks/checkBorrowLimit.js +2 -3
  64. package/dist/esm/onchain/validation/checks/checkDebtLimits.js +3 -4
  65. package/dist/esm/onchain/validation/checks/checkQuotaLimit.js +2 -1
  66. package/dist/types/model/errors/index.d.ts +2 -2
  67. package/dist/types/model/errors/liquidation-errors.d.ts +4 -0
  68. package/dist/types/model/errors/operation-errors.d.ts +38 -14
  69. package/dist/types/model/errors/oracle-errors.d.ts +2 -0
  70. package/dist/types/model/index.d.ts +2 -2
  71. package/dist/types/onchain/accounts/index.d.ts +2 -2
  72. package/dist/types/onchain/accounts/intents/guards.d.ts +12 -12
  73. package/dist/types/onchain/accounts/intents/math.d.ts +7 -16
  74. package/dist/types/onchain/accounts/intents/plan.d.ts +2 -0
  75. package/dist/types/onchain/accounts/intents/realize.d.ts +3 -0
  76. package/dist/types/onchain/accounts/intents/strategyLimits.d.ts +33 -0
  77. package/dist/types/onchain/accounts/intents/tail.d.ts +13 -9
  78. package/dist/types/onchain/accounts/intents/testing/market.d.ts +4 -0
  79. package/dist/types/onchain/accounts/intents/utils/index.d.ts +2 -2
  80. package/dist/types/onchain/accounts/intents/utils/quotas-for-update.d.ts +21 -1
  81. package/dist/types/onchain/accounts/quota-utils.d.ts +16 -1
  82. package/dist/types/onchain/chain/chains.d.ts +15 -1
  83. package/dist/types/onchain/chain/index.d.ts +2 -2
  84. package/dist/types/onchain/index.d.ts +3 -3
  85. package/dist/types/onchain/market/oracle/PriceOracleBaseContract.d.ts +0 -3
  86. package/dist/types/onchain/market/oracle/types.d.ts +4 -3
  87. package/dist/types/onchain/validation/checks/checkBorrowLimit.d.ts +2 -3
  88. package/dist/types/onchain/validation/checks/checkDebtLimits.d.ts +2 -3
  89. package/dist/types/onchain/validation/checks/checkQuotaLimit.d.ts +2 -2
  90. package/package.json +1 -1
@@ -24,6 +24,7 @@ exports.isPhantomToken = require_onchain_accounts_intents_utils_pick_token.isPha
24
24
  exports.isRedemptionPhantomToken = require_onchain_accounts_intents_utils_pick_token.isRedemptionPhantomToken;
25
25
  exports.lossRate = require_onchain_accounts_intents_utils_price_impact.lossRate;
26
26
  exports.pickFattestNonPhantomToken = require_onchain_accounts_intents_utils_pick_token.pickFattestNonPhantomToken;
27
+ exports.quotaIncreaseLimit = require_onchain_accounts_intents_utils_quotas_for_update.quotaIncreaseLimit;
27
28
  exports.quotasAfterUpdate = require_onchain_accounts_intents_utils_quotas_for_update.quotasAfterUpdate;
28
29
  exports.rankAccountTokens = require_onchain_accounts_intents_utils_pick_token.rankAccountTokens;
29
30
  exports.resolveCreditManager = require_onchain_accounts_intents_utils_common.resolveCreditManager;
@@ -32,3 +33,4 @@ exports.toCreditAccountSlice = require_onchain_accounts_intents_utils_credit_acc
32
33
  exports.toRouterCaSlice = require_onchain_accounts_intents_utils_common.toRouterCaSlice;
33
34
  exports.toTargetDecimals = require_onchain_accounts_intents_utils_common.toTargetDecimals;
34
35
  exports.unopenedAccountSlice = require_onchain_accounts_intents_utils_credit_account_slice.unopenedAccountSlice;
36
+ exports.withDirectTransferQuota = require_onchain_accounts_intents_utils_quotas_for_update.withDirectTransferQuota;
@@ -1,6 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_onchain_utils_bigint_math = require("../../../utils/bigint-math.js");
2
3
  const require_onchain_constants_math = require("../../../constants/math.js");
3
4
  const require_onchain_utils_mappers = require("../../../utils/mappers.js");
5
+ require("../../../constants/index.js");
4
6
  const require_onchain_accounts_quota_utils = require("../../quota-utils.js");
5
7
  //#region src/onchain/accounts/intents/utils/quotas-for-update.ts
6
8
  function getQuotasForUpdate({ assetsBefore, assetsAfter, initialQuotas, quotaReserve = 0, liquidationThresholds: liquidationThresholdsMap, quotas: quotasMap, maxDebt, underlyingToken, convert }) {
@@ -79,6 +81,35 @@ function clearedQuotas(initialQuotas) {
79
81
  };
80
82
  }
81
83
  /**
84
+ * Raises `directTransfer`'s quota to at least {@link DIRECT_TRANSFERS_QUOTA};
85
+ * skips a token absent from the credit manager, one the pool can't quote, or
86
+ * one the account has no free enabled token slot for.
87
+ */
88
+ function withDirectTransferQuota(update, directTransfer, initialQuotas, quotas, maxEnabledTokens, collateralTokens) {
89
+ if (!directTransfer) return update;
90
+ const token = directTransfer.toLowerCase();
91
+ const quota = quotas.get(token);
92
+ const initial = initialQuotas.find((q) => q.token.toLowerCase() === token)?.quota ?? 0n;
93
+ const change = require_onchain_accounts_quota_utils.DIRECT_TRANSFERS_QUOTA - initial;
94
+ if (!collateralTokens.some((t) => t.toLowerCase() === token) || !quota?.isActive || quota.limit - quota.totalQuoted < change || (update.desiredQuota[token]?.balance ?? initial) >= require_onchain_accounts_quota_utils.DIRECT_TRANSFERS_QUOTA || Object.keys(quotasAfterUpdate(initialQuotas, update.desiredQuota)).length >= maxEnabledTokens) return update;
95
+ const rest = (list) => list.filter((a) => a.token !== token);
96
+ const entry = {
97
+ token,
98
+ balance: change
99
+ };
100
+ return {
101
+ desiredQuota: {
102
+ ...update.desiredQuota,
103
+ [token]: {
104
+ token,
105
+ balance: require_onchain_accounts_quota_utils.DIRECT_TRANSFERS_QUOTA
106
+ }
107
+ },
108
+ quotaIncrease: change > 0n ? [...rest(update.quotaIncrease), entry] : rest(update.quotaIncrease),
109
+ quotaDecrease: change < 0n ? [...rest(update.quotaDecrease), entry] : rest(update.quotaDecrease)
110
+ };
111
+ }
112
+ /**
82
113
  * The quotas the account stands at once an update lands: the ones it came with,
83
114
  * with the ones the update names written over them.
84
115
  *
@@ -166,7 +197,45 @@ function constructAssetRecord(a) {
166
197
  return acc;
167
198
  }, {});
168
199
  }
200
+ /** Largest additional underlying amount whose purchase fits this token's quota. */
201
+ function quotaIncreaseLimit({ suite, token, balance, initialQuotas, quotaReserve = 0, rwaAsset }) {
202
+ const { market } = suite;
203
+ if (market.isUnderlyingLike(token)) return { value: void 0 };
204
+ const oracle = market.priceOracle;
205
+ const purchaseResult = oracle.safeConvert(market.pool.underlying, token, require_onchain_constants_math.MAX_UINT256);
206
+ if (purchaseResult.error) return purchaseResult;
207
+ const valuationResult = oracle.safeConvert(token, market.pool.underlying, require_onchain_constants_math.MAX_UINT256);
208
+ if (valuationResult.error) return valuationResult;
209
+ if (purchaseResult.value === 0n || valuationResult.value === 0n) return { value: void 0 };
210
+ const maxQuotaValue = require_onchain_accounts_quota_utils.maxAmountForQuota({
211
+ available: market.pool.pqk.quotaAvailable(token),
212
+ initialQuota: initialQuotas.find((q) => q.token.toLowerCase() === token.toLowerCase())?.quota ?? 0n,
213
+ totalInitialQuota: initialQuotas.reduce((sum, q) => sum + require_onchain_accounts_quota_utils.roundUpQuota(q.quota), 0n),
214
+ maxDebt: suite.creditFacade.maxDebt,
215
+ lt: BigInt(suite.creditManager.liquidationThresholds.get(token) ?? 0),
216
+ quotaReserve: BigInt(quotaReserve)
217
+ });
218
+ if (maxQuotaValue === void 0) return { value: void 0 };
219
+ const quotaBalanceResult = oracle.safeConvert(market.pool.underlying, token, maxQuotaValue);
220
+ if (quotaBalanceResult.error) return quotaBalanceResult;
221
+ const quotaValueResult = oracle.safeConvert(token, market.pool.underlying, quotaBalanceResult.value);
222
+ if (quotaValueResult.error) return quotaValueResult;
223
+ const availableTokenIncrease = quotaBalanceResult.value - (quotaValueResult.value > maxQuotaValue ? 1n : 0n) - balance;
224
+ const excessTokenIncrease = require_onchain_utils_bigint_math.BigIntMath.max(availableTokenIncrease, 0n) + 1n;
225
+ if (rwaAsset?.toLowerCase() === token.toLowerCase()) {
226
+ const underlyingScale = 10n ** BigInt(suite.sdk.tokensMeta.decimals(market.pool.underlying));
227
+ const tokenScale = 10n ** BigInt(suite.sdk.tokensMeta.decimals(token));
228
+ return { value: require_onchain_utils_bigint_math.BigIntMath.ceilDiv(excessTokenIncrease * underlyingScale, tokenScale) - 1n };
229
+ }
230
+ const increaseResult = oracle.safeConvert(token, market.pool.underlying, excessTokenIncrease - 1n);
231
+ if (increaseResult.error) return increaseResult;
232
+ const purchaseValue = oracle.safeConvert(market.pool.underlying, token, increaseResult.value);
233
+ if (purchaseValue.error) return purchaseValue;
234
+ return { value: increaseResult.value - (purchaseValue.value >= excessTokenIncrease ? 1n : 0n) };
235
+ }
169
236
  //#endregion
170
237
  exports.clearedQuotas = clearedQuotas;
171
238
  exports.getQuotasForUpdate = getQuotasForUpdate;
239
+ exports.quotaIncreaseLimit = quotaIncreaseLimit;
172
240
  exports.quotasAfterUpdate = quotasAfterUpdate;
241
+ exports.withDirectTransferQuota = withDirectTransferQuota;
@@ -3,6 +3,11 @@ const require_onchain_utils_bigint_math = require("../utils/bigint-math.js");
3
3
  const require_onchain_constants_math = require("../constants/math.js");
4
4
  //#region src/onchain/accounts/quota-utils.ts
5
5
  /**
6
+ * Quota that keeps a directly transferred token enabled, so a liquidation
7
+ * counts it.
8
+ */
9
+ const DIRECT_TRANSFERS_QUOTA = require_onchain_constants_math.PERCENTAGE_FACTOR;
10
+ /**
6
11
  * Rounds quota deltas to protocol precision step (`PERCENTAGE_FACTOR`).
7
12
  *
8
13
  * The `MIN_INT96` sentinel is preserved as-is because it encodes
@@ -38,6 +43,14 @@ function calcRecommendedQuota({ amount, debt, lt, quotaReserve }) {
38
43
  function calcDefaultQuota({ amount, lt, quotaReserve }) {
39
44
  return roundUpQuota(amount * lt / require_onchain_constants_math.PERCENTAGE_FACTOR * (require_onchain_constants_math.PERCENTAGE_FACTOR + quotaReserve) / require_onchain_constants_math.PERCENTAGE_FACTOR);
40
45
  }
46
+ /** Inverse of default quota rounding, including the account-wide increase cap. */
47
+ function maxAmountForQuota({ available, initialQuota, totalInitialQuota, maxDebt, lt, quotaReserve }) {
48
+ const increaseCap = roundUpQuota(require_onchain_utils_bigint_math.BigIntMath.max(roundUpQuota(maxDebt * 2n) - totalInitialQuota, 0n));
49
+ if (lt === 0n || increaseCap <= available) return void 0;
50
+ const desired = roundUpQuota(initialQuota) + roundUpQuota(available) + require_onchain_constants_math.PERCENTAGE_FACTOR - 1n;
51
+ const base = require_onchain_utils_bigint_math.BigIntMath.ceilDiv((desired + 1n) * require_onchain_constants_math.PERCENTAGE_FACTOR, require_onchain_constants_math.PERCENTAGE_FACTOR + quotaReserve) - 1n;
52
+ return require_onchain_utils_bigint_math.BigIntMath.ceilDiv((base + 1n) * require_onchain_constants_math.PERCENTAGE_FACTOR, lt) - 1n;
53
+ }
41
54
  /**
42
55
  * Produces desired quota state and explicit increase/decrease actions.
43
56
  *
@@ -138,7 +151,9 @@ function getSingleQuotaChange(token, unsafeMaxQuotaIncrease, props) {
138
151
  };
139
152
  }
140
153
  //#endregion
154
+ exports.DIRECT_TRANSFERS_QUOTA = DIRECT_TRANSFERS_QUOTA;
141
155
  exports.calcDefaultQuota = calcDefaultQuota;
142
156
  exports.calcQuotaUpdate = calcQuotaUpdate;
143
157
  exports.calcRecommendedQuota = calcRecommendedQuota;
158
+ exports.maxAmountForQuota = maxAmountForQuota;
144
159
  exports.roundUpQuota = roundUpQuota;
@@ -78,6 +78,7 @@ const chains = {
78
78
  "0x238a700eD6165261Cf8b2e544ba797BC11e466Ba",
79
79
  "0x7433806912Eae67919e66aea853d46Fa0aef98A8"
80
80
  ]),
81
+ directTransfers: require_onchain_utils_AddressMap.AddressMap.fromRecord({ "0x7433806912Eae67919e66aea853d46Fa0aef98A8": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" }),
81
82
  legacyStrategyTargets: require_onchain_utils_AddressMap.AddressMap.fromRecord({
82
83
  "0x1293a69e4ad4a93293a06b6303104be35bdd83af": "0x1a711a5bc48b5c1352c1882fa65dc14b5b9e829d",
83
84
  "0x29350a3c2627fb78c7e915cd59af754edf8998c5": "0xe1d9b789da5b5375eacf66f036022b019a2af307",
@@ -545,6 +546,16 @@ function isSunsetStrategy(creditManager, network) {
545
546
  return !!chains[network].sunsetStrategies?.has(creditManager);
546
547
  }
547
548
  /**
549
+ * Token a collateral's sale later transfers directly to the credit account,
550
+ * or `undefined` when the collateral is not in the table.
551
+ *
552
+ * @param collateral - Collateral token address.
553
+ * @param network - Chain id or {@link NetworkType} label.
554
+ **/
555
+ function getDirectTransferToken(collateral, network) {
556
+ return getChain(network).directTransfers?.get(collateral);
557
+ }
558
+ /**
548
559
  * Hardcoded target collateral of a legacy credit manager, or `undefined` when
549
560
  * the manager is not in the table and the on-chain rule should apply.
550
561
  *
@@ -574,6 +585,7 @@ exports.getAccountTargetCollateral = getAccountTargetCollateral;
574
585
  exports.getAssetType = getAssetType;
575
586
  exports.getChain = getChain;
576
587
  exports.getCuratorName = getCuratorName;
588
+ exports.getDirectTransferToken = getDirectTransferToken;
577
589
  exports.getLegacyStrategyTarget = getLegacyStrategyTarget;
578
590
  exports.getNetworkType = getNetworkType;
579
591
  exports.isPublicNetwork = isPublicNetwork;
@@ -10,6 +10,7 @@ exports.getAccountTargetCollateral = require_onchain_chain_chains.getAccountTarg
10
10
  exports.getAssetType = require_onchain_chain_chains.getAssetType;
11
11
  exports.getChain = require_onchain_chain_chains.getChain;
12
12
  exports.getCuratorName = require_onchain_chain_chains.getCuratorName;
13
+ exports.getDirectTransferToken = require_onchain_chain_chains.getDirectTransferToken;
13
14
  exports.getLegacyStrategyTarget = require_onchain_chain_chains.getLegacyStrategyTarget;
14
15
  exports.getNetworkType = require_onchain_chain_chains.getNetworkType;
15
16
  exports.isPublicNetwork = require_onchain_chain_chains.isPublicNetwork;
@@ -396,6 +396,7 @@ exports.DEGEN_NFT_MIDAS = require_onchain_market_rwa_midas_constants.DEGEN_NFT_M
396
396
  exports.DEGEN_NFT_SECURITIZE = require_onchain_market_rwa_securitize_constants.DEGEN_NFT_SECURITIZE;
397
397
  exports.DELAYED_INTENT_TYPES = require_onchain_accounts_withdrawal_compressor_intent_codec.DELAYED_INTENT_TYPES;
398
398
  exports.DELAYED_INTENT_VERSION = require_onchain_accounts_withdrawal_compressor_intent_codec.DELAYED_INTENT_VERSION;
399
+ exports.DIRECT_TRANSFERS_QUOTA = require_onchain_accounts_quota_utils.DIRECT_TRANSFERS_QUOTA;
399
400
  exports.DUST_THRESHOLD = require_onchain_constants_math.DUST_THRESHOLD;
400
401
  exports.DaiUsdsAdapterContract = require_onchain_market_adapters_contracts_DaiUsdsAdapterContract.DaiUsdsAdapterContract;
401
402
  exports.ERC4626AdapterContract = require_onchain_market_adapters_contracts_ERC4626AdapterContract.ERC4626AdapterContract;
@@ -661,6 +662,7 @@ exports.getAssetType = require_onchain_chain_chains.getAssetType;
661
662
  exports.getCastTraceArgs = require_onchain_utils_viem_cast.getCastTraceArgs;
662
663
  exports.getChain = require_onchain_chain_chains.getChain;
663
664
  exports.getCuratorName = require_onchain_chain_chains.getCuratorName;
665
+ exports.getDirectTransferToken = require_onchain_chain_chains.getDirectTransferToken;
664
666
  exports.getFunctionSignature = require_onchain_utils_abi_decode.getFunctionSignature;
665
667
  exports.getLegacyStrategyTarget = require_onchain_chain_chains.getLegacyStrategyTarget;
666
668
  exports.getNetworkType = require_onchain_chain_chains.getNetworkType;
@@ -764,6 +766,7 @@ exports.json_parse = require_onchain_utils_json.json_parse;
764
766
  exports.json_stringify = require_onchain_utils_json.json_stringify;
765
767
  exports.lidoV1_WETHGatewayAbi = require_onchain_market_adapters_abi_targetContractAbi.lidoV1_WETHGatewayAbi;
766
768
  exports.makeReplayState = require_onchain_preview_preview_replayInnerOperations.makeReplayState;
769
+ exports.maxAmountForQuota = require_onchain_accounts_quota_utils.maxAmountForQuota;
767
770
  exports.mellowDvvAdapterAbi = require_onchain_market_adapters_abi_adapters_mellowDvvAdapter.mellowDvvAdapterAbi;
768
771
  exports.midasGreenlistsAccount = require_onchain_preview_preview_midasGreenlistsAccount.midasGreenlistsAccount;
769
772
  exports.minSeizedAmount = require_onchain_market_math.minSeizedAmount;
@@ -113,6 +113,9 @@ var PriceOracleBaseContract = class extends require_onchain_base_BaseContract.Ba
113
113
  * {@inheritDoc IPriceOracleContract.convert}
114
114
  **/
115
115
  convert(from, to, amount, reserve = false) {
116
+ return this.#convert(from, to, amount, reserve, false);
117
+ }
118
+ #convert(from, to, amount, reserve, roundUp) {
116
119
  if ((0, viem.isAddressEqual)(from, to)) return amount;
117
120
  const fromToken = this.#priceableToken(from);
118
121
  const toToken = this.#priceableToken(to);
@@ -120,7 +123,9 @@ var PriceOracleBaseContract = class extends require_onchain_base_BaseContract.Ba
120
123
  const fromScale = 10n ** BigInt(this.tokensMeta.decimals(fromToken));
121
124
  const toPrice = reserve ? this.reservePrice(toToken) : this.mainPrice(toToken);
122
125
  const toScale = 10n ** BigInt(this.tokensMeta.decimals(toToken));
123
- return amount * fromPrice * toScale / (toPrice * fromScale);
126
+ const numerator = amount * fromPrice * toScale;
127
+ const denominator = toPrice * fromScale;
128
+ return roundUp ? require_onchain_utils_bigint_math.BigIntMath.ceilDiv(numerator, denominator) : numerator / denominator;
124
129
  }
125
130
  /**
126
131
  * {@inheritDoc IPriceOracleContract.convertToUSD}
@@ -141,15 +146,12 @@ var PriceOracleBaseContract = class extends require_onchain_base_BaseContract.Ba
141
146
  const price = reserve ? this.reservePrice(token) : this.mainPrice(token);
142
147
  return amount * 10n ** BigInt(this.tokensMeta.decimals(token)) / price;
143
148
  }
144
- /**
145
- * {@inheritDoc IPriceOracleContract.safeConvert}
146
- **/
147
149
  safeConvert(from, to, amount) {
148
150
  try {
149
- return { value: this.convert(from, to, amount) };
151
+ return { value: this.#convert(from, to, amount, false, true) };
150
152
  } catch {
151
153
  try {
152
- return { value: this.convert(from, to, amount, true) };
154
+ return { value: this.#convert(from, to, amount, true, true) };
153
155
  } catch {
154
156
  return require_model_result.safeValue(0n, require_model_errors_oracle_errors.unpriceableTokenError(from));
155
157
  }
@@ -12,13 +12,12 @@ require("../helpers/index.js");
12
12
  * takeable, left out when none is.
13
13
  */
14
14
  function checkBorrowLimit(args) {
15
- const { requested, available, limit, underlying, maxBorrowAmount } = args;
15
+ const { requested, available, underlying, maxBorrowAmount, ...rest } = args;
16
16
  if (requested <= available) return [];
17
17
  return [require_model_errors_operation_errors.insufficientPoolLiquidity({
18
- collateralLimits: args.getCollateralLimits?.(),
18
+ ...rest,
19
19
  requested: require_onchain_validation_helpers_amount.amountOf(underlying, requested),
20
20
  available: require_onchain_validation_helpers_amount.amountOf(underlying, available),
21
- limit,
22
21
  ...maxBorrowAmount === void 0 ? {} : { maxBorrowAmount: require_onchain_validation_helpers_amount.amountOf(underlying, maxBorrowAmount) }
23
22
  })];
24
23
  }
@@ -6,14 +6,13 @@ require("../helpers/index.js");
6
6
  //#region src/onchain/validation/checks/checkDebtLimits.ts
7
7
  /** A debt the facade would revert on. */
8
8
  function checkDebtLimits(args) {
9
- const { debt, minDebt, maxDebt, underlying, allowZero, maxBorrowAmount } = args;
9
+ const { debt, minDebt, maxDebt, underlying, allowZero, ...rest } = args;
10
10
  if (!(debt > maxDebt || debt < minDebt && !(allowZero && debt === 0n))) return [];
11
11
  return [require_model_errors_operation_errors.debtOutOfRange({
12
- collateralLimits: args.getCollateralLimits?.(),
12
+ ...rest,
13
13
  requested: require_onchain_validation_helpers_amount.amountOf(underlying, debt),
14
14
  minDebt: require_onchain_validation_helpers_amount.amountOf(underlying, minDebt),
15
- maxDebt: require_onchain_validation_helpers_amount.amountOf(underlying, maxDebt),
16
- maxBorrowAmount
15
+ maxDebt: require_onchain_validation_helpers_amount.amountOf(underlying, maxDebt)
17
16
  })];
18
17
  }
19
18
  //#endregion
@@ -6,9 +6,10 @@ require("../helpers/index.js");
6
6
  //#region src/onchain/validation/checks/checkQuotaLimit.ts
7
7
  /** The room the keeper still has for a token's quota, in the underlying. */
8
8
  function checkQuotaLimit(args) {
9
- const { token, requested, available, underlying } = args;
9
+ const { token, requested, available, underlying, ...rest } = args;
10
10
  if (requested !== void 0 && requested <= available) return [];
11
11
  return [require_model_errors_operation_errors.quotaLimitReached({
12
+ ...rest,
12
13
  token,
13
14
  requested: requested === void 0 ? void 0 : require_onchain_validation_helpers_amount.amountOf(underlying, requested),
14
15
  available: require_onchain_validation_helpers_amount.amountOf(underlying, available)
@@ -1,5 +1,5 @@
1
- import { iCreditFacadeV310Abi } from "../abi/310/generated.js";
2
1
  import { ierc20Abi } from "../abi/iERC20.js";
2
+ import { iCreditFacadeV310Abi } from "../abi/310/generated.js";
3
3
  import { AddressMap } from "../onchain/utils/AddressMap.js";
4
4
  import { AddressSet } from "../onchain/utils/AddressSet.js";
5
5
  import { AssetsMap } from "../onchain/utils/AssetsMap.js";
@@ -8,6 +8,7 @@ import "../onchain/constants/addresses.js";
8
8
  import { MAX_UINT256, PERCENTAGE_FACTOR } from "../onchain/constants/math.js";
9
9
  import { SDKConstruct } from "../onchain/base/SDKConstruct.js";
10
10
  import { sendRawTx } from "../onchain/utils/viem/sendRawTx.js";
11
+ import { DIRECT_TRANSFERS_QUOTA } from "../onchain/accounts/quota-utils.js";
11
12
  import { PoolService } from "../onchain/pools/PoolService.js";
12
13
  import "../onchain/index.js";
13
14
  import { iDegenNftv2Abi } from "./abi.js";
@@ -18,7 +19,6 @@ import "./mint/index.js";
18
19
  import { BaseError, erc20Abi, isAddress, parseEther, parseEventLogs } from "viem";
19
20
  import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
20
21
  //#region src/dev/AccountOpener.ts
21
- const DIRECT_TRANSFERS_QUOTA = 10000n;
22
22
  var OpenTxRevertedError = class extends BaseError {
23
23
  txHash;
24
24
  constructor(txHash) {
@@ -1,6 +1,6 @@
1
+ import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
1
2
  import { getNetworkType } from "../onchain/chain/chains.js";
2
3
  import { getWithdrawalCompressorAddress } from "../onchain/accounts/withdrawal-compressor/addresses.js";
3
- import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
4
4
  import "../onchain/index.js";
5
5
  import { iMidasDataFeedAbi, iMidasRedemptionVaultAbi, midasGatewayAbi, midasRedeemerAbi, midasRedemptionVaultPhantomTokenAbi, securitizeRedeemerAbi, securitizeRedemptionGatewayAbi, securitizeRedemptionPhantomTokenAbi } from "./withdrawalAbi.js";
6
6
  import { erc20Abi, hexToString, parseAbi, parseEther } from "viem";
@@ -1,5 +1,5 @@
1
- import { iCreditFacadeV310Abi } from "../../abi/310/generated.js";
2
1
  import { ierc20Abi } from "../../abi/iERC20.js";
2
+ import { iCreditFacadeV310Abi } from "../../abi/310/generated.js";
3
3
  import { AddressMap } from "../../onchain/utils/AddressMap.js";
4
4
  import "../../onchain/index.js";
5
5
  import { UnexpectedFacadeEventOrderError } from "./errors.js";
@@ -1,3 +1,5 @@
1
+ import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
2
+ import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
1
3
  import { AP_REWARDS_COMPRESSOR } from "../constants/address-provider.js";
2
4
  import { ADDRESS_0X0 } from "../constants/addresses.js";
3
5
  import { MAX_UINT256 } from "../constants/math.js";
@@ -8,8 +10,6 @@ import "../base/index.js";
8
10
  import { AccountBotsService } from "./bots/AccountBotsService.js";
9
11
  import "./bots/index.js";
10
12
  import { rewardsCompressorAbi } from "../../abi/compressors/rewardsCompressor.js";
11
- import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
12
- import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
13
13
  import { expectedBalanceDeltas } from "../market/credit/expectedBalanceDeltas.js";
14
14
  import "../market/index.js";
15
15
  import { CreditAccountCompressor } from "./credit-account-compressor/CreditAccountCompressor.js";
@@ -7,7 +7,7 @@ import "./credit-account-compressor/index.js";
7
7
  import { CreditAccountsServiceV310 } from "./CreditAccountsServiceV310.js";
8
8
  import { isPhantomToken } from "./intents/utils/pick-token.js";
9
9
  import { fetchCreditAccountSlice, toCreditAccountSlice } from "./intents/utils/credit-account-slice.js";
10
- import { calcDefaultQuota, calcQuotaUpdate, calcRecommendedQuota, roundUpQuota } from "./quota-utils.js";
10
+ import { DIRECT_TRANSFERS_QUOTA, calcDefaultQuota, calcQuotaUpdate, calcRecommendedQuota, maxAmountForQuota, roundUpQuota } from "./quota-utils.js";
11
11
  import { CreditAccountOperationsService } from "./intents/index.js";
12
12
  import { LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS } from "./liquidations/constants.js";
13
13
  import { LiquidationsService } from "./liquidations/LiquidationsService.js";
@@ -25,4 +25,4 @@ import { toWithdrawalStatus } from "./withdrawal-compressor/types.js";
25
25
  import { WithdrawalCompressorV313Contract } from "./withdrawal-compressor/WithdrawalCompressorV313Contract.js";
26
26
  import { createWithdrawalCompressor } from "./withdrawal-compressor/createWithdrawalCompressor.js";
27
27
  import "./withdrawal-compressor/index.js";
28
- export { AbstractWithdrawalCompressorContract, AccountBotsService, CreditAccountCompressor, CreditAccountCompressorV310Contract, CreditAccountOperationsService, CreditAccountsServiceV310, DELAYED_INTENT_TYPES, DELAYED_INTENT_VERSION, LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS, LiquidationsService, MultichainLiquidationsService, PeripheryCompressorV310Contract, RedemptionLoggerV310Contract, WithdrawalCompressorV310Contract, WithdrawalCompressorV311Contract, WithdrawalCompressorV313Contract, calcDefaultQuota, calcQuotaUpdate, calcRecommendedQuota, createRedemptionLogger, createWithdrawalCompressor, decodeDelayedIntent, encodeDelayedIntent, fetchCreditAccountSlice, getWithdrawalCompressorAddress, iCreditAccountAbi, isPhantomToken, roundUpQuota, toClaimableWithdrawal, toCreditAccountSlice, toPendingWithdrawal, toRequestableWithdrawal, toWithdrawalStatus };
28
+ export { AbstractWithdrawalCompressorContract, AccountBotsService, CreditAccountCompressor, CreditAccountCompressorV310Contract, CreditAccountOperationsService, CreditAccountsServiceV310, DELAYED_INTENT_TYPES, DELAYED_INTENT_VERSION, DIRECT_TRANSFERS_QUOTA, LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS, LiquidationsService, MultichainLiquidationsService, PeripheryCompressorV310Contract, RedemptionLoggerV310Contract, WithdrawalCompressorV310Contract, WithdrawalCompressorV311Contract, WithdrawalCompressorV313Contract, calcDefaultQuota, calcQuotaUpdate, calcRecommendedQuota, createRedemptionLogger, createWithdrawalCompressor, decodeDelayedIntent, encodeDelayedIntent, fetchCreditAccountSlice, getWithdrawalCompressorAddress, iCreditAccountAbi, isPhantomToken, maxAmountForQuota, roundUpQuota, toClaimableWithdrawal, toCreditAccountSlice, toPendingWithdrawal, toRequestableWithdrawal, toWithdrawalStatus };
@@ -52,7 +52,7 @@ function assertCanBorrow(sdk, suite, amount, options = {}) {
52
52
  available: maxBorrowAmount.amount.value,
53
53
  limit: maxBorrowAmount.limit,
54
54
  underlying: toToken(sdk, suite.market.pool.underlying),
55
- getCollateralLimits: options.getCollateralLimits
55
+ ...options
56
56
  }), `borrow: ${amount} exceeds what the pool can lend now (${maxBorrowAmount.amount.value})`);
57
57
  }
58
58
  /**
@@ -81,6 +81,7 @@ function assertGrowthAllowed(args) {
81
81
  token: toToken(sdk, token),
82
82
  requested: void 0,
83
83
  available: 0n,
84
+ ...args.limits,
84
85
  underlying: toToken(sdk, underlying)
85
86
  }), `${token} takes no quota in this market, so it counts as no collateral`);
86
87
  }
@@ -138,7 +139,7 @@ function assertCollateralised(healthFactorBps, safePrices, atSafePrices) {
138
139
  * A quota can only be raised as far as the market still has room for: past the
139
140
  * token's limit the keeper takes nothing more, whoever is asking.
140
141
  */
141
- function assertQuotaAvailable(sdk, market, increases) {
142
+ function assertQuotaAvailable(sdk, market, increases, options = {}) {
142
143
  const underlying = market.pool.underlying;
143
144
  const { pqk } = market.pool;
144
145
  for (const { token, balance } of increases) {
@@ -148,6 +149,7 @@ function assertQuotaAvailable(sdk, market, increases) {
148
149
  token: toToken(sdk, token),
149
150
  requested: balance,
150
151
  available: left,
152
+ ...options,
151
153
  underlying: toToken(sdk, underlying)
152
154
  }), `${token} has ${left} of quota left, the plan needs ${balance}`);
153
155
  }
@@ -1,3 +1,4 @@
1
+ import { LEVERAGE_DECIMALS } from "../../constants/math.js";
1
2
  import { SDKConstruct } from "../../base/SDKConstruct.js";
2
3
  import { unsupportedTokenPair } from "../../../model/errors/prepare-errors.js";
3
4
  import { sdkErr } from "../../../model/result.js";
@@ -12,6 +13,7 @@ import { buildBorrowState } from "./borrow.js";
12
13
  import { calcLeverageBand } from "./leverage-band.js";
13
14
  import { maxBorrow } from "./maxBorrow.js";
14
15
  import { maxWithdrawCollateral } from "./maxWithdrawCollateral.js";
16
+ import { strategyLimits } from "./strategyLimits.js";
15
17
  import { buildOpenStrategyState } from "./open-strategy.js";
16
18
  import { planAddCollateral, planAdjustLeverage, planAdjustLeverageDelayed, planDeposit, planRepay, planWithdraw, planWithdrawAsset, planWithdrawDelayed } from "./plan.js";
17
19
  import { accountView } from "./view.js";
@@ -36,9 +38,25 @@ var CreditAccountOperationsService = class extends SDKConstruct {
36
38
  * balance)
37
39
  */
38
40
  async startIntent(props) {
41
+ const { intent, sdk, creditAccount, quotaReserve } = props;
42
+ let current;
43
+ let limits = {};
44
+ if (intent.type === "DEPOSIT" || intent.type === "ADJUST_LEVERAGE") {
45
+ current = accountView(creditAccount, sdk);
46
+ limits = strategyLimits({
47
+ ...intent,
48
+ suite: sdk.marketRegister.findCreditManager(creditAccount.creditManager),
49
+ view: current,
50
+ initialQuotas: creditAccount.tokens,
51
+ quotaReserve
52
+ });
53
+ }
39
54
  return plain(await this.#preview(props, () => {
40
55
  const { intent } = props;
41
- const view = accountView(props.creditAccount, props.sdk);
56
+ const view = {
57
+ ...current ?? accountView(props.creditAccount, props.sdk),
58
+ limits
59
+ };
42
60
  switch (intent.type) {
43
61
  case "ADD_COLLATERAL": return planAddCollateral(intent);
44
62
  case "WITHDRAW_ASSET": return planWithdrawAsset(intent, view);
@@ -48,7 +66,7 @@ var CreditAccountOperationsService = class extends SDKConstruct {
48
66
  case "WITHDRAW": return planWithdraw(intent, view);
49
67
  default: throw new Error(`${intent.type} - not implemented`);
50
68
  }
51
- }));
69
+ }, limits));
52
70
  }
53
71
  /**
54
72
  * Both ends of what a `WITHDRAW` can take out, in underlying: the largest
@@ -190,14 +208,28 @@ var CreditAccountOperationsService = class extends SDKConstruct {
190
208
  */
191
209
  async startDelayedIntent(props) {
192
210
  const { intent } = props;
211
+ const current = accountView(props.creditAccount, props.sdk);
212
+ const repayFromSource = current.debt - current.balanceOf(current.underlying);
213
+ const maximum = intent.type === "ADJUST_LEVERAGE" && current.collateral > 0n && repayFromSource > 0n ? LEVERAGE_DECIMALS + (repayFromSource * LEVERAGE_DECIMALS - 1n) / current.collateral : void 0;
214
+ const limits = intent.type === "ADJUST_LEVERAGE" && maximum !== void 0 ? strategyLimits({
215
+ ...intent,
216
+ suite: props.sdk.marketRegister.findCreditManager(props.creditAccount.creditManager),
217
+ view: current,
218
+ initialQuotas: props.creditAccount.tokens,
219
+ quotaReserve: props.quotaReserve,
220
+ maxLeverage: maximum
221
+ }) : {};
193
222
  const result = await this.#preview(props, () => {
194
- const view = accountView(props.creditAccount, props.sdk);
223
+ const view = {
224
+ ...current,
225
+ limits
226
+ };
195
227
  switch (intent.type) {
196
228
  case "ADJUST_LEVERAGE": return planAdjustLeverageDelayed(intent, view);
197
229
  case "WITHDRAW": return planWithdrawDelayed(intent, view);
198
230
  default: throw new Error(`${intent.type} - cannot be delayed`);
199
231
  }
200
- });
232
+ }, limits);
201
233
  if (!result.ok) return result;
202
234
  const { delayed } = result;
203
235
  if (!delayed) throw new Error("startDelayedIntent: plan started no withdrawal");
@@ -213,7 +245,8 @@ var CreditAccountOperationsService = class extends SDKConstruct {
213
245
  delayed,
214
246
  creditAccount: props.creditAccount,
215
247
  sdk: props.sdk,
216
- quotaReserve: props.quotaReserve
248
+ quotaReserve: props.quotaReserve,
249
+ limits
217
250
  });
218
251
  return {
219
252
  ...result,
@@ -399,7 +432,7 @@ var CreditAccountOperationsService = class extends SDKConstruct {
399
432
  }
400
433
  }
401
434
  /** Plan → realise → wrap. Unviable requests become `{ ok: false }`. */
402
- async #preview(props, plan) {
435
+ async #preview(props, plan, limits = {}) {
403
436
  const draft = props.draft ?? {};
404
437
  try {
405
438
  const suite = props.sdk.marketRegister.findCreditManager(props.creditAccount.creditManager);
@@ -410,7 +443,8 @@ var CreditAccountOperationsService = class extends SDKConstruct {
410
443
  sdk: props.sdk,
411
444
  slippage: props.slippage ?? 0,
412
445
  quotaReserve: props.quotaReserve,
413
- draft
446
+ draft,
447
+ limits
414
448
  });
415
449
  return {
416
450
  ok: true,
@@ -1,6 +1,5 @@
1
1
  import { BigIntMath } from "../../utils/bigint-math.js";
2
- import { LEVERAGE_DECIMALS, MAX_UINT256, PERCENTAGE_FACTOR } from "../../constants/math.js";
3
- import "../../constants/index.js";
2
+ import { LEVERAGE_DECIMALS, PERCENTAGE_FACTOR } from "../../constants/math.js";
4
3
  import { insufficientBalance } from "../../../model/errors/operation-errors.js";
5
4
  import "../../../model/index.js";
6
5
  import { toToken } from "../../validation/helpers/token.js";
@@ -58,53 +57,14 @@ function assertLeverageAtLeastOne(leverage) {
58
57
  * may end owing nothing, an opening may not.
59
58
  */
60
59
  function assertDebtLimits(sdk, debt, debtLimits, underlying, options = {}) {
61
- const { allowZero = true, getCollateralLimits, maxBorrowAmount } = options;
60
+ const { allowZero = true, ...rest } = options;
62
61
  raise(checkDebtLimits({
63
62
  debt,
64
- minDebt: debtLimits.minDebt,
65
- maxDebt: debtLimits.maxDebt,
63
+ ...debtLimits,
66
64
  underlying: toToken(sdk, underlying),
67
65
  allowZero,
68
- getCollateralLimits,
69
- maxBorrowAmount
66
+ ...rest
70
67
  }), debt > debtLimits.maxDebt ? `debt ${debt} exceeds maxDebt ${debtLimits.maxDebt}` : `debt ${debt} is below minDebt ${debtLimits.minDebt}`);
71
68
  }
72
- /** Finds single-token Open amounts whose projected debt fits the market limits. */
73
- function openCollateralForDebtLimits({ suite, collateral, leverage }) {
74
- if (collateral.length !== 1 || leverage <= 100n) return void 0;
75
- const [{ token }] = collateral;
76
- const { market } = suite;
77
- const limits = {
78
- minDebt: suite.creditFacade.minDebt,
79
- maxDebt: suite.maxBorrowAmount().amount.value
80
- };
81
- if (limits.maxDebt < limits.minDebt) return void 0;
82
- const debtAt = (amount) => {
83
- const converted = market.priceOracle.safeConvert(token, market.pool.underlying, amount);
84
- return converted.error ? void 0 : debtForLeverage(converted.value, leverage);
85
- };
86
- const lastDebt = debtAt(MAX_UINT256);
87
- if (lastDebt === void 0 || lastDebt < limits.minDebt) return void 0;
88
- const firstAtLeast = (threshold) => {
89
- let low = 0n;
90
- let high = MAX_UINT256;
91
- while (low < high) {
92
- const middle = (low + high) / 2n;
93
- const debt = debtAt(middle);
94
- if (debt === void 0) return void 0;
95
- if (debt < threshold) low = middle + 1n;
96
- else high = middle;
97
- }
98
- return low;
99
- };
100
- const min = firstAtLeast(limits.minDebt > 0n ? limits.minDebt : 1n);
101
- const above = lastDebt > limits.maxDebt ? firstAtLeast(limits.maxDebt + 1n) : void 0;
102
- if (min === void 0 || lastDebt > limits.maxDebt && above === void 0) return void 0;
103
- const max = above === void 0 ? MAX_UINT256 : above - 1n;
104
- return min <= max ? {
105
- min: market.priceOracle.toTokenAmount(token, min),
106
- max: market.priceOracle.toTokenAmount(token, max)
107
- } : void 0;
108
- }
109
69
  //#endregion
110
- export { assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage, maxProportionalWithdrawal, openCollateralForDebtLimits, proportionalDebt };
70
+ export { assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage, maxProportionalWithdrawal, proportionalDebt };
@@ -85,7 +85,13 @@ function maxBorrow(props) {
85
85
  if (lends < suite.creditFacade.minDebt) return 0n;
86
86
  const ceiling = BigIntMath.min(priceOracle.safeConvertFromUSD(underlying, backed / targetHF).value, lends);
87
87
  const unwrapsPayout = !!rwaAsset && eq(borrowToken, rwaAsset);
88
- return eq(borrowToken, underlying) ? ceiling : unwrapsPayout ? toTargetDecimals(ceiling, underlying, borrowToken, sdk) : priceOracle.safeConvert(underlying, borrowToken, ceiling).value;
88
+ if (eq(borrowToken, underlying)) return ceiling;
89
+ if (unwrapsPayout) return toTargetDecimals(ceiling, underlying, borrowToken, sdk);
90
+ const payout = priceOracle.safeConvert(underlying, borrowToken, ceiling);
91
+ if (payout.error) return 0n;
92
+ const debt = priceOracle.safeConvert(borrowToken, underlying, payout.value);
93
+ if (debt.error) return 0n;
94
+ return BigIntMath.max(payout.value - (debt.value > ceiling ? 1n : 0n), 0n);
89
95
  }
90
96
  //#endregion
91
97
  export { maxBorrow };