@gearbox-protocol/sdk 17.6.1 → 17.7.0

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 (45) hide show
  1. package/dist/cjs/onchain/accounts/intents/borrow.js +1 -1
  2. package/dist/cjs/onchain/accounts/intents/collateral-valuation.js +5 -3
  3. package/dist/cjs/onchain/accounts/intents/guards.js +3 -2
  4. package/dist/cjs/onchain/accounts/intents/index.js +17 -12
  5. package/dist/cjs/onchain/accounts/intents/leverage-band.js +1 -1
  6. package/dist/cjs/onchain/accounts/intents/math.js +46 -4
  7. package/dist/cjs/onchain/accounts/intents/maxWithdrawCollateral.js +6 -3
  8. package/dist/cjs/onchain/accounts/intents/open-strategy.js +11 -2
  9. package/dist/cjs/onchain/accounts/intents/plan.js +5 -6
  10. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +1 -1
  11. package/dist/cjs/onchain/accounts/intents/view.js +3 -4
  12. package/dist/cjs/onchain/accounts/intents/withdraw-limits.js +3 -3
  13. package/dist/cjs/onchain/validation/checks/checkBorrowLimit.js +1 -0
  14. package/dist/cjs/onchain/validation/checks/checkDebtLimits.js +1 -0
  15. package/dist/cjs/sdk/prepare/PrepareApi.js +5 -4
  16. package/dist/esm/onchain/accounts/intents/borrow.js +1 -1
  17. package/dist/esm/onchain/accounts/intents/collateral-valuation.js +5 -3
  18. package/dist/esm/onchain/accounts/intents/guards.js +3 -2
  19. package/dist/esm/onchain/accounts/intents/index.js +18 -13
  20. package/dist/esm/onchain/accounts/intents/leverage-band.js +1 -1
  21. package/dist/esm/onchain/accounts/intents/math.js +47 -6
  22. package/dist/esm/onchain/accounts/intents/maxWithdrawCollateral.js +6 -3
  23. package/dist/esm/onchain/accounts/intents/open-strategy.js +12 -3
  24. package/dist/esm/onchain/accounts/intents/plan.js +5 -6
  25. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +1 -1
  26. package/dist/esm/onchain/accounts/intents/view.js +3 -4
  27. package/dist/esm/onchain/accounts/intents/withdraw-limits.js +3 -3
  28. package/dist/esm/onchain/validation/checks/checkBorrowLimit.js +1 -0
  29. package/dist/esm/onchain/validation/checks/checkDebtLimits.js +1 -0
  30. package/dist/esm/sdk/prepare/PrepareApi.js +5 -4
  31. package/dist/types/model/errors/operation-errors.d.ts +10 -0
  32. package/dist/types/onchain/accounts/intents/collateral-valuation.d.ts +4 -2
  33. package/dist/types/onchain/accounts/intents/guards.d.ts +4 -1
  34. package/dist/types/onchain/accounts/intents/index.d.ts +11 -9
  35. package/dist/types/onchain/accounts/intents/math.d.ts +20 -4
  36. package/dist/types/onchain/accounts/intents/maxWithdrawCollateral.d.ts +3 -1
  37. package/dist/types/onchain/accounts/intents/plan.d.ts +0 -3
  38. package/dist/types/onchain/accounts/intents/withdraw-limits.d.ts +7 -0
  39. package/dist/types/onchain/validation/checks/checkBorrowLimit.d.ts +1 -0
  40. package/dist/types/onchain/validation/checks/checkDebtLimits.d.ts +2 -1
  41. package/dist/types/sdk/index.d.ts +2 -2
  42. package/dist/types/sdk/prepare/PrepareApi.d.ts +3 -3
  43. package/dist/types/sdk/prepare/index.d.ts +2 -2
  44. package/dist/types/sdk/prepare/types.d.ts +16 -5
  45. package/package.json +1 -1
@@ -55,7 +55,7 @@ async function buildBorrowState(props) {
55
55
  totalDebt: market.toUnderlyingAmount(debt),
56
56
  netValue: market.toUnderlyingAmount(margin - debt)
57
57
  });
58
- require_onchain_accounts_intents_math.assertDebtLimits(sdk, debt, suite.creditFacade, underlying, suite.maxBorrowAmount());
58
+ require_onchain_accounts_intents_math.assertDebtLimits(sdk, debt, suite.creditFacade, underlying, { maxBorrowAmount: existing ? void 0 : suite.maxBorrowAmount() });
59
59
  require_onchain_accounts_intents_guards.assertCanBorrow(sdk, suite, debt);
60
60
  const account = existing ?? require_onchain_accounts_intents_utils_credit_account_slice.unopenedAccountSlice({
61
61
  creditManager,
@@ -4,8 +4,10 @@ const require_onchain_constants_math = require("../../constants/math.js");
4
4
  require("../../utils/index.js");
5
5
  const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
6
6
  //#region src/onchain/accounts/intents/collateral-valuation.ts
7
- /** {@inheritDoc CollateralValuation} */
8
- function collateralValuation(creditAccount, sdk) {
7
+ /** {@inheritDoc CollateralValuation}
8
+ * Set `safePrices` to false to value the same counted holdings at main prices.
9
+ */
10
+ function collateralValuation(creditAccount, sdk, safePrices = true) {
9
11
  const { market, creditManager } = sdk.marketRegister.findCreditManager(creditAccount.creditManager);
10
12
  const { priceOracle } = market;
11
13
  const { pqk } = market.pool;
@@ -19,7 +21,7 @@ function collateralValuation(creditAccount, sdk) {
19
21
  }
20
22
  };
21
23
  const lt = (token) => BigInt(creditManager.liquidationThresholds.get(token) ?? 0);
22
- const checkedUsd = (holding) => require_onchain_accounts_intents_utils_common.eq(holding.token, underlying) ? mainUsd(holding.token, holding.balance) ?? 0n : priceOracle.safeConvertMinUSD(holding.token, holding.balance).value;
24
+ const checkedUsd = (holding) => !safePrices || require_onchain_accounts_intents_utils_common.eq(holding.token, underlying) ? mainUsd(holding.token, holding.balance) ?? 0n : priceOracle.safeConvertMinUSD(holding.token, holding.balance).value;
23
25
  /** A quota is underlying-denominated, and a closed market backs nothing. */
24
26
  const quotaValue = (holding) => pqk.hasActiveQuota(holding.token) ? (mainUsd(underlying, holding.quota) ?? 0n) * require_onchain_constants_math.PERCENTAGE_FACTOR : 0n;
25
27
  const weigh = (holding) => {
@@ -46,13 +46,14 @@ function assertMarketOperable(suite) {
46
46
  }), `${creditManager} expired at ${suite.creditFacade.expirationDate}`);
47
47
  }
48
48
  /** The pool has to be able to lend what the plan means to draw. */
49
- function assertCanBorrow(sdk, suite, amount) {
49
+ function assertCanBorrow(sdk, suite, amount, options = {}) {
50
50
  const maxBorrowAmount = suite.maxBorrowAmount();
51
51
  require_onchain_validation_raise.raise(require_onchain_validation_checks_checkBorrowLimit.checkBorrowLimit({
52
52
  requested: amount,
53
53
  available: maxBorrowAmount.amount.value,
54
54
  limit: maxBorrowAmount.limit,
55
- underlying: require_onchain_validation_helpers_token.toToken(sdk, suite.market.pool.underlying)
55
+ underlying: require_onchain_validation_helpers_token.toToken(sdk, suite.market.pool.underlying),
56
+ getCollateralLimits: options.getCollateralLimits
56
57
  }), `borrow: ${amount} exceeds what the pool can lend now (${maxBorrowAmount.amount.value})`);
57
58
  }
58
59
  /**
@@ -64,18 +64,23 @@ var CreditAccountOperationsService = class extends require_onchain_base_SDKConst
64
64
  * it as `safePartial`. The second is the one to offer — see
65
65
  * {@link WithdrawCeilings}.
66
66
  *
67
- * Takes no target health factor, unlike {@link maxWithdrawCollateral}. A
68
- * proportional withdrawal leaves the factor where it found it, so there is
69
- * no room to choose: what these answer to is the facade's own threshold,
70
- * which is also what {@link startIntent} refuses against.
67
+ * The default target health factor is the facade's own threshold, which is
68
+ * also what {@link startIntent} refuses against. A form holding the account
69
+ * to something stricter passes its own, as with
70
+ * {@link maxWithdrawCollateral}.
71
71
  *
72
- * @param props - Account slice, the SDK holding its market, and optionally
73
- * the collateral the withdrawal would be funded from
72
+ * @param props - Account slice, the SDK holding its market, optionally the
73
+ * collateral the withdrawal would be funded from, and optionally the health
74
+ * factor the ceiling should leave
74
75
  * @returns The three limits, see {@link WithdrawCeilings} for the gap
75
76
  * between them
76
77
  */
77
78
  maxWithdraw(props) {
78
- return require_onchain_accounts_intents_withdraw_limits.withdrawLimits(props);
79
+ const { targetHF = BigInt(require_onchain_validation_helpers_health_factor_limits.MIN_HEALTH_FACTOR_FACADE), ...rest } = props;
80
+ return require_onchain_accounts_intents_withdraw_limits.withdrawLimits({
81
+ ...rest,
82
+ targetHF: targetHF + 2n
83
+ });
79
84
  }
80
85
  /**
81
86
  * Debt a `REPAY` would have to cover to settle the account, in underlying
@@ -115,23 +120,23 @@ var CreditAccountOperationsService = class extends require_onchain_base_SDKConst
115
120
  }
116
121
  /**
117
122
  * Largest `WITHDRAW_ASSET` amount of one token the account can take out
118
- * while its health factor stays at `targetHF` — the ceiling a
123
+ * while its main and safe health factors clear their targets — the ceiling a
119
124
  * withdraw-collateral form should offer. Thresholds, prices and quota
120
125
  * activity come from the account's market, valued the way the facade values
121
126
  * a call that withdraws collateral; zero debt frees the whole balance.
122
127
  *
123
- * The default is {@link MIN_HF_LIMITED}, the threshold a form holds an
124
- * account to.
128
+ * Defaults are the independent main and safe form thresholds.
125
129
  *
126
130
  * @param props - Account slice, the SDK holding its market, the collateral
127
131
  * to withdraw, and optionally the health factor to leave behind
128
132
  * @returns Amount in the token's units; `0n` when nothing can leave
129
133
  */
130
134
  maxWithdrawCollateral(props) {
131
- const { targetHF = require_onchain_validation_helpers_health_factor_limits.MIN_HF_LIMITED, ...rest } = props;
135
+ const { targetHF = BigInt(require_onchain_validation_helpers_health_factor_limits.MIN_HEALTH_FACTOR_FORM), targetSafeHF = BigInt(require_onchain_validation_helpers_health_factor_limits.MIN_SAFE_HEALTH_FACTOR_FORM), ...rest } = props;
132
136
  return require_onchain_accounts_intents_maxWithdrawCollateral.maxWithdrawCollateral({
133
137
  ...rest,
134
- targetHF: targetHF + 2n
138
+ targetHF: targetHF + 2n,
139
+ targetSafeHF: targetSafeHF + 2n
135
140
  });
136
141
  }
137
142
  /**
@@ -48,7 +48,7 @@ function calcLeverageBand({ sdk, creditManager, collateral, targetHF }) {
48
48
  const available = market.pool.pool.creditManagerDebtParams.get(suite.creditManager.address)?.available;
49
49
  const borrowLimit = available === void 0 ? maxDebt : require_onchain_utils_bigint_math.BigIntMath.min(maxDebt, available);
50
50
  const floor = require_onchain_utils_bigint_math.BigIntMath.ceilDiv(require_onchain_constants_math.LEVERAGE_DECIMALS * minDebt, netValue);
51
- const roof = require_onchain_constants_math.LEVERAGE_DECIMALS * borrowLimit / netValue;
51
+ const roof = require_onchain_utils_bigint_math.BigIntMath.ceilDiv(require_onchain_constants_math.LEVERAGE_DECIMALS * (borrowLimit + 1n), netValue) - 1n;
52
52
  const min = 1 + Number(floor) / Number(require_onchain_constants_math.LEVERAGE_DECIMALS);
53
53
  const max = Math.min(ceiling, 1 + Number(roof) / Number(require_onchain_constants_math.LEVERAGE_DECIMALS));
54
54
  return min > max ? void 0 : {
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_onchain_utils_bigint_math = require("../../utils/bigint-math.js");
3
3
  const require_onchain_constants_math = require("../../constants/math.js");
4
+ require("../../constants/index.js");
4
5
  const require_model_errors_operation_errors = require("../../../model/errors/operation-errors.js");
5
6
  require("../../../model/index.js");
6
7
  const require_onchain_validation_helpers_token = require("../../validation/helpers/token.js");
@@ -53,22 +54,63 @@ function assertLeverageAtLeastOne(leverage) {
53
54
  }), `target leverage ${leverage} is below 1x`);
54
55
  }
55
56
  /**
56
- * Rejects a debt the facade would revert on: zero is always fine (no loan at
57
- * all), anything else has to sit inside `[minDebt, maxDebt]`.
57
+ * Rejects a debt the facade would revert on: anything else has to sit inside
58
+ * `[minDebt, maxDebt]`. Zero is fine only `allowZero`-ing it: an adjustment
59
+ * may end owing nothing, an opening may not.
58
60
  */
59
- function assertDebtLimits(sdk, debt, debtLimits, underlying, maxBorrowAmount) {
61
+ function assertDebtLimits(sdk, debt, debtLimits, underlying, options = {}) {
62
+ const { allowZero = true, getCollateralLimits, maxBorrowAmount } = options;
60
63
  require_onchain_validation_raise.raise(require_onchain_validation_checks_checkDebtLimits.checkDebtLimits({
61
64
  debt,
62
65
  minDebt: debtLimits.minDebt,
63
66
  maxDebt: debtLimits.maxDebt,
64
67
  underlying: require_onchain_validation_helpers_token.toToken(sdk, underlying),
65
- allowZero: true,
68
+ allowZero,
69
+ getCollateralLimits,
66
70
  maxBorrowAmount
67
71
  }), debt > debtLimits.maxDebt ? `debt ${debt} exceeds maxDebt ${debtLimits.maxDebt}` : `debt ${debt} is below minDebt ${debtLimits.minDebt}`);
68
72
  }
73
+ /** Finds single-token Open amounts whose projected debt fits the market limits. */
74
+ function openCollateralForDebtLimits({ suite, collateral, leverage }) {
75
+ if (collateral.length !== 1 || leverage <= 100n) return void 0;
76
+ const [{ token }] = collateral;
77
+ const { market } = suite;
78
+ const limits = {
79
+ minDebt: suite.creditFacade.minDebt,
80
+ maxDebt: suite.maxBorrowAmount().amount.value
81
+ };
82
+ if (limits.maxDebt < limits.minDebt) return void 0;
83
+ const debtAt = (amount) => {
84
+ const converted = market.priceOracle.safeConvert(token, market.pool.underlying, amount);
85
+ return converted.error ? void 0 : debtForLeverage(converted.value, leverage);
86
+ };
87
+ const lastDebt = debtAt(require_onchain_constants_math.MAX_UINT256);
88
+ if (lastDebt === void 0 || lastDebt < limits.minDebt) return void 0;
89
+ const firstAtLeast = (threshold) => {
90
+ let low = 0n;
91
+ let high = require_onchain_constants_math.MAX_UINT256;
92
+ while (low < high) {
93
+ const middle = (low + high) / 2n;
94
+ const debt = debtAt(middle);
95
+ if (debt === void 0) return void 0;
96
+ if (debt < threshold) low = middle + 1n;
97
+ else high = middle;
98
+ }
99
+ return low;
100
+ };
101
+ const min = firstAtLeast(limits.minDebt > 0n ? limits.minDebt : 1n);
102
+ const above = lastDebt > limits.maxDebt ? firstAtLeast(limits.maxDebt + 1n) : void 0;
103
+ if (min === void 0 || lastDebt > limits.maxDebt && above === void 0) return void 0;
104
+ const max = above === void 0 ? require_onchain_constants_math.MAX_UINT256 : above - 1n;
105
+ return min <= max ? {
106
+ min: market.priceOracle.toTokenAmount(token, min),
107
+ max: market.priceOracle.toTokenAmount(token, max)
108
+ } : void 0;
109
+ }
69
110
  //#endregion
70
111
  exports.assertDebtLimits = assertDebtLimits;
71
112
  exports.assertLeverageAtLeastOne = assertLeverageAtLeastOne;
72
113
  exports.debtForLeverage = debtForLeverage;
73
114
  exports.maxProportionalWithdrawal = maxProportionalWithdrawal;
115
+ exports.openCollateralForDebtLimits = openCollateralForDebtLimits;
74
116
  exports.proportionalDebt = proportionalDebt;
@@ -7,7 +7,7 @@ const require_onchain_accounts_intents_collateral_valuation = require("./collate
7
7
  //#region src/onchain/accounts/intents/maxWithdrawCollateral.ts
8
8
  /**
9
9
  * Largest amount of one collateral the account can withdraw while its health
10
- * factor stays at or above `targetHF`.
10
+ * factors stay at or above `targetHF` and `targetSafeHF`.
11
11
  *
12
12
  * This is the collateral check solved for one balance, and it counts what that
13
13
  * check counts — see {@link collateralValuation} for it, safe prices included.
@@ -22,11 +22,14 @@ const require_onchain_accounts_intents_collateral_valuation = require("./collate
22
22
  * underlying has no price
23
23
  **/
24
24
  function maxWithdrawCollateral(props) {
25
- const { creditAccount, sdk, token, targetHF } = props;
25
+ return require_onchain_utils_bigint_math.BigIntMath.min(ceilingAtPrice(props, props.targetHF, false), ceilingAtPrice(props, props.targetSafeHF, true));
26
+ }
27
+ function ceilingAtPrice(props, targetHF, safePrices) {
28
+ const { creditAccount, sdk, token } = props;
26
29
  const target = creditAccount.tokens.find((t) => require_onchain_accounts_intents_utils_common.eq(t.token, token));
27
30
  if (!target || target.balance <= 10n) return 0n;
28
31
  if (creditAccount.totalDebt === 0n) return target.balance;
29
- const valuation = require_onchain_accounts_intents_collateral_valuation.collateralValuation(creditAccount, sdk);
32
+ const valuation = require_onchain_accounts_intents_collateral_valuation.collateralValuation(creditAccount, sdk, safePrices);
30
33
  let otherValue = 0n;
31
34
  for (const t of creditAccount.tokens) {
32
35
  if (require_onchain_accounts_intents_utils_common.eq(t.token, token) || !valuation.counts(t)) continue;
@@ -45,8 +45,17 @@ async function buildOpenStrategyState(props) {
45
45
  creditFacade: suite.creditFacade.address,
46
46
  underlying
47
47
  });
48
- require_onchain_accounts_intents_math.assertDebtLimits(sdk, debt, suite.creditFacade, underlying, suite.maxBorrowAmount());
49
- require_onchain_accounts_intents_guards.assertCanBorrow(sdk, suite, debt);
48
+ const getCollateralLimits = () => require_onchain_accounts_intents_math.openCollateralForDebtLimits({
49
+ suite,
50
+ collateral,
51
+ leverage
52
+ });
53
+ require_onchain_accounts_intents_math.assertDebtLimits(sdk, debt, suite.creditFacade, underlying, {
54
+ allowZero: false,
55
+ maxBorrowAmount: suite.maxBorrowAmount(),
56
+ getCollateralLimits
57
+ });
58
+ require_onchain_accounts_intents_guards.assertCanBorrow(sdk, suite, debt, { getCollateralLimits });
50
59
  const paths = require_onchain_accounts_intents_utils_router_path.createRouterPaths({
51
60
  sdk,
52
61
  creditAccount: account,
@@ -43,7 +43,7 @@ function planDeposit(intent, view) {
43
43
  const aU = view.price(intent.token, U, intent.amount);
44
44
  const debtDelta = intent.targetLeverage === void 0 ? require_onchain_accounts_intents_math.proportionalDebt(view, aU) : require_onchain_accounts_intents_math.debtForLeverage(view.collateral + aU, intent.targetLeverage) - view.debt;
45
45
  if (debtDelta < 0n) throw new require_onchain_validation_raise.IntentPreviewError(require_model_errors_operation_errors.leverageOutOfRange(), `deposit: target leverage ${intent.targetLeverage} would require repaying debt`);
46
- require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, view.debt + debtDelta, view.debtLimits, U, view.maxBorrowAmount);
46
+ require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, view.debt + debtDelta, view.debtLimits, U);
47
47
  const T = intent.positionToken ?? positionToken(view, "deposit");
48
48
  const depositStays = require_onchain_accounts_intents_utils_common.eq(intent.token, T);
49
49
  return [
@@ -74,12 +74,11 @@ function planRepay(intent, view) {
74
74
  if (view.debt <= 0n) throw new require_onchain_validation_raise.IntentPreviewError(require_model_errors_operation_errors.debtOutOfRange({
75
75
  requested: require_onchain_validation_helpers_token.toTokenAmount(view.sdk, U, view.debt),
76
76
  minDebt: require_onchain_validation_helpers_token.toTokenAmount(view.sdk, U, view.debtLimits.minDebt),
77
- maxDebt: require_onchain_validation_helpers_token.toTokenAmount(view.sdk, U, view.debtLimits.maxDebt),
78
- maxBorrowAmount: view.maxBorrowAmount
77
+ maxDebt: require_onchain_validation_helpers_token.toTokenAmount(view.sdk, U, view.debtLimits.maxDebt)
79
78
  }), "repay: the account owes nothing");
80
79
  const funding = everything(intent.amount) ? view.price(U, intent.token, withMargin(view.debt)) : intent.amount;
81
80
  const repaid = min(view.price(intent.token, U, funding), view.debt);
82
- require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, view.debt - repaid, view.debtLimits, view.underlying, view.maxBorrowAmount);
81
+ require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, view.debt - repaid, view.debtLimits, view.underlying);
83
82
  return [
84
83
  add(intent.token, funding, intent.value),
85
84
  ...fundsInU ? [] : [convert(intent.token, U, funding)],
@@ -308,7 +307,7 @@ function withdrawShape(intent, view) {
308
307
  };
309
308
  }
310
309
  const dD = require_onchain_accounts_intents_math.proportionalDebt(view, WU);
311
- require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, view.debt - dD, view.debtLimits, view.underlying, view.maxBorrowAmount);
310
+ require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, view.debt - dD, view.debtLimits, view.underlying);
312
311
  return {
313
312
  U,
314
313
  T,
@@ -327,7 +326,7 @@ function leverageShape(intent, view) {
327
326
  require_onchain_accounts_intents_math.assertLeverageAtLeastOne(intent.targetLeverage);
328
327
  if (view.collateral <= 0n) throw new require_onchain_validation_raise.IntentPreviewError(require_model_errors_operation_errors.insufficientBalance(), "adjustLeverage: account has no collateral to lever");
329
328
  const target = require_onchain_accounts_intents_math.debtForLeverage(view.collateral, intent.targetLeverage);
330
- require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, target, view.debtLimits, view.underlying, view.maxBorrowAmount);
329
+ require_onchain_accounts_intents_math.assertDebtLimits(view.sdk, target, view.debtLimits, view.underlying);
331
330
  return {
332
331
  U: view.underlying,
333
332
  delta: target - view.debt
@@ -113,7 +113,7 @@ function buildMockSdk(args) {
113
113
  reservePrice: lookup(args.reservePrices, token)
114
114
  };
115
115
  const priceOracle = new require_TestPriceOracle_mock.TestPriceOracle(tokenCfgs);
116
- const convert = (from, to, amount) => priceOracle.convert(from, to, amount);
116
+ const convert = (from, to, amount) => priceOracle.safeConvert(from, to, amount).value;
117
117
  const fullQuota = (q) => ({
118
118
  cumulativeIndexLU: 0n,
119
119
  totalQuoted: 0n,
@@ -13,7 +13,7 @@ function accountView(creditAccount, sdk) {
13
13
  const { underlying, creditManager } = creditAccount;
14
14
  const oracle = sdk.marketRegister.findByCreditManager(creditManager).priceOracle;
15
15
  const price = (from, to, amount) => oracle.safeConvert(from, to, amount).value;
16
- const creditSuite = sdk.marketRegister.findCreditManager(creditManager);
16
+ const { creditFacade } = sdk.marketRegister.findCreditManager(creditManager);
17
17
  let totalValue = 0n;
18
18
  for (const t of creditAccount.tokens) totalValue += price(t.token, underlying, t.balance);
19
19
  return {
@@ -23,10 +23,9 @@ function accountView(creditAccount, sdk) {
23
23
  debt: creditAccount.totalDebt,
24
24
  collateral: totalValue - creditAccount.totalDebt,
25
25
  debtLimits: {
26
- minDebt: creditSuite.creditFacade.minDebt,
27
- maxDebt: creditSuite.creditFacade.maxDebt
26
+ minDebt: creditFacade.minDebt,
27
+ maxDebt: creditFacade.maxDebt
28
28
  },
29
- maxBorrowAmount: creditSuite.maxBorrowAmount(),
30
29
  balanceOf: (token) => creditAccount.tokens.find((t) => require_onchain_accounts_intents_utils_common.eq(t.token, token))?.balance ?? 0n,
31
30
  price,
32
31
  fattest: (exclude) => require_onchain_accounts_intents_utils_pick_token.pickFattestNonPhantomToken({
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_onchain_utils_bigint_math = require("../../utils/bigint-math.js");
3
3
  require("../../utils/index.js");
4
- const require_onchain_validation_helpers_health_factor_limits = require("../../validation/helpers/health-factor-limits.js");
4
+ 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");
@@ -21,12 +21,12 @@ const require_onchain_accounts_intents_view = require("./view.js");
21
21
  * @returns The three limits, see {@link WithdrawCeilings}
22
22
  **/
23
23
  function withdrawLimits(props) {
24
- const { creditAccount, sdk } = props;
24
+ const { creditAccount, sdk, targetHF } = props;
25
25
  const view = require_onchain_accounts_intents_view.accountView(creditAccount, sdk);
26
26
  const partial = require_onchain_accounts_intents_math.maxProportionalWithdrawal(view, view.debtLimits);
27
27
  const safe = maxSafeWithdrawal({
28
28
  ...props,
29
- targetHF: BigInt(require_onchain_validation_helpers_health_factor_limits.MIN_HEALTH_FACTOR_FACADE)
29
+ targetHF: targetHF ?? BigInt(1e4)
30
30
  });
31
31
  return {
32
32
  partial,
@@ -15,6 +15,7 @@ function checkBorrowLimit(args) {
15
15
  const { requested, available, limit, underlying, maxBorrowAmount } = args;
16
16
  if (requested <= available) return [];
17
17
  return [require_model_errors_operation_errors.insufficientPoolLiquidity({
18
+ collateralLimits: args.getCollateralLimits?.(),
18
19
  requested: require_onchain_validation_helpers_amount.amountOf(underlying, requested),
19
20
  available: require_onchain_validation_helpers_amount.amountOf(underlying, available),
20
21
  limit,
@@ -9,6 +9,7 @@ function checkDebtLimits(args) {
9
9
  const { debt, minDebt, maxDebt, underlying, allowZero, maxBorrowAmount } = 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
13
  requested: require_onchain_validation_helpers_amount.amountOf(underlying, debt),
13
14
  minDebt: require_onchain_validation_helpers_amount.amountOf(underlying, minDebt),
14
15
  maxDebt: require_onchain_validation_helpers_amount.amountOf(underlying, maxDebt),
@@ -307,13 +307,14 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
307
307
  /**
308
308
  * {@inheritDoc IOpportunitiesPrepare.maxWithdraw}
309
309
  **/
310
- async maxWithdraw(position, sourceToken) {
310
+ async maxWithdraw(position, sourceToken, targetHF) {
311
311
  const sdk = await this.#chain(position.chainId);
312
312
  const creditAccount = await this.#account(sdk, position);
313
313
  return service(sdk).maxWithdraw({
314
314
  creditAccount,
315
315
  sdk,
316
- sourceToken
316
+ sourceToken,
317
+ targetHF
317
318
  });
318
319
  }
319
320
  /**
@@ -391,14 +392,14 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
391
392
  /**
392
393
  * {@inheritDoc IOpportunitiesPrepare.maxWithdrawCollateral}
393
394
  **/
394
- async maxWithdrawCollateral(position, token, targetHF) {
395
+ async maxWithdrawCollateral(position, token, options) {
395
396
  const sdk = await this.#chain(position.chainId);
396
397
  const creditAccount = await this.#account(sdk, position);
397
398
  return service(sdk).maxWithdrawCollateral({
398
399
  creditAccount,
399
400
  sdk,
400
401
  token,
401
- targetHF
402
+ ...options
402
403
  });
403
404
  }
404
405
  /**
@@ -54,7 +54,7 @@ async function buildBorrowState(props) {
54
54
  totalDebt: market.toUnderlyingAmount(debt),
55
55
  netValue: market.toUnderlyingAmount(margin - debt)
56
56
  });
57
- assertDebtLimits(sdk, debt, suite.creditFacade, underlying, suite.maxBorrowAmount());
57
+ assertDebtLimits(sdk, debt, suite.creditFacade, underlying, { maxBorrowAmount: existing ? void 0 : suite.maxBorrowAmount() });
58
58
  assertCanBorrow(sdk, suite, debt);
59
59
  const account = existing ?? unopenedAccountSlice({
60
60
  creditManager,
@@ -3,8 +3,10 @@ import { PERCENTAGE_FACTOR } from "../../constants/math.js";
3
3
  import "../../utils/index.js";
4
4
  import { eq } from "./utils/common.js";
5
5
  //#region src/onchain/accounts/intents/collateral-valuation.ts
6
- /** {@inheritDoc CollateralValuation} */
7
- function collateralValuation(creditAccount, sdk) {
6
+ /** {@inheritDoc CollateralValuation}
7
+ * Set `safePrices` to false to value the same counted holdings at main prices.
8
+ */
9
+ function collateralValuation(creditAccount, sdk, safePrices = true) {
8
10
  const { market, creditManager } = sdk.marketRegister.findCreditManager(creditAccount.creditManager);
9
11
  const { priceOracle } = market;
10
12
  const { pqk } = market.pool;
@@ -18,7 +20,7 @@ function collateralValuation(creditAccount, sdk) {
18
20
  }
19
21
  };
20
22
  const lt = (token) => BigInt(creditManager.liquidationThresholds.get(token) ?? 0);
21
- const checkedUsd = (holding) => eq(holding.token, underlying) ? mainUsd(holding.token, holding.balance) ?? 0n : priceOracle.safeConvertMinUSD(holding.token, holding.balance).value;
23
+ const checkedUsd = (holding) => !safePrices || eq(holding.token, underlying) ? mainUsd(holding.token, holding.balance) ?? 0n : priceOracle.safeConvertMinUSD(holding.token, holding.balance).value;
22
24
  /** A quota is underlying-denominated, and a closed market backs nothing. */
23
25
  const quotaValue = (holding) => pqk.hasActiveQuota(holding.token) ? (mainUsd(underlying, holding.quota) ?? 0n) * PERCENTAGE_FACTOR : 0n;
24
26
  const weigh = (holding) => {
@@ -45,13 +45,14 @@ function assertMarketOperable(suite) {
45
45
  }), `${creditManager} expired at ${suite.creditFacade.expirationDate}`);
46
46
  }
47
47
  /** The pool has to be able to lend what the plan means to draw. */
48
- function assertCanBorrow(sdk, suite, amount) {
48
+ function assertCanBorrow(sdk, suite, amount, options = {}) {
49
49
  const maxBorrowAmount = suite.maxBorrowAmount();
50
50
  raise(checkBorrowLimit({
51
51
  requested: amount,
52
52
  available: maxBorrowAmount.amount.value,
53
53
  limit: maxBorrowAmount.limit,
54
- underlying: toToken(sdk, suite.market.pool.underlying)
54
+ underlying: toToken(sdk, suite.market.pool.underlying),
55
+ getCollateralLimits: options.getCollateralLimits
55
56
  }), `borrow: ${amount} exceeds what the pool can lend now (${maxBorrowAmount.amount.value})`);
56
57
  }
57
58
  /**
@@ -2,7 +2,7 @@ import { SDKConstruct } from "../../base/SDKConstruct.js";
2
2
  import { unsupportedTokenPair } from "../../../model/errors/prepare-errors.js";
3
3
  import { sdkErr } from "../../../model/result.js";
4
4
  import "../../../model/index.js";
5
- import { MIN_HF_LIMITED } from "../../validation/helpers/health-factor-limits.js";
5
+ import { MIN_HEALTH_FACTOR_FACADE, MIN_HEALTH_FACTOR_FORM, MIN_HF_LIMITED, MIN_SAFE_HEALTH_FACTOR_FORM } from "../../validation/helpers/health-factor-limits.js";
6
6
  import { IntentPreviewError } from "../../validation/raise.js";
7
7
  import "../../validation/index.js";
8
8
  import { isPhantomToken } from "./utils/pick-token.js";
@@ -63,18 +63,23 @@ var CreditAccountOperationsService = class extends SDKConstruct {
63
63
  * it as `safePartial`. The second is the one to offer — see
64
64
  * {@link WithdrawCeilings}.
65
65
  *
66
- * Takes no target health factor, unlike {@link maxWithdrawCollateral}. A
67
- * proportional withdrawal leaves the factor where it found it, so there is
68
- * no room to choose: what these answer to is the facade's own threshold,
69
- * which is also what {@link startIntent} refuses against.
66
+ * The default target health factor is the facade's own threshold, which is
67
+ * also what {@link startIntent} refuses against. A form holding the account
68
+ * to something stricter passes its own, as with
69
+ * {@link maxWithdrawCollateral}.
70
70
  *
71
- * @param props - Account slice, the SDK holding its market, and optionally
72
- * the collateral the withdrawal would be funded from
71
+ * @param props - Account slice, the SDK holding its market, optionally the
72
+ * collateral the withdrawal would be funded from, and optionally the health
73
+ * factor the ceiling should leave
73
74
  * @returns The three limits, see {@link WithdrawCeilings} for the gap
74
75
  * between them
75
76
  */
76
77
  maxWithdraw(props) {
77
- return withdrawLimits(props);
78
+ const { targetHF = BigInt(MIN_HEALTH_FACTOR_FACADE), ...rest } = props;
79
+ return withdrawLimits({
80
+ ...rest,
81
+ targetHF: targetHF + 2n
82
+ });
78
83
  }
79
84
  /**
80
85
  * Debt a `REPAY` would have to cover to settle the account, in underlying
@@ -114,23 +119,23 @@ var CreditAccountOperationsService = class extends SDKConstruct {
114
119
  }
115
120
  /**
116
121
  * Largest `WITHDRAW_ASSET` amount of one token the account can take out
117
- * while its health factor stays at `targetHF` — the ceiling a
122
+ * while its main and safe health factors clear their targets — the ceiling a
118
123
  * withdraw-collateral form should offer. Thresholds, prices and quota
119
124
  * activity come from the account's market, valued the way the facade values
120
125
  * a call that withdraws collateral; zero debt frees the whole balance.
121
126
  *
122
- * The default is {@link MIN_HF_LIMITED}, the threshold a form holds an
123
- * account to.
127
+ * Defaults are the independent main and safe form thresholds.
124
128
  *
125
129
  * @param props - Account slice, the SDK holding its market, the collateral
126
130
  * to withdraw, and optionally the health factor to leave behind
127
131
  * @returns Amount in the token's units; `0n` when nothing can leave
128
132
  */
129
133
  maxWithdrawCollateral(props) {
130
- const { targetHF = MIN_HF_LIMITED, ...rest } = props;
134
+ const { targetHF = BigInt(MIN_HEALTH_FACTOR_FORM), targetSafeHF = BigInt(MIN_SAFE_HEALTH_FACTOR_FORM), ...rest } = props;
131
135
  return maxWithdrawCollateral({
132
136
  ...rest,
133
- targetHF: targetHF + 2n
137
+ targetHF: targetHF + 2n,
138
+ targetSafeHF: targetSafeHF + 2n
134
139
  });
135
140
  }
136
141
  /**
@@ -47,7 +47,7 @@ function calcLeverageBand({ sdk, creditManager, collateral, targetHF }) {
47
47
  const available = market.pool.pool.creditManagerDebtParams.get(suite.creditManager.address)?.available;
48
48
  const borrowLimit = available === void 0 ? maxDebt : BigIntMath.min(maxDebt, available);
49
49
  const floor = BigIntMath.ceilDiv(LEVERAGE_DECIMALS * minDebt, netValue);
50
- const roof = LEVERAGE_DECIMALS * borrowLimit / netValue;
50
+ const roof = BigIntMath.ceilDiv(LEVERAGE_DECIMALS * (borrowLimit + 1n), netValue) - 1n;
51
51
  const min = 1 + Number(floor) / Number(LEVERAGE_DECIMALS);
52
52
  const max = Math.min(ceiling, 1 + Number(roof) / Number(LEVERAGE_DECIMALS));
53
53
  return min > max ? void 0 : {
@@ -1,5 +1,6 @@
1
1
  import { BigIntMath } from "../../utils/bigint-math.js";
2
- import { LEVERAGE_DECIMALS, PERCENTAGE_FACTOR } from "../../constants/math.js";
2
+ import { LEVERAGE_DECIMALS, MAX_UINT256, PERCENTAGE_FACTOR } from "../../constants/math.js";
3
+ import "../../constants/index.js";
3
4
  import { insufficientBalance } from "../../../model/errors/operation-errors.js";
4
5
  import "../../../model/index.js";
5
6
  import { toToken } from "../../validation/helpers/token.js";
@@ -52,18 +53,58 @@ function assertLeverageAtLeastOne(leverage) {
52
53
  }), `target leverage ${leverage} is below 1x`);
53
54
  }
54
55
  /**
55
- * Rejects a debt the facade would revert on: zero is always fine (no loan at
56
- * all), anything else has to sit inside `[minDebt, maxDebt]`.
56
+ * Rejects a debt the facade would revert on: anything else has to sit inside
57
+ * `[minDebt, maxDebt]`. Zero is fine only `allowZero`-ing it: an adjustment
58
+ * may end owing nothing, an opening may not.
57
59
  */
58
- function assertDebtLimits(sdk, debt, debtLimits, underlying, maxBorrowAmount) {
60
+ function assertDebtLimits(sdk, debt, debtLimits, underlying, options = {}) {
61
+ const { allowZero = true, getCollateralLimits, maxBorrowAmount } = options;
59
62
  raise(checkDebtLimits({
60
63
  debt,
61
64
  minDebt: debtLimits.minDebt,
62
65
  maxDebt: debtLimits.maxDebt,
63
66
  underlying: toToken(sdk, underlying),
64
- allowZero: true,
67
+ allowZero,
68
+ getCollateralLimits,
65
69
  maxBorrowAmount
66
70
  }), debt > debtLimits.maxDebt ? `debt ${debt} exceeds maxDebt ${debtLimits.maxDebt}` : `debt ${debt} is below minDebt ${debtLimits.minDebt}`);
67
71
  }
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
+ }
68
109
  //#endregion
69
- export { assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage, maxProportionalWithdrawal, proportionalDebt };
110
+ export { assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage, maxProportionalWithdrawal, openCollateralForDebtLimits, proportionalDebt };
@@ -6,7 +6,7 @@ import { collateralValuation } from "./collateral-valuation.js";
6
6
  //#region src/onchain/accounts/intents/maxWithdrawCollateral.ts
7
7
  /**
8
8
  * Largest amount of one collateral the account can withdraw while its health
9
- * factor stays at or above `targetHF`.
9
+ * factors stay at or above `targetHF` and `targetSafeHF`.
10
10
  *
11
11
  * This is the collateral check solved for one balance, and it counts what that
12
12
  * check counts — see {@link collateralValuation} for it, safe prices included.
@@ -21,11 +21,14 @@ import { collateralValuation } from "./collateral-valuation.js";
21
21
  * underlying has no price
22
22
  **/
23
23
  function maxWithdrawCollateral(props) {
24
- const { creditAccount, sdk, token, targetHF } = props;
24
+ return BigIntMath.min(ceilingAtPrice(props, props.targetHF, false), ceilingAtPrice(props, props.targetSafeHF, true));
25
+ }
26
+ function ceilingAtPrice(props, targetHF, safePrices) {
27
+ const { creditAccount, sdk, token } = props;
25
28
  const target = creditAccount.tokens.find((t) => eq(t.token, token));
26
29
  if (!target || target.balance <= 10n) return 0n;
27
30
  if (creditAccount.totalDebt === 0n) return target.balance;
28
- const valuation = collateralValuation(creditAccount, sdk);
31
+ const valuation = collateralValuation(creditAccount, sdk, safePrices);
29
32
  let otherValue = 0n;
30
33
  for (const t of creditAccount.tokens) {
31
34
  if (eq(t.token, token) || !valuation.counts(t)) continue;
@@ -2,7 +2,7 @@ import { insufficientBalance } from "../../../model/errors/operation-errors.js";
2
2
  import "../../../model/index.js";
3
3
  import { IntentPreviewError } from "../../validation/raise.js";
4
4
  import { assertCanBorrow, assertCollateralised, assertGrowthAllowed, assertMarketOperable, assertQuotaAvailable } from "./guards.js";
5
- import { assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage } from "./math.js";
5
+ import { assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage, openCollateralForDebtLimits } from "./math.js";
6
6
  import { unopenedAccountSlice } from "./utils/credit-account-slice.js";
7
7
  import { collectPriceImpact } from "./utils/price-impact.js";
8
8
  import { getQuotasForUpdate } from "./utils/quotas-for-update.js";
@@ -44,8 +44,17 @@ async function buildOpenStrategyState(props) {
44
44
  creditFacade: suite.creditFacade.address,
45
45
  underlying
46
46
  });
47
- assertDebtLimits(sdk, debt, suite.creditFacade, underlying, suite.maxBorrowAmount());
48
- assertCanBorrow(sdk, suite, debt);
47
+ const getCollateralLimits = () => openCollateralForDebtLimits({
48
+ suite,
49
+ collateral,
50
+ leverage
51
+ });
52
+ assertDebtLimits(sdk, debt, suite.creditFacade, underlying, {
53
+ allowZero: false,
54
+ maxBorrowAmount: suite.maxBorrowAmount(),
55
+ getCollateralLimits
56
+ });
57
+ assertCanBorrow(sdk, suite, debt, { getCollateralLimits });
49
58
  const paths = createRouterPaths({
50
59
  sdk,
51
60
  creditAccount: account,
@@ -42,7 +42,7 @@ function planDeposit(intent, view) {
42
42
  const aU = view.price(intent.token, U, intent.amount);
43
43
  const debtDelta = intent.targetLeverage === void 0 ? proportionalDebt(view, aU) : debtForLeverage(view.collateral + aU, intent.targetLeverage) - view.debt;
44
44
  if (debtDelta < 0n) throw new IntentPreviewError(leverageOutOfRange(), `deposit: target leverage ${intent.targetLeverage} would require repaying debt`);
45
- assertDebtLimits(view.sdk, view.debt + debtDelta, view.debtLimits, U, view.maxBorrowAmount);
45
+ assertDebtLimits(view.sdk, view.debt + debtDelta, view.debtLimits, U);
46
46
  const T = intent.positionToken ?? positionToken(view, "deposit");
47
47
  const depositStays = eq(intent.token, T);
48
48
  return [
@@ -73,12 +73,11 @@ function planRepay(intent, view) {
73
73
  if (view.debt <= 0n) throw new IntentPreviewError(debtOutOfRange({
74
74
  requested: toTokenAmount(view.sdk, U, view.debt),
75
75
  minDebt: toTokenAmount(view.sdk, U, view.debtLimits.minDebt),
76
- maxDebt: toTokenAmount(view.sdk, U, view.debtLimits.maxDebt),
77
- maxBorrowAmount: view.maxBorrowAmount
76
+ maxDebt: toTokenAmount(view.sdk, U, view.debtLimits.maxDebt)
78
77
  }), "repay: the account owes nothing");
79
78
  const funding = everything(intent.amount) ? view.price(U, intent.token, withMargin(view.debt)) : intent.amount;
80
79
  const repaid = min(view.price(intent.token, U, funding), view.debt);
81
- assertDebtLimits(view.sdk, view.debt - repaid, view.debtLimits, view.underlying, view.maxBorrowAmount);
80
+ assertDebtLimits(view.sdk, view.debt - repaid, view.debtLimits, view.underlying);
82
81
  return [
83
82
  add(intent.token, funding, intent.value),
84
83
  ...fundsInU ? [] : [convert(intent.token, U, funding)],
@@ -307,7 +306,7 @@ function withdrawShape(intent, view) {
307
306
  };
308
307
  }
309
308
  const dD = proportionalDebt(view, WU);
310
- assertDebtLimits(view.sdk, view.debt - dD, view.debtLimits, view.underlying, view.maxBorrowAmount);
309
+ assertDebtLimits(view.sdk, view.debt - dD, view.debtLimits, view.underlying);
311
310
  return {
312
311
  U,
313
312
  T,
@@ -326,7 +325,7 @@ function leverageShape(intent, view) {
326
325
  assertLeverageAtLeastOne(intent.targetLeverage);
327
326
  if (view.collateral <= 0n) throw new IntentPreviewError(insufficientBalance(), "adjustLeverage: account has no collateral to lever");
328
327
  const target = debtForLeverage(view.collateral, intent.targetLeverage);
329
- assertDebtLimits(view.sdk, target, view.debtLimits, view.underlying, view.maxBorrowAmount);
328
+ assertDebtLimits(view.sdk, target, view.debtLimits, view.underlying);
330
329
  return {
331
330
  U: view.underlying,
332
331
  delta: target - view.debt
@@ -113,7 +113,7 @@ function buildMockSdk(args) {
113
113
  reservePrice: lookup(args.reservePrices, token)
114
114
  };
115
115
  const priceOracle = new TestPriceOracle(tokenCfgs);
116
- const convert = (from, to, amount) => priceOracle.convert(from, to, amount);
116
+ const convert = (from, to, amount) => priceOracle.safeConvert(from, to, amount).value;
117
117
  const fullQuota = (q) => ({
118
118
  cumulativeIndexLU: 0n,
119
119
  totalQuoted: 0n,
@@ -12,7 +12,7 @@ function accountView(creditAccount, sdk) {
12
12
  const { underlying, creditManager } = creditAccount;
13
13
  const oracle = sdk.marketRegister.findByCreditManager(creditManager).priceOracle;
14
14
  const price = (from, to, amount) => oracle.safeConvert(from, to, amount).value;
15
- const creditSuite = sdk.marketRegister.findCreditManager(creditManager);
15
+ const { creditFacade } = sdk.marketRegister.findCreditManager(creditManager);
16
16
  let totalValue = 0n;
17
17
  for (const t of creditAccount.tokens) totalValue += price(t.token, underlying, t.balance);
18
18
  return {
@@ -22,10 +22,9 @@ function accountView(creditAccount, sdk) {
22
22
  debt: creditAccount.totalDebt,
23
23
  collateral: totalValue - creditAccount.totalDebt,
24
24
  debtLimits: {
25
- minDebt: creditSuite.creditFacade.minDebt,
26
- maxDebt: creditSuite.creditFacade.maxDebt
25
+ minDebt: creditFacade.minDebt,
26
+ maxDebt: creditFacade.maxDebt
27
27
  },
28
- maxBorrowAmount: creditSuite.maxBorrowAmount(),
29
28
  balanceOf: (token) => creditAccount.tokens.find((t) => eq(t.token, token))?.balance ?? 0n,
30
29
  price,
31
30
  fattest: (exclude) => pickFattestNonPhantomToken({
@@ -1,6 +1,6 @@
1
1
  import { BigIntMath } from "../../utils/bigint-math.js";
2
2
  import "../../utils/index.js";
3
- import { MIN_HEALTH_FACTOR_FACADE } from "../../validation/helpers/health-factor-limits.js";
3
+ import "../../validation/helpers/health-factor-limits.js";
4
4
  import "../../validation/index.js";
5
5
  import { eq } from "./utils/common.js";
6
6
  import { maxProportionalWithdrawal } from "./math.js";
@@ -20,12 +20,12 @@ import { accountView } from "./view.js";
20
20
  * @returns The three limits, see {@link WithdrawCeilings}
21
21
  **/
22
22
  function withdrawLimits(props) {
23
- const { creditAccount, sdk } = props;
23
+ const { creditAccount, sdk, targetHF } = props;
24
24
  const view = accountView(creditAccount, sdk);
25
25
  const partial = maxProportionalWithdrawal(view, view.debtLimits);
26
26
  const safe = maxSafeWithdrawal({
27
27
  ...props,
28
- targetHF: BigInt(MIN_HEALTH_FACTOR_FACADE)
28
+ targetHF: targetHF ?? BigInt(1e4)
29
29
  });
30
30
  return {
31
31
  partial,
@@ -14,6 +14,7 @@ function checkBorrowLimit(args) {
14
14
  const { requested, available, limit, underlying, maxBorrowAmount } = args;
15
15
  if (requested <= available) return [];
16
16
  return [insufficientPoolLiquidity({
17
+ collateralLimits: args.getCollateralLimits?.(),
17
18
  requested: amountOf(underlying, requested),
18
19
  available: amountOf(underlying, available),
19
20
  limit,
@@ -8,6 +8,7 @@ function checkDebtLimits(args) {
8
8
  const { debt, minDebt, maxDebt, underlying, allowZero, maxBorrowAmount } = args;
9
9
  if (!(debt > maxDebt || debt < minDebt && !(allowZero && debt === 0n))) return [];
10
10
  return [debtOutOfRange({
11
+ collateralLimits: args.getCollateralLimits?.(),
11
12
  requested: amountOf(underlying, debt),
12
13
  minDebt: amountOf(underlying, minDebt),
13
14
  maxDebt: amountOf(underlying, maxDebt),
@@ -306,13 +306,14 @@ var PrepareApi = class extends MultichainConstruct {
306
306
  /**
307
307
  * {@inheritDoc IOpportunitiesPrepare.maxWithdraw}
308
308
  **/
309
- async maxWithdraw(position, sourceToken) {
309
+ async maxWithdraw(position, sourceToken, targetHF) {
310
310
  const sdk = await this.#chain(position.chainId);
311
311
  const creditAccount = await this.#account(sdk, position);
312
312
  return service(sdk).maxWithdraw({
313
313
  creditAccount,
314
314
  sdk,
315
- sourceToken
315
+ sourceToken,
316
+ targetHF
316
317
  });
317
318
  }
318
319
  /**
@@ -390,14 +391,14 @@ var PrepareApi = class extends MultichainConstruct {
390
391
  /**
391
392
  * {@inheritDoc IOpportunitiesPrepare.maxWithdrawCollateral}
392
393
  **/
393
- async maxWithdrawCollateral(position, token, targetHF) {
394
+ async maxWithdrawCollateral(position, token, options) {
394
395
  const sdk = await this.#chain(position.chainId);
395
396
  const creditAccount = await this.#account(sdk, position);
396
397
  return service(sdk).maxWithdrawCollateral({
397
398
  creditAccount,
398
399
  sdk,
399
400
  token,
400
- targetHF
401
+ ...options
401
402
  });
402
403
  }
403
404
  /**
@@ -64,6 +64,11 @@ declare function poolSunset(pool: Address): PoolSunsetError;
64
64
  **/
65
65
  interface InsufficientPoolLiquidityError extends IGearboxError {
66
66
  code: "insufficientPoolLiquidity";
67
+ /** Single-token Open amounts whose projected debt fits the current debt limits. */
68
+ collateralLimits?: {
69
+ min: TokenAmount;
70
+ max: TokenAmount;
71
+ };
67
72
  /** Both in the market's underlying. */
68
73
  requested: TokenAmount;
69
74
  available: TokenAmount;
@@ -85,6 +90,11 @@ declare function insufficientPoolLiquidity(args: Omit<InsufficientPoolLiquidityE
85
90
  **/
86
91
  interface DebtOutOfRangeError extends IGearboxError {
87
92
  code: "debtOutOfRange";
93
+ /** Single-token Open amounts whose projected debt fits the current debt limits. */
94
+ collateralLimits?: {
95
+ min: TokenAmount;
96
+ max: TokenAmount;
97
+ };
88
98
  /** All three in the market's underlying. */
89
99
  requested: TokenAmount;
90
100
  minDebt: TokenAmount;
@@ -36,7 +36,9 @@ interface CollateralValuation {
36
36
  /** Liquidation threshold in basis points; 0 for a token the manager refuses. */
37
37
  lt(token: Address): bigint;
38
38
  }
39
- /** {@inheritDoc CollateralValuation} */
40
- declare function collateralValuation(creditAccount: CreditAccountSlice, sdk: OnchainSDK): CollateralValuation;
39
+ /** {@inheritDoc CollateralValuation}
40
+ * Set `safePrices` to false to value the same counted holdings at main prices.
41
+ */
42
+ declare function collateralValuation(creditAccount: CreditAccountSlice, sdk: OnchainSDK, safePrices?: boolean): CollateralValuation;
41
43
  //#endregion
42
44
  export { CollateralValuation, Holding, collateralValuation };
@@ -1,4 +1,5 @@
1
1
  import { Bps, TokenAmount } from "../../../model/primitives.js";
2
+ import { InsufficientPoolLiquidityError } from "../../../model/errors/operation-errors.js";
2
3
  import "../../../model/index.js";
3
4
  import { Asset } from "../../base/types.js";
4
5
  import { MarketSuite } from "../../market/MarketSuite.js";
@@ -28,7 +29,9 @@ import "../../index.js";
28
29
  */
29
30
  declare function assertMarketOperable(suite: CreditSuite): void;
30
31
  /** The pool has to be able to lend what the plan means to draw. */
31
- declare function assertCanBorrow(sdk: OnchainSDK, suite: CreditSuite, amount: bigint): void;
32
+ declare function assertCanBorrow(sdk: OnchainSDK, suite: CreditSuite, amount: bigint, options?: {
33
+ getCollateralLimits?: () => InsufficientPoolLiquidityError["collateralLimits"];
34
+ }): void;
32
35
  /**
33
36
  * What the account is allowed to end up holding more of than it started with.
34
37
  *
@@ -74,18 +74,20 @@ declare class CreditAccountOperationsService extends SDKConstruct {
74
74
  * it as `safePartial`. The second is the one to offer — see
75
75
  * {@link WithdrawCeilings}.
76
76
  *
77
- * Takes no target health factor, unlike {@link maxWithdrawCollateral}. A
78
- * proportional withdrawal leaves the factor where it found it, so there is
79
- * no room to choose: what these answer to is the facade's own threshold,
80
- * which is also what {@link startIntent} refuses against.
77
+ * The default target health factor is the facade's own threshold, which is
78
+ * also what {@link startIntent} refuses against. A form holding the account
79
+ * to something stricter passes its own, as with
80
+ * {@link maxWithdrawCollateral}.
81
81
  *
82
- * @param props - Account slice, the SDK holding its market, and optionally
83
- * the collateral the withdrawal would be funded from
82
+ * @param props - Account slice, the SDK holding its market, optionally the
83
+ * collateral the withdrawal would be funded from, and optionally the health
84
+ * factor the ceiling should leave
84
85
  * @returns The three limits, see {@link WithdrawCeilings} for the gap
85
86
  * between them
86
87
  */
87
88
  maxWithdraw(props: Pick<StartIntentProps, "creditAccount" | "sdk"> & {
88
89
  sourceToken?: Address;
90
+ targetHF?: bigint;
89
91
  }): WithdrawCeilings;
90
92
  /**
91
93
  * Debt a `REPAY` would have to cover to settle the account, in underlying
@@ -121,13 +123,12 @@ declare class CreditAccountOperationsService extends SDKConstruct {
121
123
  leverageBand(props: LeverageBandProps): LeverageBand | undefined;
122
124
  /**
123
125
  * Largest `WITHDRAW_ASSET` amount of one token the account can take out
124
- * while its health factor stays at `targetHF` — the ceiling a
126
+ * while its main and safe health factors clear their targets — the ceiling a
125
127
  * withdraw-collateral form should offer. Thresholds, prices and quota
126
128
  * activity come from the account's market, valued the way the facade values
127
129
  * a call that withdraws collateral; zero debt frees the whole balance.
128
130
  *
129
- * The default is {@link MIN_HF_LIMITED}, the threshold a form holds an
130
- * account to.
131
+ * Defaults are the independent main and safe form thresholds.
131
132
  *
132
133
  * @param props - Account slice, the SDK holding its market, the collateral
133
134
  * to withdraw, and optionally the health factor to leave behind
@@ -136,6 +137,7 @@ declare class CreditAccountOperationsService extends SDKConstruct {
136
137
  maxWithdrawCollateral(props: Pick<StartIntentProps, "creditAccount" | "sdk"> & {
137
138
  token: Address;
138
139
  targetHF?: bigint;
140
+ targetSafeHF?: bigint;
139
141
  }): bigint;
140
142
  /**
141
143
  * Largest loan a given collateral supports at `targetHF`, in the payout
@@ -1,6 +1,11 @@
1
+ import { DebtOutOfRangeError } from "../../../model/errors/operation-errors.js";
2
+ import "../../../model/index.js";
3
+ import { Asset } from "../../base/types.js";
1
4
  import { MaxBorrowAmount } from "../../market/credit/types.js";
5
+ import { CreditSuite } from "../../market/credit/CreditSuite.js";
2
6
  import "../../market/index.js";
3
7
  import { OnchainSDK } from "../../OnchainSDK.js";
8
+ import "../../base/index.js";
4
9
  import { Address } from "viem";
5
10
  //#region src/onchain/accounts/intents/math.d.ts
6
11
  /**
@@ -43,9 +48,20 @@ declare function maxProportionalWithdrawal(position: Position, debtLimits: DebtL
43
48
  /** Total leverage cannot drop below 1x — that would be negative debt. */
44
49
  declare function assertLeverageAtLeastOne(leverage: bigint): void;
45
50
  /**
46
- * Rejects a debt the facade would revert on: zero is always fine (no loan at
47
- * all), anything else has to sit inside `[minDebt, maxDebt]`.
51
+ * Rejects a debt the facade would revert on: anything else has to sit inside
52
+ * `[minDebt, maxDebt]`. Zero is fine only `allowZero`-ing it: an adjustment
53
+ * may end owing nothing, an opening may not.
48
54
  */
49
- declare function assertDebtLimits(sdk: OnchainSDK, debt: bigint, debtLimits: DebtLimits, underlying: Address, maxBorrowAmount: MaxBorrowAmount): void;
55
+ declare function assertDebtLimits(sdk: OnchainSDK, debt: bigint, debtLimits: DebtLimits, underlying: Address, options?: {
56
+ allowZero?: boolean;
57
+ maxBorrowAmount?: MaxBorrowAmount;
58
+ getCollateralLimits?: () => DebtOutOfRangeError["collateralLimits"];
59
+ }): void;
60
+ /** Finds single-token Open amounts whose projected debt fits the market limits. */
61
+ declare function openCollateralForDebtLimits({ suite, collateral, leverage }: {
62
+ suite: CreditSuite;
63
+ collateral: readonly Asset[];
64
+ leverage: bigint;
65
+ }): DebtOutOfRangeError["collateralLimits"];
50
66
  //#endregion
51
- export { DebtLimits, Position, assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage, maxProportionalWithdrawal, proportionalDebt };
67
+ export { DebtLimits, Position, assertDebtLimits, assertLeverageAtLeastOne, debtForLeverage, maxProportionalWithdrawal, openCollateralForDebtLimits, proportionalDebt };
@@ -10,10 +10,12 @@ interface MaxWithdrawCollateralProps {
10
10
  token: Address;
11
11
  /** Health factor the withdrawal has to leave behind, in basis points. */
12
12
  targetHF: bigint;
13
+ /** Safe-price health factor the withdrawal has to leave behind. */
14
+ targetSafeHF: bigint;
13
15
  }
14
16
  /**
15
17
  * Largest amount of one collateral the account can withdraw while its health
16
- * factor stays at or above `targetHF`.
18
+ * factors stay at or above `targetHF` and `targetSafeHF`.
17
19
  *
18
20
  * This is the collateral check solved for one balance, and it counts what that
19
21
  * check counts — see {@link collateralValuation} for it, safe prices included.
@@ -1,8 +1,6 @@
1
1
  import { DelayedIntent } from "../../../model/delayed-intents.js";
2
2
  import "../../../model/index.js";
3
3
  import { ClaimableWithdrawal } from "../withdrawal-compressor/types.js";
4
- import { MaxBorrowAmount } from "../../market/credit/types.js";
5
- import "../../market/index.js";
6
4
  import { OnchainSDK } from "../../OnchainSDK.js";
7
5
  import { AddCollateralIntent, AdjustLeverageIntent, DepositStrategyIntent, RepayStrategyIntent, WithdrawAssetIntent, WithdrawStrategyIntent } from "./types.js";
8
6
  import { DebtLimits } from "./math.js";
@@ -111,7 +109,6 @@ interface AccountView {
111
109
  /** TVL − debt, in underlying. */
112
110
  collateral: bigint;
113
111
  debtLimits: DebtLimits;
114
- maxBorrowAmount: MaxBorrowAmount;
115
112
  balanceOf(token: Address): bigint;
116
113
  /** Oracle conversion; unpriceable tokens contribute 0n. */
117
114
  price(from: Address, to: Address, amount: bigint): bigint;
@@ -12,6 +12,13 @@ interface WithdrawLimitsProps {
12
12
  * names none.
13
13
  */
14
14
  sourceToken?: Address;
15
+ /**
16
+ * Health factor `safePartial` has to leave behind, in basis points. The
17
+ * default is the facade's own threshold — what the collateral guard refuses
18
+ * against, and what the guard quotes back; a form holding the account to
19
+ * something stricter passes its own.
20
+ */
21
+ targetHF?: bigint;
15
22
  }
16
23
  /**
17
24
  * Every limit a `WITHDRAW` answers to, in underlying units.
@@ -7,6 +7,7 @@ interface BorrowLimitArgs {
7
7
  available: bigint;
8
8
  limit: BorrowLimitCause;
9
9
  underlying: Token;
10
+ getCollateralLimits?: () => InsufficientPoolLiquidityError["collateralLimits"];
10
11
  maxBorrowAmount?: bigint;
11
12
  }
12
13
  /**
@@ -9,6 +9,7 @@ interface DebtLimitsArgs {
9
9
  minDebt: bigint;
10
10
  maxDebt: bigint;
11
11
  underlying: Token;
12
+ getCollateralLimits?: () => DebtOutOfRangeError["collateralLimits"];
12
13
  /**
13
14
  * Whether ending with no loan at all is acceptable. The one place the two
14
15
  * callers genuinely disagree: an account being adjusted may end owing
@@ -17,7 +18,7 @@ interface DebtLimitsArgs {
17
18
  */
18
19
  allowZero: boolean;
19
20
  /** From the caller's suite; a caller that raises to throw advises nobody. */
20
- maxBorrowAmount: MaxBorrowAmount;
21
+ maxBorrowAmount?: MaxBorrowAmount;
21
22
  }
22
23
  /** A debt the facade would revert on. */
23
24
  declare function checkDebtLimits(args: DebtLimitsArgs): DebtOutOfRangeError[];
@@ -5,7 +5,7 @@ import { LeverageBand } from "../onchain/accounts/intents/leverage-band.js";
5
5
  import { PoolOperationError } from "../onchain/validation/bundles/checkPoolOperation.js";
6
6
  import { IAnalytics, IAnalyticsByMode } from "./analytics/types.js";
7
7
  import { ILiquidations, ILiquidationsByMode } from "./liquidations/types.js";
8
- import { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, OpenFlowError, OpenStrategyParams, OpenStrategyResult, PoolInput, PositionInput, PrepareOptions, RepayStrategyParams, StrategyInput, StrategyResult, StrategyRoutesResult, WithRouteErrors, WithdrawCollateralParams, WithdrawStrategyParams } from "./prepare/types.js";
8
+ import { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, MaxWithdrawCollateralOptions, OpenFlowError, OpenStrategyParams, OpenStrategyResult, PoolInput, PositionInput, PrepareOptions, RepayStrategyParams, StrategyInput, StrategyResult, StrategyRoutesResult, WithRouteErrors, WithdrawCollateralParams, WithdrawStrategyParams } from "./prepare/types.js";
9
9
  import { ChainOf, PrepareApi } from "./prepare/PrepareApi.js";
10
10
  import "./prepare/index.js";
11
11
  import { AccountPrepareRequest, BorrowPrepareRequest, IOpportunitiesExecute, OpenEmptyPrepareRequest, OpenPrepareRequest, PoolPrepareRequest, PrepareRequest } from "./execute/types.js";
@@ -39,4 +39,4 @@ import { SourceUnavailableError } from "./errors/SourceUnavailableError.js";
39
39
  import { assertSameChains } from "./errors/assertSameChains.js";
40
40
  import { everyChainFailed } from "./errors/everyChainFailed.js";
41
41
  import "./errors/index.js";
42
- export { AbstractNamespace, AccountFlowError, AccountPrepareRequest, AddCollateralParams, AdjustLeverageParams, AllSourcesFailedError, AnalyticsNamespace, BorrowParams, BorrowPrepareRequest, BorrowResult, type BorrowState, ChainOf, ChainRef, CheckOperationProps, type CreditAccountNotEmptyError, type CreditAccountNotFoundError, DEFAULT_MAX_OFFCHAIN_LAG, DEFAULT_MAX_STATE_AGE, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, EnsureFreshChains, type EntityMerger, ExecuteApi, type ExecutionCost, type FilterResult, FinalizeParams, FinalizeResult, GearboxSDK, GearboxSDKOptions, IAnalytics, IAnalyticsByMode, IGearboxSDK, ILiquidations, ILiquidationsByMode, INotices, INoticesByMode, IOpportunities, IOpportunitiesBase, IOpportunitiesByMode, IOpportunitiesExecute, IOpportunitiesOffchainBranch, IOpportunitiesOffchainOnly, IOpportunitiesOnchainBranch, IOpportunitiesOnchainOnly, IOpportunitiesPrepare, IOpportunityMergers, IPositionMergers, IPositions, IPositionsBase, IPositionsByMode, IPositionsOffchainBranch, IPositionsOffchainOnly, IPositionsOnchainBranch, IPositionsOnchainOnly, IPreview, IPreviewByMode, type LeverageBand, LiquidationsNamespace, type ListMerger, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, type MergeListResult, MergedQuery, MissingSourceError, Mode, type MultipleDelayedWithdrawalsError, NamespaceOptions, type NoDelayedRouteError, type NoRecordedIntentError, NoSourceServedError, type NoStrategyTargetCollateralError, OffchainByMode, OffchainSource, OnchainByMode, OnchainSource, OpenEmptyPrepareRequest, OpenFlowError, OpenPrepareRequest, OpenStrategyParams, OpenStrategyResult, type OperationState, OpportunitiesNamespace, type PathLossRate, PlainMultichainSDKOptions, PoolInput, type PoolOperationError, PoolPrepareRequest, PositionInput, PositionsNamespace, PrepareApi, PrepareOptions, PrepareRequest, PreviewNamespace, RepayStrategyParams, type RouteErrors, SourceChainMismatchError, SourceUnavailableError, StrategyInput, StrategyResult, StrategyRoutesResult, type UnexpectedFailureError, type UnsupportedCollateralTokenError, type UnsupportedTokenPairError, type WithPartialState, WithRouteErrors, type WithdrawCeilings, WithdrawCollateralParams, WithdrawStrategyParams, type WithdrawalInProgressError, assertSameChains, creditAccountNotEmpty, creditAccountNotFound, everyChainFailed, filterResponse, mergeChainList, mergeChainOne, noStrategyTargetCollateral, unexpectedFailure };
42
+ export { AbstractNamespace, AccountFlowError, AccountPrepareRequest, AddCollateralParams, AdjustLeverageParams, AllSourcesFailedError, AnalyticsNamespace, BorrowParams, BorrowPrepareRequest, BorrowResult, type BorrowState, ChainOf, ChainRef, CheckOperationProps, type CreditAccountNotEmptyError, type CreditAccountNotFoundError, DEFAULT_MAX_OFFCHAIN_LAG, DEFAULT_MAX_STATE_AGE, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, EnsureFreshChains, type EntityMerger, ExecuteApi, type ExecutionCost, type FilterResult, FinalizeParams, FinalizeResult, GearboxSDK, GearboxSDKOptions, IAnalytics, IAnalyticsByMode, IGearboxSDK, ILiquidations, ILiquidationsByMode, INotices, INoticesByMode, IOpportunities, IOpportunitiesBase, IOpportunitiesByMode, IOpportunitiesExecute, IOpportunitiesOffchainBranch, IOpportunitiesOffchainOnly, IOpportunitiesOnchainBranch, IOpportunitiesOnchainOnly, IOpportunitiesPrepare, IOpportunityMergers, IPositionMergers, IPositions, IPositionsBase, IPositionsByMode, IPositionsOffchainBranch, IPositionsOffchainOnly, IPositionsOnchainBranch, IPositionsOnchainOnly, IPreview, IPreviewByMode, type LeverageBand, LiquidationsNamespace, type ListMerger, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, MaxWithdrawCollateralOptions, type MergeListResult, MergedQuery, MissingSourceError, Mode, type MultipleDelayedWithdrawalsError, NamespaceOptions, type NoDelayedRouteError, type NoRecordedIntentError, NoSourceServedError, type NoStrategyTargetCollateralError, OffchainByMode, OffchainSource, OnchainByMode, OnchainSource, OpenEmptyPrepareRequest, OpenFlowError, OpenPrepareRequest, OpenStrategyParams, OpenStrategyResult, type OperationState, OpportunitiesNamespace, type PathLossRate, PlainMultichainSDKOptions, PoolInput, type PoolOperationError, PoolPrepareRequest, PositionInput, PositionsNamespace, PrepareApi, PrepareOptions, PrepareRequest, PreviewNamespace, RepayStrategyParams, type RouteErrors, SourceChainMismatchError, SourceUnavailableError, StrategyInput, StrategyResult, StrategyRoutesResult, type UnexpectedFailureError, type UnsupportedCollateralTokenError, type UnsupportedTokenPairError, type WithPartialState, WithRouteErrors, type WithdrawCeilings, WithdrawCollateralParams, WithdrawStrategyParams, type WithdrawalInProgressError, assertSameChains, creditAccountNotEmpty, creditAccountNotFound, everyChainFailed, filterResponse, mergeChainList, mergeChainOne, noStrategyTargetCollateral, unexpectedFailure };
@@ -14,7 +14,7 @@ import { LeverageBand } from "../../onchain/accounts/intents/leverage-band.js";
14
14
  import { OpenStrategyState } from "../../onchain/accounts/intents/open-strategy.js";
15
15
  import { PoolOperationError } from "../../onchain/validation/bundles/checkPoolOperation.js";
16
16
  import "../../onchain/index.js";
17
- import { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, DepositStrategyParams, EmptyCreditAccountResult, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, OpenFlowError, OpenStrategyParams, OpenStrategyResult, PoolInput, PositionInput, RepayStrategyParams, StrategyInput, StrategyResult, StrategyRoutesResult, WithRouteErrors, WithdrawCollateralParams, WithdrawStrategyParams } from "./types.js";
17
+ import { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, DepositStrategyParams, EmptyCreditAccountResult, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, MaxWithdrawCollateralOptions, OpenFlowError, OpenStrategyParams, OpenStrategyResult, PoolInput, PositionInput, RepayStrategyParams, StrategyInput, StrategyResult, StrategyRoutesResult, WithRouteErrors, WithdrawCollateralParams, WithdrawStrategyParams } from "./types.js";
18
18
  import { EnsureFreshChains } from "../types.js";
19
19
  import { Address } from "viem";
20
20
  //#region src/sdk/prepare/PrepareApi.d.ts
@@ -89,7 +89,7 @@ declare class PrepareApi extends MultichainConstruct implements IOpportunitiesPr
89
89
  /**
90
90
  * {@inheritDoc IOpportunitiesPrepare.maxWithdraw}
91
91
  **/
92
- maxWithdraw(position: PositionInput, sourceToken?: Address): Promise<WithdrawCeilings>;
92
+ maxWithdraw(position: PositionInput, sourceToken?: Address, targetHF?: bigint): Promise<WithdrawCeilings>;
93
93
  /**
94
94
  * {@inheritDoc IOpportunitiesPrepare.repayStrategy}
95
95
  **/
@@ -121,7 +121,7 @@ declare class PrepareApi extends MultichainConstruct implements IOpportunitiesPr
121
121
  /**
122
122
  * {@inheritDoc IOpportunitiesPrepare.maxWithdrawCollateral}
123
123
  **/
124
- maxWithdrawCollateral(position: PositionInput, token: Address, targetHF?: bigint): Promise<bigint>;
124
+ maxWithdrawCollateral(position: PositionInput, token: Address, options?: MaxWithdrawCollateralOptions): Promise<bigint>;
125
125
  /**
126
126
  * {@inheritDoc IOpportunitiesPrepare.maxBorrow}
127
127
  **/
@@ -4,6 +4,6 @@ import { ExecutionCost, OperationState, PathLossRate, RouteErrors, WithPartialSt
4
4
  import { BorrowState } from "../../onchain/accounts/intents/borrow.js";
5
5
  import { LeverageBand } from "../../onchain/accounts/intents/leverage-band.js";
6
6
  import { PoolOperationError } from "../../onchain/validation/bundles/checkPoolOperation.js";
7
- import { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, OpenFlowError, OpenStrategyParams, OpenStrategyResult, PoolInput, PositionInput, PrepareOptions, RepayStrategyParams, StrategyInput, StrategyResult, StrategyRoutesResult, WithRouteErrors, WithdrawCollateralParams, WithdrawStrategyParams } from "./types.js";
7
+ import { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, MaxWithdrawCollateralOptions, OpenFlowError, OpenStrategyParams, OpenStrategyResult, PoolInput, PositionInput, PrepareOptions, RepayStrategyParams, StrategyInput, StrategyResult, StrategyRoutesResult, WithRouteErrors, WithdrawCollateralParams, WithdrawStrategyParams } from "./types.js";
8
8
  import { ChainOf, PrepareApi } from "./PrepareApi.js";
9
- export { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, type BorrowState, ChainOf, type CreditAccountNotEmptyError, type CreditAccountNotFoundError, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, type ExecutionCost, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, type LeverageBand, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, type MultipleDelayedWithdrawalsError, type NoDelayedRouteError, type NoRecordedIntentError, type NoStrategyTargetCollateralError, OpenFlowError, OpenStrategyParams, OpenStrategyResult, type OperationState, type PathLossRate, PoolInput, type PoolOperationError, PositionInput, PrepareApi, PrepareOptions, RepayStrategyParams, type RouteErrors, StrategyInput, StrategyResult, StrategyRoutesResult, type UnexpectedFailureError, type UnsupportedCollateralTokenError, type UnsupportedTokenPairError, type WithPartialState, WithRouteErrors, type WithdrawCeilings, WithdrawCollateralParams, WithdrawStrategyParams, type WithdrawalInProgressError, creditAccountNotEmpty, creditAccountNotFound, noStrategyTargetCollateral, unexpectedFailure };
9
+ export { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, type BorrowState, ChainOf, type CreditAccountNotEmptyError, type CreditAccountNotFoundError, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, type ExecutionCost, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, type LeverageBand, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, MaxWithdrawCollateralOptions, type MultipleDelayedWithdrawalsError, type NoDelayedRouteError, type NoRecordedIntentError, type NoStrategyTargetCollateralError, OpenFlowError, OpenStrategyParams, OpenStrategyResult, type OperationState, type PathLossRate, PoolInput, type PoolOperationError, PositionInput, PrepareApi, PrepareOptions, RepayStrategyParams, type RouteErrors, StrategyInput, StrategyResult, StrategyRoutesResult, type UnexpectedFailureError, type UnsupportedCollateralTokenError, type UnsupportedTokenPairError, type WithPartialState, WithRouteErrors, type WithdrawCeilings, WithdrawCollateralParams, WithdrawStrategyParams, type WithdrawalInProgressError, creditAccountNotEmpty, creditAccountNotFound, noStrategyTargetCollateral, unexpectedFailure };
@@ -19,6 +19,12 @@ import { PoolOperationError } from "../../onchain/validation/bundles/checkPoolOp
19
19
  import "../../onchain/index.js";
20
20
  import { Address } from "viem";
21
21
  //#region src/sdk/prepare/types.d.ts
22
+ interface MaxWithdrawCollateralOptions {
23
+ /** Main-price HF threshold, in basis points; defaults to 10101. */
24
+ targetHF?: bigint;
25
+ /** Safe-price HF threshold, in basis points; defaults to 10001. */
26
+ targetSafeHF?: bigint;
27
+ }
22
28
  /**
23
29
  * What any operation on an existing account can answer with: the engine's
24
30
  * shared guards, the missing account, and a wrapped crash.
@@ -663,6 +669,11 @@ interface IOpportunitiesPrepare {
663
669
  * amounts; omitted, both this and the flow itself reach for the account's
664
670
  * largest non-phantom balance.
665
671
  *
672
+ * `targetHF` is the health factor `safePartial` has to leave behind, in
673
+ * basis points. The default is the facade's own threshold; a form holding
674
+ * the account to something stricter passes its own, so the ceiling it
675
+ * offers clears its own bar rather than landing a basis point under it.
676
+ *
666
677
  * Taking everything out needs none of the figures: send `MAX_UINT256` to
667
678
  * {@link withdrawStrategy} and the exit is what runs, named rather than
668
679
  * priced.
@@ -670,7 +681,7 @@ interface IOpportunitiesPrepare {
670
681
  * A bare read: it answers its numbers, and throws on an account or a chain
671
682
  * the SDK does not hold.
672
683
  **/
673
- maxWithdraw(position: PositionInput, sourceToken?: Address): Promise<WithdrawCeilings>;
684
+ maxWithdraw(position: PositionInput, sourceToken?: Address, targetHF?: bigint): Promise<WithdrawCeilings>;
674
685
  /**
675
686
  * Paying debt down with funds from the wallet: collateral stays where it is,
676
687
  * so net value grows by what was repaid, leverage falls and the health factor
@@ -766,13 +777,13 @@ interface IOpportunitiesPrepare {
766
777
  * requires. Zero debt frees the whole balance — the ceiling a
767
778
  * withdraw-collateral form should offer.
768
779
  *
769
- * `targetHF` names the health factor to leave the account at, in basis
770
- * points; omitted, the SDK holds it to the threshold a form would.
780
+ * Options name independent main and safe price health-factor thresholds in
781
+ * basis points. The SDK defaults to the form thresholds and adds its margin.
771
782
  *
772
783
  * A bare read: it answers its number, and throws on an account or a chain
773
784
  * the SDK does not hold.
774
785
  **/
775
- maxWithdrawCollateral(position: PositionInput, token: Address, targetHF?: bigint): Promise<bigint>;
786
+ maxWithdrawCollateral(position: PositionInput, token: Address, options?: MaxWithdrawCollateralOptions): Promise<bigint>;
776
787
  /**
777
788
  * Largest loan {@link borrow} can draw against a given collateral while the
778
789
  * account stays safely collateralised, in the payout token's units — the
@@ -829,4 +840,4 @@ interface IOpportunitiesPrepare {
829
840
  finalize(position: PositionInput, params: FinalizeParams): Promise<SDKReturn<FinalizeResult, (AccountFlowError | NoRecordedIntentError | NoDelayedRouteError | WithdrawalInProgressError | UnsupportedTokenPairError) & WithPartialState<OperationState>>>;
830
841
  }
831
842
  //#endregion
832
- export { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, type BorrowState, type CreditAccountNotEmptyError, type CreditAccountNotFoundError, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, type ExecutionCost, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, type LeverageBand, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, type MultipleDelayedWithdrawalsError, type NoDelayedRouteError, type NoRecordedIntentError, type NoStrategyTargetCollateralError, OpenFlowError, OpenStrategyParams, OpenStrategyResult, type OperationState, type PathLossRate, PoolInput, type PoolOperationError, PositionInput, PrepareOptions, RepayStrategyParams, type RouteErrors, StrategyInput, StrategyResult, StrategyRoutesResult, type UnexpectedFailureError, type UnsupportedCollateralTokenError, type UnsupportedTokenPairError, type WithPartialState, WithRouteErrors, type WithdrawCeilings, WithdrawCollateralParams, WithdrawStrategyParams, type WithdrawalInProgressError };
843
+ export { AccountFlowError, AddCollateralParams, AdjustLeverageParams, BorrowParams, BorrowResult, type BorrowState, type CreditAccountNotEmptyError, type CreditAccountNotFoundError, DelayedStrategyResult, DepositStrategyParams, EmptyCreditAccountResult, type ExecutionCost, FinalizeParams, FinalizeResult, IOpportunitiesPrepare, type LeverageBand, LpParams, LpRedeemParams, LpResult, LpState, MaxBorrowParams, MaxWithdrawCollateralOptions, type MultipleDelayedWithdrawalsError, type NoDelayedRouteError, type NoRecordedIntentError, type NoStrategyTargetCollateralError, OpenFlowError, OpenStrategyParams, OpenStrategyResult, type OperationState, type PathLossRate, PoolInput, type PoolOperationError, PositionInput, PrepareOptions, RepayStrategyParams, type RouteErrors, StrategyInput, StrategyResult, StrategyRoutesResult, type UnexpectedFailureError, type UnsupportedCollateralTokenError, type UnsupportedTokenPairError, type WithPartialState, WithRouteErrors, type WithdrawCeilings, WithdrawCollateralParams, WithdrawStrategyParams, type WithdrawalInProgressError };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "17.6.1",
3
+ "version": "17.7.0",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {