@gearbox-protocol/sdk 16.3.2 → 16.4.0-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 (70) hide show
  1. package/dist/cjs/dev/midasUtils.js +11 -46
  2. package/dist/cjs/model/errors/index.js +1 -0
  3. package/dist/cjs/model/errors/operation-errors.js +9 -0
  4. package/dist/cjs/model/index.js +1 -0
  5. package/dist/cjs/onchain/accounts/intents/collateral-money.js +41 -0
  6. package/dist/cjs/onchain/accounts/intents/guards.js +15 -3
  7. package/dist/cjs/onchain/accounts/intents/index.js +21 -18
  8. package/dist/cjs/onchain/accounts/intents/maxWithdrawCollateral.js +12 -38
  9. package/dist/cjs/onchain/accounts/intents/realize.js +10 -2
  10. package/dist/cjs/onchain/accounts/intents/tail.js +1 -1
  11. package/dist/cjs/onchain/accounts/intents/withdraw-limits.js +97 -0
  12. package/dist/cjs/onchain/index.js +2 -0
  13. package/dist/cjs/onchain/market/adapters/abi/conctructorAbi.js +1 -1
  14. package/dist/cjs/onchain/preview/preview/previewOpenStrategyPosition.js +10 -16
  15. package/dist/cjs/onchain/preview/preview/previewOperation.js +19 -11
  16. package/dist/cjs/onchain/preview/preview/replayMulticall.js +4 -3
  17. package/dist/cjs/onchain/validation/bundles/checkCollateralFunding.js +3 -3
  18. package/dist/cjs/onchain/validation/bundles/checkCreditOperation.js +4 -3
  19. package/dist/cjs/onchain/validation/bundles/checkRWAOpening.js +1 -2
  20. package/dist/cjs/onchain/validation/checkOperation.js +0 -1
  21. package/dist/cjs/onchain/validation/checks/checkReservePriceLimited.js +30 -0
  22. package/dist/cjs/onchain/validation/checks/index.js +2 -0
  23. package/dist/cjs/onchain/validation/index.js +2 -0
  24. package/dist/cjs/sdk/prepare/PrepareApi.js +3 -2
  25. package/dist/esm/dev/midasUtils.js +12 -47
  26. package/dist/esm/model/errors/index.js +2 -2
  27. package/dist/esm/model/errors/operation-errors.js +9 -1
  28. package/dist/esm/model/index.js +2 -2
  29. package/dist/esm/onchain/accounts/intents/collateral-money.js +40 -0
  30. package/dist/esm/onchain/accounts/intents/guards.js +15 -3
  31. package/dist/esm/onchain/accounts/intents/index.js +21 -18
  32. package/dist/esm/onchain/accounts/intents/maxWithdrawCollateral.js +12 -38
  33. package/dist/esm/onchain/accounts/intents/realize.js +10 -2
  34. package/dist/esm/onchain/accounts/intents/tail.js +1 -1
  35. package/dist/esm/onchain/accounts/intents/withdraw-limits.js +95 -0
  36. package/dist/esm/onchain/index.js +2 -1
  37. package/dist/esm/onchain/market/adapters/abi/conctructorAbi.js +1 -1
  38. package/dist/esm/onchain/preview/preview/previewOpenStrategyPosition.js +11 -17
  39. package/dist/esm/onchain/preview/preview/previewOperation.js +19 -11
  40. package/dist/esm/onchain/preview/preview/replayMulticall.js +4 -3
  41. package/dist/esm/onchain/validation/bundles/checkCollateralFunding.js +3 -3
  42. package/dist/esm/onchain/validation/bundles/checkCreditOperation.js +4 -3
  43. package/dist/esm/onchain/validation/bundles/checkRWAOpening.js +1 -2
  44. package/dist/esm/onchain/validation/checkOperation.js +0 -1
  45. package/dist/esm/onchain/validation/checks/checkReservePriceLimited.js +29 -0
  46. package/dist/esm/onchain/validation/checks/index.js +2 -1
  47. package/dist/esm/onchain/validation/index.js +2 -1
  48. package/dist/esm/sdk/prepare/PrepareApi.js +3 -2
  49. package/dist/types/dev/midasUtils.d.ts +3 -4
  50. package/dist/types/model/errors/index.d.ts +2 -2
  51. package/dist/types/model/errors/operation-errors.d.ts +41 -1
  52. package/dist/types/model/index.d.ts +3 -3
  53. package/dist/types/model/previews.d.ts +11 -20
  54. package/dist/types/onchain/accounts/intents/collateral-money.d.ts +42 -0
  55. package/dist/types/onchain/accounts/intents/guards.d.ts +18 -2
  56. package/dist/types/onchain/accounts/intents/index.d.ts +23 -14
  57. package/dist/types/onchain/accounts/intents/maxWithdrawCollateral.d.ts +3 -8
  58. package/dist/types/onchain/accounts/intents/types.d.ts +26 -4
  59. package/dist/types/onchain/accounts/intents/withdraw-limits.d.ts +80 -0
  60. package/dist/types/onchain/index.d.ts +2 -1
  61. package/dist/types/onchain/preview/preview/previewOpenStrategyPosition.d.ts +5 -3
  62. package/dist/types/onchain/preview/preview/replayMulticall.d.ts +8 -7
  63. package/dist/types/onchain/validation/checks/checkDebtLimits.d.ts +2 -2
  64. package/dist/types/onchain/validation/checks/checkReservePriceLimited.d.ts +31 -0
  65. package/dist/types/onchain/validation/checks/index.d.ts +2 -1
  66. package/dist/types/onchain/validation/index.d.ts +2 -1
  67. package/dist/types/onchain/validation/raise.d.ts +2 -2
  68. package/dist/types/sdk/prepare/PrepareApi.d.ts +1 -1
  69. package/dist/types/sdk/prepare/types.d.ts +23 -16
  70. package/package.json +1 -1
@@ -34,9 +34,13 @@ async function previewOperation(sdk, input, options, creditAccount) {
34
34
  if (!parsed.ok) return parsed;
35
35
  const operation = parsed.data;
36
36
  if (require_onchain_preview_parse_types.isPoolOperation(operation)) return require_onchain_preview_preview_previewPoolPositionOperation.previewPoolPositionOperation(sdk, operation, options);
37
- if (operation.operation === "OpenCreditAccount" || operation.operation === "RWAOpenCreditAccount") return require_onchain_preview_preview_previewOpenStrategyPosition.previewOpenStrategyPosition(sdk, input, operation);
37
+ if (operation.operation === "OpenCreditAccount" || operation.operation === "RWAOpenCreditAccount") {
38
+ const replayed = require_onchain_preview_preview_replayMulticall.replayMulticall(sdk, operation);
39
+ if (!replayed.ok) return replayed;
40
+ return require_onchain_preview_preview_previewOpenStrategyPosition.previewOpenStrategyPosition(sdk, input, operation, replayed.data);
41
+ }
38
42
  if (operation.operation === "CloseCreditAccount") {
39
- const resolved = await resolveCreditAccount(sdk, operation, options, creditAccount);
43
+ const resolved = await resolveCreditAccount(sdk, operation.creditAccount, options, creditAccount);
40
44
  if (!resolved.ok) return resolved;
41
45
  const replayed = require_onchain_preview_preview_replayMulticall.replayMulticall(sdk, operation, resolved.data);
42
46
  if (!replayed.ok) return replayed;
@@ -48,7 +52,7 @@ async function previewOperation(sdk, input, options, creditAccount) {
48
52
  return preview;
49
53
  }
50
54
  if (operation.operation === "MultiCall" || operation.operation === "BotMulticall" || operation.operation === "RWAMulticall") {
51
- const resolved = await resolveCreditAccount(sdk, operation, options, creditAccount);
55
+ const resolved = await resolveCreditAccount(sdk, operation.creditAccount, options, creditAccount);
52
56
  if (!resolved.ok) return resolved;
53
57
  const replayed = require_onchain_preview_preview_replayMulticall.replayMulticall(sdk, operation, resolved.data);
54
58
  if (!replayed.ok) return replayed;
@@ -65,20 +69,24 @@ async function previewOperation(sdk, input, options, creditAccount) {
65
69
  * injected state when present, otherwise fetches it from the credit account
66
70
  * compressor.
67
71
  */
68
- async function resolveCreditAccount(sdk, operation, options, creditAccount) {
69
- let resolved = creditAccount;
70
- if (!resolved) resolved = await sdk.accounts.getCreditAccountData(operation.creditAccount, options?.blockNumber);
71
- if (!resolved) return require_model_result.sdkErr(require_model_errors_prepare_errors.creditAccountNotFound(operation.creditAccount));
72
+ async function resolveCreditAccount(sdk, address, options, data) {
73
+ let resolved = data;
74
+ if (!resolved) resolved = await sdk.accounts.getCreditAccountData(address, options?.blockNumber);
75
+ if (!resolved) return require_model_result.sdkErr(require_model_errors_prepare_errors.creditAccountNotFound(address));
72
76
  return require_model_result.sdkOk(resolved);
73
77
  }
74
78
  /**
75
79
  * Previews a plain/bot/RWA multicall: classifies the instant preview
76
- * (zero-debt closure/repay vs adjustment) and, when the multicall requests a
77
- * delayed withdrawal, wraps the instant preview into a
78
- * `DelayedCreditAccountOperation` together with the best-effort preview of
79
- * the state after the withdrawal is claimed.
80
+ * (reopening a zero-debt account, zero-debt closure/repay, or adjustment)
81
+ * and, when the multicall requests a delayed withdrawal, wraps the instant
82
+ * preview into a `DelayedCreditAccountOperation` together with the
83
+ * best-effort preview of the state after the withdrawal is claimed.
84
+ *
85
+ * A reopening is reported as `OpenCreditAccount` and never as a delayed
86
+ * withdrawal: an opening requests no redemption.
80
87
  */
81
88
  async function previewMulticallOperation(sdk, input, operation, replay, blockNumber) {
89
+ if (replay.before.totalDebt === 0n && replay.before.quotas.toAssets(0n).length === 0 && replay.after.account.totalDebt > 0n) return require_onchain_preview_preview_previewOpenStrategyPosition.previewOpenStrategyPosition(sdk, input, operation, replay);
82
90
  let instantPreview;
83
91
  if (require_onchain_preview_preview_detectCloseOrRepay.isCloseOrRepay(operation.multicall)) {
84
92
  const instant = require_onchain_preview_preview_previewExitOrRepayStrategyPosition.previewExitOrRepayStrategyPosition(sdk, input, operation, false, replay);
@@ -5,11 +5,12 @@ const require_onchain_preview_preview_CreditAccountState = require("./CreditAcco
5
5
  const require_onchain_preview_preview_replayInnerOperations = require("./replayInnerOperations.js");
6
6
  //#region src/onchain/preview/preview/replayMulticall.ts
7
7
  /**
8
- * Replays the operation's multicall over the account's pre-resolved
9
- * pre-state via {@link replayInnerOperations}.
8
+ * Replays the operation's multicall via {@link replayInnerOperations}.
9
+ * When `creditAccount` is omitted, the seed is
10
+ * {@link CreditAccountState.beforeOpen} (a fresh opening).
10
11
  */
11
12
  function replayMulticall(sdk, operation, creditAccount) {
12
- const before = require_onchain_preview_preview_CreditAccountState.CreditAccountState.fromCreditAccountData(creditAccount);
13
+ const before = creditAccount ? require_onchain_preview_preview_CreditAccountState.CreditAccountState.fromCreditAccountData(creditAccount) : require_onchain_preview_preview_CreditAccountState.CreditAccountState.beforeOpen(operation.creditManager, sdk.marketRegister.findByCreditManager(operation.creditManager).underlying);
13
14
  const after = require_onchain_preview_preview_replayInnerOperations.makeReplayState(before.clone());
14
15
  const error = require_onchain_preview_preview_replayInnerOperations.replayInnerOperations(sdk, operation.multicall, after);
15
16
  if (error) return require_model_result.sdkErr(error);
@@ -23,13 +23,13 @@ async function checkCollateralFunding(input) {
23
23
  if (held.size === 0) return [];
24
24
  let spender;
25
25
  try {
26
- if (preview.operation === "OpenCreditAccount" || preview.operation === "RWAOpenCreditAccount") spender = await sdk.accounts.getApprovalAddress({
26
+ if (preview.creditAccount) spender = await sdk.accounts.getApprovalAddress({
27
27
  creditManager: preview.creditManager,
28
- borrower: sender
28
+ creditAccount: preview.creditAccount
29
29
  });
30
30
  else spender = await sdk.accounts.getApprovalAddress({
31
31
  creditManager: preview.creditManager,
32
- creditAccount: preview.creditAccount
32
+ borrower: sender
33
33
  });
34
34
  } catch (cause) {
35
35
  return [require_model_errors_prepare_errors.unexpectedFailure(cause, "resolve the approval address")];
@@ -26,7 +26,8 @@ async function checkCreditOperation(args) {
26
26
  const suite = sdk.marketRegister.findCreditManager(preview.creditManager);
27
27
  const market = suite.market;
28
28
  const underlying = require_onchain_validation_helpers_token.toToken(sdk, market.pool.underlying);
29
- const isOpening = preview.operation === "OpenCreditAccount" || preview.operation === "RWAOpenCreditAccount";
29
+ const isOpening = preview.operation === "OpenCreditAccount";
30
+ const isEmptyOpening = preview.operation === "OpenCreditAccount" && preview.totalDebt.value === 0n && preview.collateralAdded.length === 0 && preview.quotas.length === 0;
30
31
  const protocol = [
31
32
  ...require_onchain_validation_bundles_checkMarket.checkMarket(suite),
32
33
  ...require_onchain_validation_checks_checkDebtLimits.checkDebtLimits({
@@ -34,7 +35,7 @@ async function checkCreditOperation(args) {
34
35
  minDebt: suite.creditFacade.minDebt,
35
36
  maxDebt: suite.creditFacade.maxDebt,
36
37
  underlying,
37
- allowZero: !isOpening,
38
+ allowZero: !isOpening || isEmptyOpening,
38
39
  maxBorrowAmount: suite.maxBorrowAmount()
39
40
  }),
40
41
  ...require_onchain_validation_bundles_checkIncreaseDebt.checkIncreaseDebt(suite, preview, underlying),
@@ -52,7 +53,7 @@ async function checkCreditOperation(args) {
52
53
  preview,
53
54
  sender,
54
55
  blockNumber
55
- }), preview.operation === "OpenCreditAccount" || preview.operation === "RWAOpenCreditAccount" ? require_onchain_validation_bundles_checkRWAOpening.checkRWAOpening({
56
+ }), isOpening ? require_onchain_validation_bundles_checkRWAOpening.checkRWAOpening({
56
57
  sdk,
57
58
  preview,
58
59
  sender
@@ -12,13 +12,12 @@ async function checkRWAOpening(input) {
12
12
  if (!nft) return [];
13
13
  const gated = new require_onchain_utils_AddressSet.AddressSet(await nft.getTokens());
14
14
  const candidates = new require_onchain_utils_AddressSet.AddressSet([...preview.collateralAdded.map((a) => a.token.address), ...preview.quotas.map((q) => q.token.address)]);
15
- const providedArgs = preview.operation === "RWAOpenCreditAccount" ? preview.rwaArgs : void 0;
16
15
  return (await Promise.all([...candidates].filter((token) => gated.has(token)).map((token) => require_onchain_validation_bundles_checkRWAOpenRequirements.checkRWAOpenRequirements({
17
16
  sdk,
18
17
  wallet: sender,
19
18
  creditManager: preview.creditManager,
20
19
  token,
21
- providedArgs
20
+ providedArgs: preview.rwaArgs
22
21
  })))).flat();
23
22
  }
24
23
  //#endregion
@@ -43,7 +43,6 @@ async function checkOperation(input, options = {}) {
43
43
  sender
44
44
  }, options);
45
45
  case "OpenCreditAccount":
46
- case "RWAOpenCreditAccount":
47
46
  case "AdjustCreditAccount": return require_onchain_validation_bundles_checkCreditOperation.checkCreditOperation({
48
47
  sdk,
49
48
  preview,
@@ -0,0 +1,30 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_model_errors_operation_errors = require("../../../model/errors/operation-errors.js");
3
+ require("../../../model/index.js");
4
+ //#region src/onchain/validation/checks/checkReservePriceLimited.ts
5
+ /**
6
+ * Whether a failed collateral check is the reserve price feed's doing.
7
+ *
8
+ * A call that hands funds over is weighed at safe prices — `min` of a token's
9
+ * two feeds, and nothing at all where governance registered no reserve feed —
10
+ * so an account that covers its debt at the main feed can still be refused.
11
+ * The two are worth telling apart: a position that is genuinely too small is
12
+ * fixed by adding collateral or requesting less, while this one is a valuation
13
+ * the account does not control, and requesting less only helps as far as
14
+ * `withdrawable` says it does.
15
+ *
16
+ * Runs after `checkCollateralised` and answers only when that one refused, so
17
+ * the caller keeps its own threshold rather than restating it here.
18
+ */
19
+ function checkReservePriceLimited(args) {
20
+ const { healthFactor, atMainPrices, healthFactorThreshold, withdrawable } = args;
21
+ if (healthFactor >= healthFactorThreshold || atMainPrices < healthFactorThreshold) return [];
22
+ return [require_model_errors_operation_errors.reservePriceLimited({
23
+ healthFactor,
24
+ atMainPrices,
25
+ healthFactorThreshold,
26
+ withdrawable
27
+ })];
28
+ }
29
+ //#endregion
30
+ exports.checkReservePriceLimited = checkReservePriceLimited;
@@ -14,6 +14,7 @@ const require_onchain_validation_checks_checkPoolPaused = require("./checkPoolPa
14
14
  const require_onchain_validation_checks_checkPoolSunset = require("./checkPoolSunset.js");
15
15
  const require_onchain_validation_checks_checkQuotaCount = require("./checkQuotaCount.js");
16
16
  const require_onchain_validation_checks_checkQuotaLimit = require("./checkQuotaLimit.js");
17
+ const require_onchain_validation_checks_checkReservePriceLimited = require("./checkReservePriceLimited.js");
17
18
  exports.checkBorrowLimit = require_onchain_validation_checks_checkBorrowLimit.checkBorrowLimit;
18
19
  exports.checkCollateralised = require_onchain_validation_checks_checkCollateralised.checkCollateralised;
19
20
  exports.checkCreditAccountFrozen = require_onchain_validation_checks_checkCreditAccountFrozen.checkCreditAccountFrozen;
@@ -29,3 +30,4 @@ exports.checkPoolPaused = require_onchain_validation_checks_checkPoolPaused.chec
29
30
  exports.checkPoolSunset = require_onchain_validation_checks_checkPoolSunset.checkPoolSunset;
30
31
  exports.checkQuotaCount = require_onchain_validation_checks_checkQuotaCount.checkQuotaCount;
31
32
  exports.checkQuotaLimit = require_onchain_validation_checks_checkQuotaLimit.checkQuotaLimit;
33
+ exports.checkReservePriceLimited = require_onchain_validation_checks_checkReservePriceLimited.checkReservePriceLimited;
@@ -18,6 +18,7 @@ const require_onchain_validation_checks_checkPoolPaused = require("./checks/chec
18
18
  const require_onchain_validation_checks_checkPoolSunset = require("./checks/checkPoolSunset.js");
19
19
  const require_onchain_validation_checks_checkQuotaCount = require("./checks/checkQuotaCount.js");
20
20
  const require_onchain_validation_checks_checkQuotaLimit = require("./checks/checkQuotaLimit.js");
21
+ const require_onchain_validation_checks_checkReservePriceLimited = require("./checks/checkReservePriceLimited.js");
21
22
  require("./checks/index.js");
22
23
  const require_onchain_validation_bundles_checkAccountQuotas = require("./bundles/checkAccountQuotas.js");
23
24
  const require_onchain_validation_bundles_checkWalletAllowance = require("./bundles/checkWalletAllowance.js");
@@ -77,6 +78,7 @@ exports.checkQuotaCount = require_onchain_validation_checks_checkQuotaCount.chec
77
78
  exports.checkQuotaLimit = require_onchain_validation_checks_checkQuotaLimit.checkQuotaLimit;
78
79
  exports.checkRWAOpenRequirements = require_onchain_validation_bundles_checkRWAOpenRequirements.checkRWAOpenRequirements;
79
80
  exports.checkRWAOpening = require_onchain_validation_bundles_checkRWAOpening.checkRWAOpening;
81
+ exports.checkReservePriceLimited = require_onchain_validation_checks_checkReservePriceLimited.checkReservePriceLimited;
80
82
  exports.checkSimulation = require_onchain_validation_checkSimulation.checkSimulation;
81
83
  exports.checkWallet = require_onchain_validation_bundles_checkWallet.checkWallet;
82
84
  exports.checkWalletAllowance = require_onchain_validation_bundles_checkWalletAllowance.checkWalletAllowance;
@@ -259,12 +259,13 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
259
259
  /**
260
260
  * {@inheritDoc IOpportunitiesPrepare.maxWithdraw}
261
261
  **/
262
- async maxWithdraw(position) {
262
+ async maxWithdraw(position, sourceToken) {
263
263
  const sdk = await this.#chain(position.chainId);
264
264
  const creditAccount = await this.#account(sdk, position);
265
265
  return service(sdk).maxWithdraw({
266
266
  creditAccount,
267
- sdk
267
+ sdk,
268
+ sourceToken
268
269
  });
269
270
  }
270
271
  /**
@@ -1,5 +1,5 @@
1
1
  import { writeAndWait } from "./kycUtils.js";
2
- import { parseAbi, parseEther, toFunctionSelector } from "viem";
2
+ import { parseAbi, parseEther } from "viem";
3
3
  //#region src/dev/midasUtils.ts
4
4
  /**
5
5
  * Midas vaults inherit their own `Pausable`, whose global pause is guarded by
@@ -9,24 +9,14 @@ const iMidasPausableVaultAbi = parseAbi([
9
9
  "function paused() external view returns (bool)",
10
10
  "function pause() external",
11
11
  "function unpause() external",
12
- "function fnPaused(bytes4 fn) external view returns (bool)",
13
- "function pauseFn(bytes4 fn) external",
14
- "function unpauseFn(bytes4 fn) external",
15
12
  "function pauseAdminRole() external view returns (bytes32)",
16
13
  "function accessControl() external view returns (address)"
17
14
  ]);
18
15
  const iMidasAccessControlAbi = parseAbi(["function hasRole(bytes32 role, address account) external view returns (bool)", "function grantRole(bytes32 role, address account) external"]);
19
16
  /**
20
- * Selector for `DepositVault.depositInstant(address,uint256,uint256,bytes32)`,
21
- * the 4-arg mint Gearbox adapters encode. Distinct from the custom-recipient
22
- * overload.
23
- */
24
- const DEPOSIT_INSTANT_SELECTOR = toFunctionSelector("depositInstant(address,uint256,uint256,bytes32)");
25
- /**
26
- * Unpauses a Midas issuance vault on an anvil fork so that `depositInstant`
27
- * stops reverting with `Pausable: paused` (global) or `Pausable: fn paused`
28
- * (per-selector), and returns a callback that restores the original pause
29
- * state of each layer that was cleared.
17
+ * Unpauses a globally paused Midas issuance vault on an anvil fork, so that
18
+ * `depositInstant` stops reverting with `Pausable: paused`, and returns a
19
+ * callback that restores the original pause state.
30
20
  *
31
21
  * Impersonates `admin` and grants it `pauseAdminRole()` when missing, same as
32
22
  * `greenlistMidasGateway` does with the greenlist roles. The grant is not
@@ -34,20 +24,11 @@ const DEPOSIT_INSTANT_SELECTOR = toFunctionSelector("depositInstant(address,uint
34
24
  */
35
25
  async function unpauseMidasIssuanceVault(props) {
36
26
  const { anvil, vault, admin, logger } = props;
37
- const [paused, depositInstantPaused] = await anvil.multicall({
38
- allowFailure: false,
39
- contracts: [{
40
- address: vault,
41
- abi: iMidasPausableVaultAbi,
42
- functionName: "paused"
43
- }, {
44
- address: vault,
45
- abi: iMidasPausableVaultAbi,
46
- functionName: "fnPaused",
47
- args: [DEPOSIT_INSTANT_SELECTOR]
48
- }]
49
- });
50
- if (!paused && !depositInstantPaused) {
27
+ if (!await anvil.readContract({
28
+ address: vault,
29
+ abi: iMidasPausableVaultAbi,
30
+ functionName: "paused"
31
+ })) {
51
32
  logger?.debug(`midas: issuance vault ${vault} is not paused`);
52
33
  return async () => {};
53
34
  }
@@ -69,7 +50,7 @@ async function unpauseMidasIssuanceVault(props) {
69
50
  functionName: "hasRole",
70
51
  args: [pauseAdminRole, admin]
71
52
  });
72
- logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}` + (paused ? ", global" : "") + (depositInstantPaused ? ", depositInstant" : ""));
53
+ logger?.debug(`midas: unpausing issuance vault ${vault} as ${admin}, access control ${accessControl}, pause admin role ${pauseAdminRole}`);
73
54
  await anvil.impersonateAccount({ address: admin });
74
55
  try {
75
56
  await anvil.setBalance({
@@ -87,21 +68,13 @@ async function unpauseMidasIssuanceVault(props) {
87
68
  });
88
69
  logger?.debug(`midas: granted pause admin role to ${admin}`);
89
70
  }
90
- if (paused) await writeAndWait(anvil, {
71
+ await writeAndWait(anvil, {
91
72
  account: admin,
92
73
  chain: anvil.chain,
93
74
  address: vault,
94
75
  abi: iMidasPausableVaultAbi,
95
76
  functionName: "unpause"
96
77
  });
97
- if (depositInstantPaused) await writeAndWait(anvil, {
98
- account: admin,
99
- chain: anvil.chain,
100
- address: vault,
101
- abi: iMidasPausableVaultAbi,
102
- functionName: "unpauseFn",
103
- args: [DEPOSIT_INSTANT_SELECTOR]
104
- });
105
78
  } finally {
106
79
  await anvil.stopImpersonatingAccount({ address: admin });
107
80
  }
@@ -116,21 +89,13 @@ async function unpauseMidasIssuanceVault(props) {
116
89
  address: admin,
117
90
  value: parseEther("100")
118
91
  });
119
- if (paused) await writeAndWait(anvil, {
92
+ await writeAndWait(anvil, {
120
93
  account: admin,
121
94
  chain: anvil.chain,
122
95
  address: vault,
123
96
  abi: iMidasPausableVaultAbi,
124
97
  functionName: "pause"
125
98
  });
126
- if (depositInstantPaused) await writeAndWait(anvil, {
127
- account: admin,
128
- chain: anvil.chain,
129
- address: vault,
130
- abi: iMidasPausableVaultAbi,
131
- functionName: "pauseFn",
132
- args: [DEPOSIT_INSTANT_SELECTOR]
133
- });
134
99
  } catch (e) {
135
100
  logger?.warn(`midas: failed to pause issuance vault ${vault} back: ${e}`);
136
101
  } finally {
@@ -1,7 +1,7 @@
1
1
  import "./base.js";
2
2
  import { creditAccountFrozen, liquidatorNotEligible, notEmergencyLiquidator } from "./liquidation-errors.js";
3
- import { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, rwaOpenRequirementsNotMet } from "./operation-errors.js";
3
+ import { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet } from "./operation-errors.js";
4
4
  import { unpriceableTokenError } from "./oracle-errors.js";
5
5
  import { creditAccountNotEmpty, creditAccountNotFound, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, unexpectedFailure, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress } from "./prepare-errors.js";
6
6
  import { malformedTransaction } from "./preview-errors.js";
7
- export { creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, liquidatorNotEligible, malformedTransaction, marketExpired, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, rwaOpenRequirementsNotMet, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress };
7
+ export { creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, liquidatorNotEligible, malformedTransaction, marketExpired, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress };
@@ -66,6 +66,14 @@ function insufficientCollateral(args) {
66
66
  ...args
67
67
  };
68
68
  }
69
+ /** {@inheritDoc ReservePriceLimitedError} */
70
+ function reservePriceLimited(args) {
71
+ return {
72
+ code: "reservePriceLimited",
73
+ message: `The reserve price feed values this collateral below what the operation pays out: the account covers its debt at ${args.atMainPrices} on the main feed and only ${args.healthFactor} at the reserve one, below ${args.healthFactorThreshold}.`,
74
+ ...args
75
+ };
76
+ }
69
77
  /** {@inheritDoc ForbiddenTokenError} */
70
78
  function forbiddenToken(token) {
71
79
  return {
@@ -118,4 +126,4 @@ function rwaOpenRequirementsNotMet(args) {
118
126
  };
119
127
  }
120
128
  //#endregion
121
- export { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, rwaOpenRequirementsNotMet };
129
+ export { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet };
@@ -15,7 +15,7 @@ import { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, analy
15
15
  import "./curators.js";
16
16
  import "./delayed-intents.js";
17
17
  import { creditAccountFrozen, liquidatorNotEligible, notEmergencyLiquidator } from "./errors/liquidation-errors.js";
18
- import { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, rwaOpenRequirementsNotMet } from "./errors/operation-errors.js";
18
+ import { creditManagerPaused, debtOutOfRange, forbiddenToken, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, leverageOutOfRange, marketExpired, poolPaused, poolSunset, quotaCountExceeded, quotaLimitReached, reservePriceLimited, rwaOpenRequirementsNotMet } from "./errors/operation-errors.js";
19
19
  import { unpriceableTokenError } from "./errors/oracle-errors.js";
20
20
  import { creditAccountNotEmpty, creditAccountNotFound, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, unexpectedFailure, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress } from "./errors/prepare-errors.js";
21
21
  import { malformedTransaction } from "./errors/preview-errors.js";
@@ -32,4 +32,4 @@ import { chainFailedSchema, chainMetadataSchema, chainSucceededSchema, dataSourc
32
32
  import { safeValue, sdkErr, sdkOk } from "./result.js";
33
33
  import "./withdrawals.js";
34
34
  import { positionClaimableWithdrawalSchema, positionPendingWithdrawalSchema, positionWithdrawalsSchema, withdrawalOutputAmountSchema } from "./withdrawals.schema.js";
35
- export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, KYC_REGISTRATION_LINKS, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, RWA_FACTORY_SECURITIZE, RWA_FACTORY_TYPES, RWA_PROTOCOLS, SECURITIZE_REGISTER_VAULT_TYPES, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, amountSchema, analyticsChartQueryOptionsSchema, analyticsChartQueryParamsSchema, analyticsChartQuerySchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, curatorNameSchema, curatorSchema, dataSourceSchema, debtOutOfRange, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, forbiddenToken, instantReceivedAssetSchema, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, isFilterSet, kycRequirementSchema, leverageOutOfRange, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, liquidatorNotEligible, malformedTransaction, marketExpired, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPaused, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, poolSunset, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, protocolChartMetricSchema, quotaAssetSchema, quotaCountExceeded, quotaLimitReached, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, rwaOpenRequirementsNotMet, rwaProtocolSchema, safeValue, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress, withdrawalOutputAmountSchema };
35
+ export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, KYC_REGISTRATION_LINKS, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, RWA_FACTORY_SECURITIZE, RWA_FACTORY_TYPES, RWA_PROTOCOLS, SECURITIZE_REGISTER_VAULT_TYPES, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, amountSchema, analyticsChartQueryOptionsSchema, analyticsChartQueryParamsSchema, analyticsChartQuerySchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, creditAccountFrozen, creditAccountNotEmpty, creditAccountNotFound, creditManagerPaused, curatorNameSchema, curatorSchema, dataSourceSchema, debtOutOfRange, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, forbiddenToken, instantReceivedAssetSchema, insufficientAllowance, insufficientBalance, insufficientCollateral, insufficientPoolLiquidity, isFilterSet, kycRequirementSchema, leverageOutOfRange, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, liquidatorNotEligible, malformedTransaction, marketExpired, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, multipleDelayedWithdrawals, noDelayedRoute, noRecordedIntent, noStrategyTargetCollateral, notEmergencyLiquidator, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPaused, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, poolSunset, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, protocolChartMetricSchema, quotaAssetSchema, quotaCountExceeded, quotaLimitReached, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, reservePriceLimited, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, rwaOpenRequirementsNotMet, rwaProtocolSchema, safeValue, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, unexpectedFailure, unpriceableTokenError, unsupportedCollateralToken, unsupportedTokenPair, withdrawalInProgress, withdrawalOutputAmountSchema };
@@ -0,0 +1,40 @@
1
+ import { BigIntMath } from "../../utils/bigint-math.js";
2
+ import { PERCENTAGE_FACTOR } from "../../constants/math.js";
3
+ import "../../utils/index.js";
4
+ import { eq } from "./utils/common.js";
5
+ //#region src/onchain/accounts/intents/collateral-money.ts
6
+ /** {@inheritDoc CollateralMoney} */
7
+ function collateralMoney(creditAccount, sdk) {
8
+ const { market, creditManager } = sdk.marketRegister.findCreditManager(creditAccount.creditManager);
9
+ const { priceOracle } = market;
10
+ const { pqk } = market.pool;
11
+ const underlying = market.pool.underlying;
12
+ const masked = creditAccount.enabledTokensMask !== 0n;
13
+ const mainUsd = (token, amount) => {
14
+ try {
15
+ return priceOracle.convertToUSD(token, amount);
16
+ } catch {
17
+ return;
18
+ }
19
+ };
20
+ 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;
22
+ /** A quota is underlying-denominated, and a closed market backs nothing. */
23
+ const quotaMoney = (holding) => pqk.hasActiveQuota(holding.token) ? (mainUsd(underlying, holding.quota) ?? 0n) * PERCENTAGE_FACTOR : 0n;
24
+ const weigh = (holding) => {
25
+ const weighted = checkedUsd(holding) * lt(holding.token);
26
+ if (holding.quota === 0n) return weighted;
27
+ return BigIntMath.min(quotaMoney(holding), weighted);
28
+ };
29
+ return {
30
+ underlying,
31
+ counts: (holding) => holding.balance > 10n && (!masked || (holding.mask & creditAccount.enabledTokensMask) !== 0n),
32
+ weigh,
33
+ quotaMoney,
34
+ mainUsd,
35
+ checkedUsd,
36
+ lt
37
+ };
38
+ }
39
+ //#endregion
40
+ export { collateralMoney };
@@ -6,6 +6,7 @@ import { checkCreditManagerPaused } from "../../validation/checks/checkCreditMan
6
6
  import { checkForbiddenToken } from "../../validation/checks/checkForbiddenToken.js";
7
7
  import { checkMarketExpired } from "../../validation/checks/checkMarketExpired.js";
8
8
  import { checkQuotaLimit } from "../../validation/checks/checkQuotaLimit.js";
9
+ import { checkReservePriceLimited } from "../../validation/checks/checkReservePriceLimited.js";
9
10
  import { raise } from "../../validation/raise.js";
10
11
  import "../../validation/index.js";
11
12
  import { eq } from "./utils/common.js";
@@ -111,13 +112,24 @@ function assertGrowthAllowed(args) {
111
112
  * whose reserve feed the SDK cannot read keeps its main price, so a plan can
112
113
  * still be refused on-chain after passing here.
113
114
  */
114
- function assertCollateralised(healthFactorBps, safePrices) {
115
+ function assertCollateralised(healthFactorBps, safePrices, atSafePrices) {
115
116
  const healthFactorThreshold = MIN_HEALTH_FACTOR_FACADE;
116
- raise(checkCollateralised({
117
+ const errors = checkCollateralised({
117
118
  healthFactor: healthFactorBps,
118
119
  healthFactorThreshold,
119
120
  safePrices
120
- }), `the account would end at a health factor of ${healthFactorBps}, below ${healthFactorThreshold}`);
121
+ });
122
+ if (errors.length === 0) return;
123
+ if (safePrices && atSafePrices) {
124
+ const { atMainPrices, withdrawable } = atSafePrices();
125
+ raise(checkReservePriceLimited({
126
+ healthFactor: healthFactorBps,
127
+ atMainPrices,
128
+ healthFactorThreshold,
129
+ withdrawable
130
+ }), `the account covers its debt at ${atMainPrices} on the main feed and only ${healthFactorBps} at the reserve one, below ${healthFactorThreshold}`);
131
+ }
132
+ raise(errors, `the account would end at a health factor of ${healthFactorBps}, below ${healthFactorThreshold}`);
121
133
  }
122
134
  /**
123
135
  * A quota can only be raised as far as the market still has room for: past the
@@ -8,13 +8,13 @@ import "../../validation/index.js";
8
8
  import { isPhantomToken } from "./utils/pick-token.js";
9
9
  import { assertMarketOperable } from "./guards.js";
10
10
  import { calcLeverageBand } from "./leverage-band.js";
11
- import { maxProportionalWithdrawal } from "./math.js";
12
11
  import { maxWithdrawCollateral } from "./maxWithdrawCollateral.js";
13
12
  import { fetchCreditAccountSlice, toCreditAccountSlice } from "./utils/credit-account-slice.js";
14
13
  import { buildOpenStrategyState } from "./open-strategy.js";
15
14
  import { planAddCollateral, planAdjustLeverage, planAdjustLeverageDelayed, planDeposit, planRepay, planWithdraw, planWithdrawAsset, planWithdrawDelayed } from "./plan.js";
16
- import { realize } from "./realize.js";
17
15
  import { accountView } from "./view.js";
16
+ import { withdrawLimits } from "./withdraw-limits.js";
17
+ import { realize } from "./realize.js";
18
18
  import { planTail, projectTail } from "./tail.js";
19
19
  //#region src/onchain/accounts/intents/index.ts
20
20
  /**
@@ -50,26 +50,29 @@ var CreditAccountOperationsService = class extends SDKConstruct {
50
50
  }
51
51
  /**
52
52
  * Both ends of what a `WITHDRAW` can take out, in underlying: the largest
53
- * partial withdrawal that keeps leverage and stays inside the facade's
54
- * `debtLimits`, and the net value an exit hands over. They are reported together
55
- * because a withdraw form needs both — the range it may offer, and the one
56
- * amount past it that is allowed — and because the distance between them is
57
- * the account's own, not a constant a caller could assume.
53
+ * partial withdrawal that keeps leverage, and the net value an exit hands
54
+ * over. They are reported together because a withdraw form needs both — the
55
+ * range it may offer, and the one amount past it that is allowed — and
56
+ * because the distance between them is the account's own, not a constant a
57
+ * caller could assume.
58
58
  *
59
- * Takes no target health factor, unlike {@link maxWithdrawCollateral}: a
60
- * proportional withdrawal leaves the factor where it found it, and the
61
- * facade's `minDebt` is what bounds it.
59
+ * Two rules bound the partial end and both are reported: the facade's
60
+ * `debtLimits` as `partial`, and the safe-price collateral check on top of
61
+ * it as `safePartial`. The second is the one to offer — see
62
+ * {@link WithdrawCeilings}.
62
63
  *
63
- * @param props - Account slice and the SDK holding its market
64
- * @returns The two ceilings, see {@link WithdrawCeilings} for the gap between
65
- * them
64
+ * Takes no target health factor, unlike {@link maxWithdrawCollateral}. A
65
+ * proportional withdrawal leaves the factor where it found it, so there is
66
+ * no room to choose: what these answer to is the facade's own threshold,
67
+ * which is also what {@link startIntent} refuses against.
68
+ *
69
+ * @param props - Account slice, the SDK holding its market, and optionally
70
+ * the collateral the withdrawal would be funded from
71
+ * @returns The three limits, see {@link WithdrawCeilings} for the gap
72
+ * between them
66
73
  */
67
74
  maxWithdraw(props) {
68
- const view = accountView(props.creditAccount, props.sdk);
69
- return {
70
- partial: maxProportionalWithdrawal(view, view.debtLimits),
71
- exit: view.collateral > 0n ? view.collateral : 0n
72
- };
75
+ return withdrawLimits(props);
73
76
  }
74
77
  /**
75
78
  * Debt a `REPAY` would have to cover to settle the account, in underlying