@gearbox-protocol/sdk 17.10.0 → 17.10.1-next.2

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 (88) hide show
  1. package/dist/cjs/onchain/accounts/index.js +1 -0
  2. package/dist/cjs/onchain/accounts/intents/guards.js +4 -2
  3. package/dist/cjs/onchain/accounts/intents/index.js +44 -11
  4. package/dist/cjs/onchain/accounts/intents/leverage-band.js +49 -8
  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 +4 -3
  10. package/dist/cjs/onchain/accounts/intents/strategyLimits.js +159 -0
  11. package/dist/cjs/onchain/accounts/intents/tail.js +6 -2
  12. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +4 -0
  13. package/dist/cjs/onchain/accounts/intents/utils/index.js +1 -0
  14. package/dist/cjs/onchain/accounts/intents/utils/quotas-for-update.js +39 -0
  15. package/dist/cjs/onchain/accounts/intents/withdraw-limits.js +1 -1
  16. package/dist/cjs/onchain/accounts/quota-utils.js +9 -0
  17. package/dist/cjs/onchain/index.js +1 -0
  18. package/dist/cjs/onchain/market/oracle/PriceOracleBaseContract.js +8 -6
  19. package/dist/cjs/onchain/validation/checks/checkBorrowLimit.js +2 -3
  20. package/dist/cjs/onchain/validation/checks/checkDebtLimits.js +3 -4
  21. package/dist/cjs/onchain/validation/checks/checkQuotaLimit.js +2 -1
  22. package/dist/cjs/sdk/prepare/PrepareApi.js +3 -2
  23. package/dist/esm/dev/AccountOpener.js +1 -1
  24. package/dist/esm/dev/withdrawalUtils.js +1 -1
  25. package/dist/esm/history/trace/extractTransfers.js +1 -1
  26. package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +2 -2
  27. package/dist/esm/onchain/accounts/index.js +2 -2
  28. package/dist/esm/onchain/accounts/intents/guards.js +4 -2
  29. package/dist/esm/onchain/accounts/intents/index.js +44 -11
  30. package/dist/esm/onchain/accounts/intents/leverage-band.js +50 -9
  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 +4 -3
  36. package/dist/esm/onchain/accounts/intents/strategyLimits.js +158 -0
  37. package/dist/esm/onchain/accounts/intents/tail.js +6 -2
  38. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +4 -0
  39. package/dist/esm/onchain/accounts/intents/utils/index.js +2 -2
  40. package/dist/esm/onchain/accounts/intents/utils/quotas-for-update.js +41 -3
  41. package/dist/esm/onchain/accounts/intents/withdraw-limits.js +1 -1
  42. package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +1 -1
  43. package/dist/esm/onchain/accounts/quota-utils.js +9 -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/core/createAddressProvider.js +1 -1
  50. package/dist/esm/onchain/index.js +2 -2
  51. package/dist/esm/onchain/market/adapters/contracts/AccountMigratorAdapterContract.js +1 -1
  52. package/dist/esm/onchain/market/adapters/contracts/ERC4626AdapterContract.js +1 -1
  53. package/dist/esm/onchain/market/credit/CreditFacadeV310BaseContract.js +1 -1
  54. package/dist/esm/onchain/market/oracle/PriceOracleBaseContract.js +8 -6
  55. package/dist/esm/onchain/market/pool/PoolV310Contract.js +1 -1
  56. package/dist/esm/onchain/market/rwa/createDegenNFT.js +1 -1
  57. package/dist/esm/onchain/market/zapper/IETHZapperContract.js +1 -1
  58. package/dist/esm/onchain/market/zapper/ZapperContract.js +1 -1
  59. package/dist/esm/onchain/preview/preview/previewPoolPositionOperation.js +2 -2
  60. package/dist/esm/onchain/utils/viem/simulateWithPriceUpdates.js +1 -1
  61. package/dist/esm/onchain/validation/checks/checkBorrowLimit.js +2 -3
  62. package/dist/esm/onchain/validation/checks/checkDebtLimits.js +3 -4
  63. package/dist/esm/onchain/validation/checks/checkQuotaLimit.js +2 -1
  64. package/dist/esm/sdk/prepare/PrepareApi.js +3 -2
  65. package/dist/types/model/errors/index.d.ts +2 -2
  66. package/dist/types/model/errors/operation-errors.d.ts +28 -14
  67. package/dist/types/model/index.d.ts +2 -2
  68. package/dist/types/onchain/accounts/index.d.ts +2 -2
  69. package/dist/types/onchain/accounts/intents/guards.d.ts +12 -12
  70. package/dist/types/onchain/accounts/intents/index.d.ts +2 -3
  71. package/dist/types/onchain/accounts/intents/leverage-band.d.ts +8 -6
  72. package/dist/types/onchain/accounts/intents/math.d.ts +7 -16
  73. package/dist/types/onchain/accounts/intents/plan.d.ts +2 -0
  74. package/dist/types/onchain/accounts/intents/realize.d.ts +3 -0
  75. package/dist/types/onchain/accounts/intents/strategyLimits.d.ts +33 -0
  76. package/dist/types/onchain/accounts/intents/tail.d.ts +13 -9
  77. package/dist/types/onchain/accounts/intents/utils/index.d.ts +2 -2
  78. package/dist/types/onchain/accounts/intents/utils/quotas-for-update.d.ts +15 -1
  79. package/dist/types/onchain/accounts/quota-utils.d.ts +11 -1
  80. package/dist/types/onchain/index.d.ts +2 -2
  81. package/dist/types/onchain/market/oracle/PriceOracleBaseContract.d.ts +0 -3
  82. package/dist/types/onchain/market/oracle/types.d.ts +4 -3
  83. package/dist/types/onchain/validation/checks/checkBorrowLimit.d.ts +2 -3
  84. package/dist/types/onchain/validation/checks/checkDebtLimits.d.ts +2 -3
  85. package/dist/types/onchain/validation/checks/checkQuotaLimit.d.ts +2 -2
  86. package/dist/types/sdk/prepare/PrepareApi.d.ts +1 -1
  87. package/dist/types/sdk/prepare/types.d.ts +3 -4
  88. 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;
@@ -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 }) {
@@ -195,8 +197,45 @@ function constructAssetRecord(a) {
195
197
  return acc;
196
198
  }, {});
197
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
+ }
198
236
  //#endregion
199
237
  exports.clearedQuotas = clearedQuotas;
200
238
  exports.getQuotasForUpdate = getQuotasForUpdate;
239
+ exports.quotaIncreaseLimit = quotaIncreaseLimit;
201
240
  exports.quotasAfterUpdate = quotasAfterUpdate;
202
241
  exports.withDirectTransferQuota = withDirectTransferQuota;
@@ -5,8 +5,8 @@ require("../../validation/helpers/health-factor-limits.js");
5
5
  require("../../validation/index.js");
6
6
  const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
7
7
  const require_onchain_accounts_intents_math = require("./math.js");
8
- const require_onchain_accounts_intents_collateral_valuation = require("./collateral-valuation.js");
9
8
  const require_onchain_accounts_intents_view = require("./view.js");
9
+ const require_onchain_accounts_intents_collateral_valuation = require("./collateral-valuation.js");
10
10
  //#region src/onchain/accounts/intents/withdraw-limits.ts
11
11
  /**
12
12
  * Every limit a `WITHDRAW` answers to, in underlying units.
@@ -43,6 +43,14 @@ function calcRecommendedQuota({ amount, debt, lt, quotaReserve }) {
43
43
  function calcDefaultQuota({ amount, lt, quotaReserve }) {
44
44
  return roundUpQuota(amount * lt / require_onchain_constants_math.PERCENTAGE_FACTOR * (require_onchain_constants_math.PERCENTAGE_FACTOR + quotaReserve) / require_onchain_constants_math.PERCENTAGE_FACTOR);
45
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
+ }
46
54
  /**
47
55
  * Produces desired quota state and explicit increase/decrease actions.
48
56
  *
@@ -147,4 +155,5 @@ exports.DIRECT_TRANSFERS_QUOTA = DIRECT_TRANSFERS_QUOTA;
147
155
  exports.calcDefaultQuota = calcDefaultQuota;
148
156
  exports.calcQuotaUpdate = calcQuotaUpdate;
149
157
  exports.calcRecommendedQuota = calcRecommendedQuota;
158
+ exports.maxAmountForQuota = maxAmountForQuota;
150
159
  exports.roundUpQuota = roundUpQuota;
@@ -766,6 +766,7 @@ exports.json_parse = require_onchain_utils_json.json_parse;
766
766
  exports.json_stringify = require_onchain_utils_json.json_stringify;
767
767
  exports.lidoV1_WETHGatewayAbi = require_onchain_market_adapters_abi_targetContractAbi.lidoV1_WETHGatewayAbi;
768
768
  exports.makeReplayState = require_onchain_preview_preview_replayInnerOperations.makeReplayState;
769
+ exports.maxAmountForQuota = require_onchain_accounts_quota_utils.maxAmountForQuota;
769
770
  exports.mellowDvvAdapterAbi = require_onchain_market_adapters_abi_adapters_mellowDvvAdapter.mellowDvvAdapterAbi;
770
771
  exports.midasGreenlistsAccount = require_onchain_preview_preview_midasGreenlistsAccount.midasGreenlistsAccount;
771
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)
@@ -374,13 +374,14 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
374
374
  /**
375
375
  * {@inheritDoc IOpportunitiesPrepare.leverageBand}
376
376
  **/
377
- leverageBand(strategy, collateral, targetHF) {
377
+ leverageBand(strategy, collateral, targetHF, position) {
378
378
  const sdk = this.sdk.chain(strategy.chainId);
379
379
  return service(sdk).leverageBand({
380
380
  sdk,
381
381
  creditManager: strategy.creditManager,
382
382
  collateral,
383
- targetHF
383
+ targetHF,
384
+ position
384
385
  });
385
386
  }
386
387
  /**
@@ -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";
@@ -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 { DIRECT_TRANSFERS_QUOTA, 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, 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, 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";
@@ -9,12 +10,13 @@ import { isPhantomToken } from "./utils/pick-token.js";
9
10
  import { assertMarketOperable } from "./guards.js";
10
11
  import { fetchCreditAccountSlice, toCreditAccountSlice } from "./utils/credit-account-slice.js";
11
12
  import { buildBorrowState } from "./borrow.js";
13
+ import { strategyLimits } from "./strategyLimits.js";
14
+ import { accountView } from "./view.js";
12
15
  import { calcLeverageBand } from "./leverage-band.js";
13
16
  import { maxBorrow } from "./maxBorrow.js";
14
17
  import { maxWithdrawCollateral } from "./maxWithdrawCollateral.js";
15
18
  import { buildOpenStrategyState } from "./open-strategy.js";
16
19
  import { planAddCollateral, planAdjustLeverage, planAdjustLeverageDelayed, planDeposit, planRepay, planWithdraw, planWithdrawAsset, planWithdrawDelayed } from "./plan.js";
17
- import { accountView } from "./view.js";
18
20
  import { withdrawLimits } from "./withdraw-limits.js";
19
21
  import { realize } from "./realize.js";
20
22
  import { planTail, projectTail } from "./tail.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
@@ -105,9 +123,8 @@ var CreditAccountOperationsService = class extends SDKConstruct {
105
123
  * given deposit reaches is decided by the debt it implies and by the
106
124
  * `debtLimits` the market puts that debt in — the range a leverage slider should offer.
107
125
  *
108
- * Unlike the other ceilings here this one reads no account: opening has none
109
- * yet, and adjusting measures against the net value the caller already
110
- * holds. Nothing is fetched, so a form can ask on every keystroke.
126
+ * Nothing is fetched: opening uses the supplied collateral, while adjust
127
+ * uses a supplied account slice, so a form can ask on every keystroke.
111
128
  *
112
129
  * @param props - The manager, the SDK holding its market, what stands
113
130
  * behind the position, and optionally the health factor the ceiling should
@@ -190,14 +207,28 @@ var CreditAccountOperationsService = class extends SDKConstruct {
190
207
  */
191
208
  async startDelayedIntent(props) {
192
209
  const { intent } = props;
210
+ const current = accountView(props.creditAccount, props.sdk);
211
+ const repayFromSource = current.debt - current.balanceOf(current.underlying);
212
+ const maximum = intent.type === "ADJUST_LEVERAGE" && current.collateral > 0n && repayFromSource > 0n ? LEVERAGE_DECIMALS + (repayFromSource * LEVERAGE_DECIMALS - 1n) / current.collateral : void 0;
213
+ const limits = intent.type === "ADJUST_LEVERAGE" && maximum !== void 0 ? strategyLimits({
214
+ ...intent,
215
+ suite: props.sdk.marketRegister.findCreditManager(props.creditAccount.creditManager),
216
+ view: current,
217
+ initialQuotas: props.creditAccount.tokens,
218
+ quotaReserve: props.quotaReserve,
219
+ maxLeverage: maximum
220
+ }) : {};
193
221
  const result = await this.#preview(props, () => {
194
- const view = accountView(props.creditAccount, props.sdk);
222
+ const view = {
223
+ ...current,
224
+ limits
225
+ };
195
226
  switch (intent.type) {
196
227
  case "ADJUST_LEVERAGE": return planAdjustLeverageDelayed(intent, view);
197
228
  case "WITHDRAW": return planWithdrawDelayed(intent, view);
198
229
  default: throw new Error(`${intent.type} - cannot be delayed`);
199
230
  }
200
- });
231
+ }, limits);
201
232
  if (!result.ok) return result;
202
233
  const { delayed } = result;
203
234
  if (!delayed) throw new Error("startDelayedIntent: plan started no withdrawal");
@@ -213,7 +244,8 @@ var CreditAccountOperationsService = class extends SDKConstruct {
213
244
  delayed,
214
245
  creditAccount: props.creditAccount,
215
246
  sdk: props.sdk,
216
- quotaReserve: props.quotaReserve
247
+ quotaReserve: props.quotaReserve,
248
+ limits
217
249
  });
218
250
  return {
219
251
  ...result,
@@ -399,7 +431,7 @@ var CreditAccountOperationsService = class extends SDKConstruct {
399
431
  }
400
432
  }
401
433
  /** Plan → realise → wrap. Unviable requests become `{ ok: false }`. */
402
- async #preview(props, plan) {
434
+ async #preview(props, plan, limits = {}) {
403
435
  const draft = props.draft ?? {};
404
436
  try {
405
437
  const suite = props.sdk.marketRegister.findCreditManager(props.creditAccount.creditManager);
@@ -410,7 +442,8 @@ var CreditAccountOperationsService = class extends SDKConstruct {
410
442
  sdk: props.sdk,
411
443
  slippage: props.slippage ?? 0,
412
444
  quotaReserve: props.quotaReserve,
413
- draft
445
+ draft,
446
+ limits
414
447
  });
415
448
  return {
416
449
  ok: true,
@@ -1,6 +1,8 @@
1
1
  import { BigIntMath } from "../../utils/bigint-math.js";
2
2
  import { LEVERAGE_DECIMALS } from "../../constants/math.js";
3
- import { resolveCreditManager } from "./utils/common.js";
3
+ import { eq, resolveCreditManager } from "./utils/common.js";
4
+ import { strategyLimits } from "./strategyLimits.js";
5
+ import { accountView } from "./view.js";
4
6
  //#region src/onchain/accounts/intents/leverage-band.ts
5
7
  /**
6
8
  * The leverages this market will actually fund for a position of this size.
@@ -15,8 +17,8 @@ import { resolveCreditManager } from "./utils/common.js";
15
17
  * rounds **up** so the leverage it names really does clear `minDebt`, and the
16
18
  * ceiling rounds **down** so it really does stay under the borrow limit.
17
19
  *
18
- * Nothing here is fetched or simulated — every input is loaded market state,
19
- * so a form can call this on each keystroke.
20
+ * Nothing here is fetched or simulated — adjust state comes from the supplied
21
+ * position and the attached market, so a form can call this on each keystroke.
20
22
  *
21
23
  * @param props - {@link LeverageBandProps}
22
24
  * @returns The band, or `undefined` when there is nothing to offer: an
@@ -29,13 +31,53 @@ import { resolveCreditManager } from "./utils/common.js";
29
31
  * calcLeverageBand({ sdk, creditManager, collateral }) // { min: 1.1, max: 9 }
30
32
  * ```
31
33
  **/
32
- function calcLeverageBand({ sdk, creditManager, collateral, targetHF }) {
34
+ function calcLeverageBand({ sdk, creditManager, collateral, targetHF, position }) {
33
35
  const found = resolveCreditManager(sdk, creditManager);
34
36
  if (!found) return;
35
37
  const { suite, market } = found;
36
- const target = suite.strategy?.targetCollateral;
37
- if (!target) return;
38
+ const strategy = suite.strategy;
39
+ if (!strategy) return;
40
+ const target = strategy.targetCollateral;
38
41
  const ceiling = suite.creditManager.maxLeverage(target, targetHF);
42
+ if (position) {
43
+ if (!eq(position.creditManager, creditManager)) throw new Error("credit account belongs to a different credit manager");
44
+ const creditAccount = {
45
+ creditAccount: position.creditAccount,
46
+ creditManager: position.creditManager,
47
+ creditFacade: suite.creditFacade.address,
48
+ underlying: position.underlyingToken.address,
49
+ enabledTokensMask: 0n,
50
+ totalDebtUSD: 0n,
51
+ totalDebt: position.totalDebt.value,
52
+ tokens: position.collaterals.map(({ collateral, quota }) => ({
53
+ token: collateral.token.address,
54
+ mask: 0n,
55
+ balance: collateral.value,
56
+ quota: quota.value,
57
+ success: true
58
+ }))
59
+ };
60
+ const view = {
61
+ ...accountView(creditAccount, sdk),
62
+ collateral: position.totalValue.value - position.totalDebt.value
63
+ };
64
+ const { leverageLimits, quotaLimits } = strategyLimits({
65
+ type: "ADJUST_LEVERAGE",
66
+ suite,
67
+ view,
68
+ initialQuotas: creditAccount.tokens,
69
+ token: target,
70
+ targetLeverage: LEVERAGE_DECIMALS,
71
+ quotaReserve: void 0
72
+ });
73
+ if (!leverageLimits) return void 0;
74
+ const min = Number(leverageLimits.min) / Number(LEVERAGE_DECIMALS);
75
+ const max = Math.min(ceiling, Number(BigIntMath.min(leverageLimits.max, quotaLimits?.leverageMax ?? leverageLimits.max)) / Number(LEVERAGE_DECIMALS));
76
+ return min > max ? void 0 : {
77
+ min,
78
+ max
79
+ };
80
+ }
39
81
  const underlying = market.pool.underlying;
40
82
  const convert = (from, to, amount) => market.priceOracle.safeConvert(from, to, amount).value;
41
83
  const netValue = collateral.reduce((acc, a) => acc + convert(a.token, underlying, a.balance), 0n);
@@ -43,9 +85,8 @@ function calcLeverageBand({ sdk, creditManager, collateral, targetHF }) {
43
85
  min: 1,
44
86
  max: ceiling
45
87
  };
46
- const { minDebt, maxDebt } = suite.creditFacade;
47
- const available = market.pool.pool.creditManagerDebtParams.get(suite.creditManager.address)?.available;
48
- const borrowLimit = available === void 0 ? maxDebt : BigIntMath.min(maxDebt, available);
88
+ const { minDebt } = suite.creditFacade;
89
+ const borrowLimit = strategy.maxBorrowAmount().amount.value;
49
90
  const floor = BigIntMath.ceilDiv(LEVERAGE_DECIMALS * minDebt, netValue);
50
91
  const roof = BigIntMath.ceilDiv(LEVERAGE_DECIMALS * (borrowLimit + 1n), netValue) - 1n;
51
92
  const min = 1 + Number(floor) / Number(LEVERAGE_DECIMALS);
@@ -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 };