@gearbox-protocol/sdk 16.0.0-next.22 → 16.0.0-next.23

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 (82) hide show
  1. package/dist/cjs/onchain/accounts/intents/maxWithdrawCollateral.js +2 -2
  2. package/dist/cjs/onchain/accounts/intents/open-strategy.js +7 -4
  3. package/dist/cjs/onchain/accounts/intents/realize.js +10 -6
  4. package/dist/cjs/onchain/accounts/intents/tail.js +3 -2
  5. package/dist/cjs/onchain/accounts/intents/testing/market.js +1 -1
  6. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +18 -1
  7. package/dist/cjs/onchain/accounts/intents/tests/add-collateral.fixtures.js +4 -4
  8. package/dist/cjs/onchain/accounts/intents/tests/adjust-leverage.fixtures.js +15 -15
  9. package/dist/cjs/onchain/accounts/intents/tests/deposit.fixtures.js +13 -13
  10. package/dist/cjs/onchain/accounts/intents/tests/finish-decrease-leverage.fixtures.js +2 -2
  11. package/dist/cjs/onchain/accounts/intents/tests/finish-withdraw.fixtures.js +2 -2
  12. package/dist/cjs/onchain/accounts/intents/tests/withdraw-asset.fixtures.js +4 -4
  13. package/dist/cjs/onchain/accounts/intents/tests/withdraw.fixtures.js +7 -7
  14. package/dist/cjs/onchain/accounts/intents/utils/adjust-state-to-snapshot.js +8 -5
  15. package/dist/cjs/onchain/accounts/intents/utils/common.js +2 -2
  16. package/dist/cjs/onchain/accounts/intents/utils/credit-account-slice.js +4 -4
  17. package/dist/cjs/onchain/accounts/intents/view.js +2 -2
  18. package/dist/cjs/onchain/market/MarketSuite.js +15 -0
  19. package/dist/cjs/onchain/market/math.js +6 -2
  20. package/dist/cjs/onchain/pools/PoolService.js +25 -29
  21. package/dist/cjs/preview/index.js +3 -1
  22. package/dist/cjs/preview/preview/buildDelayedPreview.js +4 -4
  23. package/dist/cjs/preview/preview/previewAdjustCreditAccount.js +3 -3
  24. package/dist/cjs/preview/preview/previewCloseOrRepayCreditAccount.js +1 -1
  25. package/dist/cjs/preview/preview/previewOpenCreditAccount.js +7 -7
  26. package/dist/cjs/preview/validate/checkOperation.js +47 -37
  27. package/dist/cjs/preview/validate/checkSimulation.js +3 -16
  28. package/dist/cjs/preview/validate/index.js +3 -1
  29. package/dist/cjs/sdk/execute/ExecuteApi.js +9 -6
  30. package/dist/cjs/sdk/prepare/PrepareApi.js +4 -1
  31. package/dist/esm/onchain/accounts/intents/maxWithdrawCollateral.js +2 -2
  32. package/dist/esm/onchain/accounts/intents/open-strategy.js +7 -4
  33. package/dist/esm/onchain/accounts/intents/realize.js +10 -6
  34. package/dist/esm/onchain/accounts/intents/tail.js +3 -2
  35. package/dist/esm/onchain/accounts/intents/testing/market.js +1 -1
  36. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +18 -1
  37. package/dist/esm/onchain/accounts/intents/tests/add-collateral.fixtures.js +4 -4
  38. package/dist/esm/onchain/accounts/intents/tests/adjust-leverage.fixtures.js +15 -15
  39. package/dist/esm/onchain/accounts/intents/tests/deposit.fixtures.js +13 -13
  40. package/dist/esm/onchain/accounts/intents/tests/finish-decrease-leverage.fixtures.js +2 -2
  41. package/dist/esm/onchain/accounts/intents/tests/finish-withdraw.fixtures.js +2 -2
  42. package/dist/esm/onchain/accounts/intents/tests/withdraw-asset.fixtures.js +4 -4
  43. package/dist/esm/onchain/accounts/intents/tests/withdraw.fixtures.js +7 -7
  44. package/dist/esm/onchain/accounts/intents/utils/adjust-state-to-snapshot.js +8 -5
  45. package/dist/esm/onchain/accounts/intents/utils/common.js +2 -2
  46. package/dist/esm/onchain/accounts/intents/utils/credit-account-slice.js +4 -4
  47. package/dist/esm/onchain/accounts/intents/view.js +2 -2
  48. package/dist/esm/onchain/market/MarketSuite.js +15 -0
  49. package/dist/esm/onchain/market/math.js +6 -2
  50. package/dist/esm/onchain/pools/PoolService.js +25 -29
  51. package/dist/esm/preview/index.js +2 -2
  52. package/dist/esm/preview/preview/buildDelayedPreview.js +4 -4
  53. package/dist/esm/preview/preview/previewAdjustCreditAccount.js +3 -3
  54. package/dist/esm/preview/preview/previewCloseOrRepayCreditAccount.js +1 -1
  55. package/dist/esm/preview/preview/previewOpenCreditAccount.js +7 -7
  56. package/dist/esm/preview/validate/checkOperation.js +45 -37
  57. package/dist/esm/preview/validate/checkSimulation.js +5 -18
  58. package/dist/esm/preview/validate/index.js +2 -2
  59. package/dist/esm/sdk/execute/ExecuteApi.js +9 -6
  60. package/dist/esm/sdk/prepare/PrepareApi.js +4 -1
  61. package/dist/types/model/index.d.ts +2 -2
  62. package/dist/types/model/previews.d.ts +59 -109
  63. package/dist/types/onchain/accounts/intents/open-strategy.d.ts +15 -29
  64. package/dist/types/onchain/accounts/intents/testing/expect.d.ts +6 -2
  65. package/dist/types/onchain/accounts/intents/testing/market.d.ts +1 -1
  66. package/dist/types/onchain/accounts/intents/testing/sdk-mock.d.ts +1 -1
  67. package/dist/types/onchain/accounts/intents/tests/add-collateral.fixtures.d.ts +1 -1
  68. package/dist/types/onchain/accounts/intents/tests/adjust-leverage.fixtures.d.ts +2 -2
  69. package/dist/types/onchain/accounts/intents/tests/deposit.fixtures.d.ts +2 -2
  70. package/dist/types/onchain/accounts/intents/tests/withdraw-asset.fixtures.d.ts +1 -1
  71. package/dist/types/onchain/accounts/intents/tests/withdraw.fixtures.d.ts +2 -2
  72. package/dist/types/onchain/accounts/intents/types.d.ts +8 -59
  73. package/dist/types/onchain/accounts/intents/utils/adjust-state-to-snapshot.d.ts +2 -2
  74. package/dist/types/onchain/accounts/intents/utils/credit-account-slice.d.ts +3 -3
  75. package/dist/types/onchain/market/MarketSuite.d.ts +13 -1
  76. package/dist/types/onchain/market/math.d.ts +5 -1
  77. package/dist/types/onchain/pools/types.d.ts +6 -4
  78. package/dist/types/preview/index.d.ts +2 -2
  79. package/dist/types/preview/preview/buildDelayedPreview.d.ts +1 -1
  80. package/dist/types/preview/validate/checkOperation.d.ts +24 -7
  81. package/dist/types/preview/validate/index.d.ts +2 -2
  82. package/package.json +1 -1
@@ -21,6 +21,14 @@ require("../market/index.js");
21
21
  */
22
22
  const LIQUIDITY_SAFETY_NUM = 99999n;
23
23
  const LIQUIDITY_SAFETY_DENOM = 100000n;
24
+ /**
25
+ * What the pool can actually pay out right now, shaved by a hair so a
26
+ * withdrawal sized against it does not fail on rounding.
27
+ **/
28
+ function payoutCeiling(market) {
29
+ const { pool } = market;
30
+ return market.priceOracle.toAmount(pool.underlying, pool.pool.availableLiquidity * LIQUIDITY_SAFETY_NUM / LIQUIDITY_SAFETY_DENOM);
31
+ }
24
32
  var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
25
33
  /**
26
34
  * {@inheritDoc IPoolsService.getDepositTokensIn}
@@ -126,7 +134,9 @@ var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
126
134
  */
127
135
  simulateDeposit(props) {
128
136
  const { pool: poolAddr, amount } = props;
129
- const { pool } = this.sdk.marketRegister.findByPool(poolAddr);
137
+ const market = this.sdk.marketRegister.findByPool(poolAddr);
138
+ const { pool } = market;
139
+ const { toTokenAmount } = market.priceOracle;
130
140
  const tokenIn = props.tokenIn ?? pool.underlying;
131
141
  const tokenOut = this.#resolveTokenOut(props.tokenOut, () => this.getDepositTokensOut(poolAddr, tokenIn), {
132
142
  poolAddr,
@@ -135,14 +145,8 @@ var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
135
145
  });
136
146
  const { zapper } = this.getDepositMetadata(poolAddr, tokenIn, tokenOut);
137
147
  return {
138
- tokenIn: {
139
- token: tokenIn,
140
- balance: amount
141
- },
142
- tokenOut: {
143
- token: tokenOut,
144
- balance: toShares(pool.pool, amount)
145
- },
148
+ tokenIn: toTokenAmount(tokenIn, amount),
149
+ tokenOut: toTokenAmount(tokenOut, toShares(pool.pool, amount)),
146
150
  zapper: zapper?.baseParams.addr
147
151
  };
148
152
  }
@@ -151,7 +155,9 @@ var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
151
155
  */
152
156
  simulateWithdraw(props) {
153
157
  const { pool: poolAddr, amount } = props;
154
- const { pool } = this.sdk.marketRegister.findByPool(poolAddr);
158
+ const market = this.sdk.marketRegister.findByPool(poolAddr);
159
+ const { pool } = market;
160
+ const { toTokenAmount } = market.priceOracle;
155
161
  const tokenIn = props.tokenIn ?? poolAddr;
156
162
  const tokenOut = this.#resolveTokenOut(props.tokenOut, () => this.getWithdrawalTokensOut(poolAddr, tokenIn), {
157
163
  poolAddr,
@@ -160,16 +166,10 @@ var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
160
166
  });
161
167
  const { zapper } = this.getWithdrawalMetadata(poolAddr, tokenIn, tokenOut);
162
168
  return {
163
- tokenIn: {
164
- token: tokenIn,
165
- balance: toSharesUp(pool.pool, amount)
166
- },
167
- tokenOut: {
168
- token: tokenOut,
169
- balance: amount
170
- },
169
+ tokenIn: toTokenAmount(tokenIn, toSharesUp(pool.pool, amount)),
170
+ tokenOut: toTokenAmount(tokenOut, amount),
171
171
  zapper: zapper?.baseParams.addr,
172
- availableLiquidity: pool.pool.availableLiquidity * LIQUIDITY_SAFETY_NUM / LIQUIDITY_SAFETY_DENOM
172
+ availableLiquidity: payoutCeiling(market)
173
173
  };
174
174
  }
175
175
  /**
@@ -177,7 +177,9 @@ var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
177
177
  */
178
178
  simulateRedeem(props) {
179
179
  const { pool: poolAddr, amount } = props;
180
- const { pool } = this.sdk.marketRegister.findByPool(poolAddr);
180
+ const market = this.sdk.marketRegister.findByPool(poolAddr);
181
+ const { pool } = market;
182
+ const { toTokenAmount } = market.priceOracle;
181
183
  const tokenIn = props.tokenIn ?? poolAddr;
182
184
  const tokenOut = this.#resolveTokenOut(props.tokenOut, () => this.getWithdrawalTokensOut(poolAddr, tokenIn), {
183
185
  poolAddr,
@@ -186,16 +188,10 @@ var PoolService = class extends require_onchain_base_SDKConstruct.SDKConstruct {
186
188
  });
187
189
  const { zapper } = this.getWithdrawalMetadata(poolAddr, tokenIn, tokenOut);
188
190
  return {
189
- tokenIn: {
190
- token: tokenIn,
191
- balance: amount
192
- },
193
- tokenOut: {
194
- token: tokenOut,
195
- balance: toAssets(pool.pool, amount)
196
- },
191
+ tokenIn: toTokenAmount(tokenIn, amount),
192
+ tokenOut: toTokenAmount(tokenOut, toAssets(pool.pool, amount)),
197
193
  zapper: zapper?.baseParams.addr,
198
- availableLiquidity: pool.pool.availableLiquidity * LIQUIDITY_SAFETY_NUM / LIQUIDITY_SAFETY_DENOM
194
+ availableLiquidity: payoutCeiling(market)
199
195
  };
200
196
  }
201
197
  /**
@@ -57,7 +57,7 @@ exports.checkPrerequisites = require_preview_prerequisites_checkPrerequisites.ch
57
57
  exports.checkSimulation = require_preview_validate_checkSimulation.checkSimulation;
58
58
  exports.classifyCloseOrRepay = require_preview_preview_detectCloseOrRepay.classifyCloseOrRepay;
59
59
  exports.classifyInnerOperations = require_preview_parse_classifyInnerOperations.classifyInnerOperations;
60
- exports.collateralIssuesOf = require_preview_validate_checkOperation.collateralIssuesOf;
60
+ exports.collateralIssue = require_preview_validate_checkOperation.collateralIssue;
61
61
  exports.detectDelayedClaim = require_preview_preview_detectDelayedClaim.detectDelayedClaim;
62
62
  exports.detectDelayedOperation = require_preview_preview_detectDelayedOperation.detectDelayedOperation;
63
63
  exports.extractAdapterCallTraces = require_preview_trace_extractAdapterCallTraces.extractAdapterCallTraces;
@@ -67,6 +67,7 @@ exports.isCloseOrRepay = require_preview_preview_detectCloseOrRepay.isCloseOrRep
67
67
  exports.isPoolOperation = require_preview_parse_types.isPoolOperation;
68
68
  exports.isRWAOperation = require_preview_parse_types.isRWAOperation;
69
69
  exports.makeReplayState = require_preview_preview_replayInnerOperations.makeReplayState;
70
+ exports.marketIssues = require_preview_validate_checkOperation.marketIssues;
70
71
  exports.parseFacadeOperationCalldata = require_preview_parse_parseFacadeOperationCalldata.parseFacadeOperationCalldata;
71
72
  exports.parseOperationCalldata = require_preview_parse_parseOperationCalldata.parseOperationCalldata;
72
73
  exports.parsePoolOperationCalldata = require_preview_parse_parsePoolOperationCalldata.parsePoolOperationCalldata;
@@ -74,6 +75,7 @@ exports.parseRWAFactoryOperationCalldata = require_preview_parse_parseRWAFactory
74
75
  exports.previewAdjustCreditAccount = require_preview_preview_previewAdjustCreditAccount.previewAdjustCreditAccount;
75
76
  exports.previewCloseOrRepayCreditAccount = require_preview_preview_previewCloseOrRepayCreditAccount.previewCloseOrRepayCreditAccount;
76
77
  exports.previewOperation = require_preview_preview_previewOperation.previewOperation;
78
+ exports.quotaCountIssue = require_preview_validate_checkOperation.quotaCountIssue;
77
79
  exports.raise = require_onchain_validation_refusal.raise;
78
80
  exports.refuse = require_onchain_validation_refusal.refuse;
79
81
  exports.replayInnerOperations = require_preview_preview_replayInnerOperations.replayInnerOperations;
@@ -18,7 +18,7 @@ let viem = require("viem");
18
18
  * nothing and set a non-fatal `ERROR_UNPRICEABLE_TOKEN` error on the
19
19
  * preview.
20
20
  *
21
- * The changes (e.g. `debtChange`) are reported relative to the account
21
+ * The changes (e.g. `totalDebtChange`) are reported relative to the account
22
22
  * state before the whole transaction.
23
23
  *
24
24
  * @param afterInstant - Account state after the instant part of the
@@ -188,9 +188,9 @@ function buildAdjustPreview(post, before, collateralWithdrawn, converter, sdk) {
188
188
  creditAccount: post.creditAccount,
189
189
  collateralAdded: [],
190
190
  collateralWithdrawn: collateralWithdrawn.toAssets().map((a) => oracle.toTokenAmount(a.token, a.balance)),
191
- totalValue,
192
- debt: post.totalDebt,
193
- debtChange: post.totalDebt - before.totalDebt,
191
+ totalValue: market.toUnderlyingAmount(totalValue),
192
+ totalDebt: market.toUnderlyingAmount(post.totalDebt),
193
+ totalDebtChange: market.toUnderlyingAmount(post.totalDebt - before.totalDebt),
194
194
  quotas: quotas.map((q) => ({
195
195
  token: sdk.tokensMeta.mustGetToken(q.token),
196
196
  ...oracle.toAmount(market.underlying, q.balance)
@@ -46,9 +46,9 @@ async function previewAdjustCreditAccount(input, operation, options) {
46
46
  creditAccount: operation.creditAccount,
47
47
  collateralAdded: collateralAdded.map((a) => oracle.toTokenAmount(a.token, a.balance)),
48
48
  collateralWithdrawn: after.collateralWithdrawn.toAssets().map((a) => oracle.toTokenAmount(a.token, a.balance)),
49
- totalValue,
50
- debt: account.totalDebt,
51
- debtChange: account.totalDebt - before.totalDebt,
49
+ totalValue: market.toUnderlyingAmount(totalValue),
50
+ totalDebt: market.toUnderlyingAmount(account.totalDebt),
51
+ totalDebtChange: market.toUnderlyingAmount(account.totalDebt - before.totalDebt),
52
52
  quotas: quotas.map((q) => ({
53
53
  token: sdk.tokensMeta.mustGetToken(q.token),
54
54
  ...oracle.toAmount(market.underlying, q.balance)
@@ -57,7 +57,7 @@ function previewRepayCreditAccount(input, operation, permanent, replay) {
57
57
  name: sdk.marketRegister.findCreditManager(operation.creditManager).name,
58
58
  creditAccount: operation.creditAccount,
59
59
  collateralAdded: collateralAdded.map((a) => market.priceOracle.toTokenAmount(a.token, a.balance)),
60
- debtRepaid: before.totalDebt - after.account.totalDebt,
60
+ debtRepaid: market.toUnderlyingAmount(before.totalDebt - after.account.totalDebt),
61
61
  collateralWithdrawn: after.collateralWithdrawn.toAssets().map((a) => market.priceOracle.toTokenAmount(a.token, a.balance)),
62
62
  error
63
63
  };
@@ -17,7 +17,7 @@ async function previewOpenCreditAccount(input, operation) {
17
17
  let error = await require_preview_preview_replayInnerOperations.replayInnerOperations(sdk, operation.multicall, state);
18
18
  const account = state.account;
19
19
  let priceError;
20
- const collateralValue = state.collateralAdded.sum((token, balance) => {
20
+ const netValue = state.collateralAdded.sum((token, balance) => {
21
21
  try {
22
22
  return oracle.convert(token, market.underlying, balance);
23
23
  } catch {
@@ -32,18 +32,18 @@ async function previewOpenCreditAccount(input, operation) {
32
32
  error ??= unwrapError ?? priceError;
33
33
  const assets = account.balances.toAssets(require_onchain_constants_math.DUST_THRESHOLD);
34
34
  const quotas = account.quotas.toAssets(0n);
35
- const totalValue = collateralValue + account.totalDebt;
35
+ const totalValue = netValue + account.totalDebt;
36
36
  const snap = account.toSnapshot(totalValue);
37
37
  const targetAsset = inferTargetAsset(operation.multicall, account.balances);
38
38
  return {
39
39
  operation: operation.operation,
40
40
  creditManager: operation.creditManager,
41
41
  name: sdk.marketRegister.findCreditManager(operation.creditManager).name,
42
- target: targetAsset ? oracle.toTokenAmount(targetAsset.token, targetAsset.balance) : void 0,
43
- collateral: collateral.map((a) => oracle.toTokenAmount(a.token, a.balance)),
44
- collateralValue,
45
- totalValue,
46
- debt: account.debt,
42
+ targetCollateral: targetAsset ? oracle.toTokenAmount(targetAsset.token, targetAsset.balance) : void 0,
43
+ collateralAdded: collateral.map((a) => oracle.toTokenAmount(a.token, a.balance)),
44
+ netValue: market.toUnderlyingAmount(netValue),
45
+ totalValue: market.toUnderlyingAmount(totalValue),
46
+ totalDebt: market.toUnderlyingAmount(account.totalDebt),
47
47
  quotas: quotas.map((q) => ({
48
48
  token: sdk.tokensMeta.mustGetToken(q.token),
49
49
  ...oracle.toAmount(market.underlying, q.balance)
@@ -31,7 +31,7 @@ function checkOperation(input, options = {}) {
31
31
  case "RWAOpenCreditAccount":
32
32
  case "AdjustCreditAccount": return creditIssues(sdk, preview, options);
33
33
  case "CloseCreditAccount":
34
- case "RepayCreditAccount": return marketIssues(sdk, preview.creditManager);
34
+ case "RepayCreditAccount": return marketIssues(sdk.marketRegister.findCreditManager(preview.creditManager));
35
35
  }
36
36
  }
37
37
  function poolIssues(sdk, preview, options, isDeposit) {
@@ -50,8 +50,8 @@ function poolIssues(sdk, preview, options, isDeposit) {
50
50
  })) || fundingIssue(options, [preview.tokenIn]);
51
51
  }
52
52
  /** What the market itself refuses, whatever the operation does. */
53
- function marketIssues(sdk, creditManager) {
54
- const suite = sdk.marketRegister.findCreditManager(creditManager);
53
+ function marketIssues(suite) {
54
+ const creditManager = suite.creditManager.address;
55
55
  return require_onchain_validation_checks.checkCreditManagerPaused({
56
56
  isPaused: suite.isPaused,
57
57
  creditManager
@@ -66,29 +66,42 @@ function creditIssues(sdk, preview, options) {
66
66
  const market = suite.market;
67
67
  const underlying = require_onchain_validation_token.toToken(sdk, market.pool.underlying);
68
68
  const isOpening = preview.operation === "OpenCreditAccount" || preview.operation === "RWAOpenCreditAccount";
69
- return marketIssues(sdk, preview.creditManager) || require_onchain_validation_checks.checkDebtInBand({
70
- debt: preview.debt,
69
+ return marketIssues(suite) || require_onchain_validation_checks.checkDebtInBand({
70
+ debt: preview.totalDebt.value,
71
71
  minDebt: suite.creditFacade.minDebt,
72
72
  maxDebt: suite.creditFacade.maxDebt,
73
73
  underlying,
74
74
  allowZero: !isOpening
75
- }) || borrowIssue(suite, preview, underlying) || forbiddenIssue(suite, preview) || require_onchain_validation_checks.checkQuotaCount({
76
- count: preview.quotas.filter((q) => q.value > 0n).length,
75
+ }) || borrowIssue(suite, preview, underlying) || forbiddenIssue(suite, preview) || quotaCountIssue(suite, preview) || quotaIssue(market, preview, underlying) || collateralIssue(preview, options) || fundingIssue(options, preview.collateralAdded);
76
+ }
77
+ /**
78
+ * A bar that reads nothing but the projected account, so a parsed transaction
79
+ * and a simulated one are held to it by the same code.
80
+ *
81
+ * These stay separate functions rather than one block because the order the
82
+ * checks run in is the answer: `checkOperation` interleaves the checks that
83
+ * need an operation's *delta* between them, and the caller acts on the first
84
+ * issue reported.
85
+ */
86
+ function quotaCountIssue(suite, projection) {
87
+ return require_onchain_validation_checks.checkQuotaCount({
88
+ count: projection.quotas.filter((q) => q.value > 0n).length,
77
89
  max: suite.creditManager.maxEnabledTokens
78
- }) || quotaIssue(market, preview, underlying) || (preview.debt === 0n ? null : collateralIssue(preview, options)) || fundingIssue(options, collateralOf(preview));
90
+ });
79
91
  }
80
92
  /**
81
93
  * What the transaction draws, against what the market can lend right now.
82
94
  *
83
95
  * Only a draw is weighed: repaying, or leaving the debt alone, can never exceed
84
- * a ceiling. Opening borrows the whole debt; adjusting borrows `debtChange`.
96
+ * a ceiling. Opening borrows the whole debt; adjusting borrows
97
+ * `totalDebtChange`.
85
98
  *
86
99
  * The engine holds every simulation to this already (`assertCanBorrow`), so
87
100
  * this is here for the transactions it never saw — a pasted calldata reaches
88
101
  * the confirm screen with nothing else standing between it and a revert.
89
102
  */
90
103
  function borrowIssue(suite, preview, underlying) {
91
- const drawn = preview.operation === "AdjustCreditAccount" ? preview.debtChange : preview.debt;
104
+ const drawn = preview.operation === "AdjustCreditAccount" ? preview.totalDebtChange.value : preview.totalDebt.value;
92
105
  if (drawn <= 0n) return null;
93
106
  const { limit, binding } = require_onchain_accounts_intents_guards.borrowable(suite);
94
107
  return require_onchain_validation_checks.checkBorrowLimit({
@@ -98,12 +111,27 @@ function borrowIssue(suite, preview, underlying) {
98
111
  underlying
99
112
  });
100
113
  }
101
- /** The account against whichever bars the caller holds it to. */
102
- function collateralIssue(preview, options) {
103
- return collateralIssuesOf({
104
- healthFactor: preview.healthFactor,
105
- safeHealthFactor: preview.safeHealthFactor
106
- }, options);
114
+ /**
115
+ * The account against whichever bars the caller holds it to.
116
+ *
117
+ * A loan-free account is nothing to weigh: the health factor reports its
118
+ * zero-debt sentinel and no bar applies.
119
+ *
120
+ * {@inheritDoc quotaCountIssue}
121
+ */
122
+ function collateralIssue(projection, options) {
123
+ const { minHealthFactor, minSafeHealthFactor, currentHealthFactor } = options;
124
+ if (projection.totalDebt.value === 0n) return null;
125
+ return (minHealthFactor === void 0 ? null : require_onchain_validation_checks.checkCollateralised({
126
+ healthFactor: projection.healthFactor,
127
+ required: minHealthFactor,
128
+ safePrices: false,
129
+ improvesFrom: currentHealthFactor
130
+ })) || (minSafeHealthFactor === void 0 || projection.safeHealthFactor === void 0 ? null : require_onchain_validation_checks.checkCollateralised({
131
+ healthFactor: projection.safeHealthFactor,
132
+ required: minSafeHealthFactor,
133
+ safePrices: true
134
+ }));
107
135
  }
108
136
  /** The wallet's side of the operation, against the balances it was given. */
109
137
  function fundingIssue(options, puts) {
@@ -119,12 +147,6 @@ function fundingIssue(options, puts) {
119
147
  }
120
148
  return null;
121
149
  }
122
- /** What the wallet puts in, which is what its balances have to cover. */
123
- function collateralOf(preview) {
124
- if ("collateral" in preview) return preview.collateral;
125
- if ("collateralAdded" in preview) return preview.collateralAdded;
126
- return [];
127
- }
128
150
  function forbiddenIssue(suite, preview) {
129
151
  const obtained = preview.operation === "AdjustCreditAccount" ? preview.assetsChange : preview.assets;
130
152
  const forbidden = suite.forbiddenTokens;
@@ -154,20 +176,8 @@ function quotaIssue(market, preview, underlying) {
154
176
  }
155
177
  return null;
156
178
  }
157
- /** The two collateral bars, shared by the preview and the simulation paths. */
158
- function collateralIssuesOf(factors, options) {
159
- const { minHealthFactor, minSafeHealthFactor, currentHealthFactor } = options;
160
- return (minHealthFactor === void 0 ? null : require_onchain_validation_checks.checkCollateralised({
161
- healthFactor: factors.healthFactor,
162
- required: minHealthFactor,
163
- safePrices: false,
164
- improvesFrom: currentHealthFactor
165
- })) || (minSafeHealthFactor === void 0 || factors.safeHealthFactor === void 0 ? null : require_onchain_validation_checks.checkCollateralised({
166
- healthFactor: factors.safeHealthFactor,
167
- required: minSafeHealthFactor,
168
- safePrices: true
169
- }));
170
- }
171
179
  //#endregion
172
180
  exports.checkOperation = checkOperation;
173
- exports.collateralIssuesOf = collateralIssuesOf;
181
+ exports.collateralIssue = collateralIssue;
182
+ exports.marketIssues = marketIssues;
183
+ exports.quotaCountIssue = quotaCountIssue;
@@ -27,26 +27,13 @@ const require_preview_validate_checkOperation = require("./checkOperation.js");
27
27
  function checkSimulation(input, options = {}) {
28
28
  const { sdk, state, creditManager } = input;
29
29
  const suite = sdk.marketRegister.findCreditManager(creditManager);
30
- return require_onchain_validation_checks.checkCreditManagerPaused({
31
- isPaused: suite.isPaused,
32
- creditManager
33
- }) || require_onchain_validation_checks.checkMarketExpired({
34
- isExpired: suite.isExpired,
35
- creditManager,
36
- expirationDate: suite.creditFacade.expirationDate
37
- }) || require_onchain_validation_checks.checkDebtInBand({
38
- debt: state.accountDebt,
30
+ return require_preview_validate_checkOperation.marketIssues(suite) || require_onchain_validation_checks.checkDebtInBand({
31
+ debt: state.totalDebt.value,
39
32
  minDebt: suite.creditFacade.minDebt,
40
33
  maxDebt: suite.creditFacade.maxDebt,
41
34
  underlying: require_onchain_validation_token.toToken(sdk, suite.market.pool.underlying),
42
35
  allowZero: true
43
- }) || require_onchain_validation_checks.checkQuotaCount({
44
- count: Object.values(state.quotas).filter((q) => q.balance > 0n).length,
45
- max: suite.creditManager.maxEnabledTokens
46
- }) || (state.accountDebt === 0n ? null : require_preview_validate_checkOperation.collateralIssuesOf({
47
- healthFactor: state.healthFactor,
48
- safeHealthFactor: state.safeHealthFactor
49
- }, options));
36
+ }) || require_preview_validate_checkOperation.quotaCountIssue(suite, state) || require_preview_validate_checkOperation.collateralIssue(state, options);
50
37
  }
51
38
  //#endregion
52
39
  exports.checkSimulation = checkSimulation;
@@ -3,4 +3,6 @@ const require_preview_validate_checkOperation = require("./checkOperation.js");
3
3
  const require_preview_validate_checkSimulation = require("./checkSimulation.js");
4
4
  exports.checkOperation = require_preview_validate_checkOperation.checkOperation;
5
5
  exports.checkSimulation = require_preview_validate_checkSimulation.checkSimulation;
6
- exports.collateralIssuesOf = require_preview_validate_checkOperation.collateralIssuesOf;
6
+ exports.collateralIssue = require_preview_validate_checkOperation.collateralIssue;
7
+ exports.marketIssues = require_preview_validate_checkOperation.marketIssues;
8
+ exports.quotaCountIssue = require_preview_validate_checkOperation.quotaCountIssue;
@@ -25,21 +25,24 @@ function poolTx(sdk, request) {
25
25
  const { pool, wallet, sim } = request;
26
26
  const { tokenIn, tokenOut } = sim.preview;
27
27
  if (request.op === "deposit") {
28
- const meta = sdk.pools.getDepositMetadata(pool, tokenIn.token, tokenOut.token);
28
+ const meta = sdk.pools.getDepositMetadata(pool, tokenIn.token.address, tokenOut.token.address);
29
29
  const result = sdk.pools.addLiquidity({
30
30
  pool,
31
31
  wallet,
32
- collateral: tokenIn,
32
+ collateral: {
33
+ token: tokenIn.token.address,
34
+ balance: tokenIn.value
35
+ },
33
36
  meta
34
37
  });
35
- if (!result) throw new Error(`pool ${pool} takes no deposit transaction for ${tokenIn.token} (${meta.type})`);
38
+ if (!result) throw new Error(`pool ${pool} takes no deposit transaction for ${tokenIn.token.address} (${meta.type})`);
36
39
  return result.tx;
37
40
  }
38
- const meta = sdk.pools.getWithdrawalMetadata(pool, tokenIn.token, tokenOut.token);
41
+ const meta = sdk.pools.getWithdrawalMetadata(pool, tokenIn.token.address, tokenOut.token.address);
39
42
  return sdk.pools.removeLiquidity({
40
43
  pool,
41
44
  wallet,
42
- amount: request.op === "withdraw" ? tokenOut.balance : tokenIn.balance,
45
+ amount: request.op === "withdraw" ? tokenOut.value : tokenIn.value,
43
46
  permit: void 0,
44
47
  meta,
45
48
  mode: request.op === "withdraw" ? "withdraw" : "redeem"
@@ -53,7 +56,7 @@ async function openTx(sdk, request) {
53
56
  to: wallet,
54
57
  collateral,
55
58
  ethAmount,
56
- debt: preview.debt,
59
+ debt: preview.totalDebt.value,
57
60
  calls: preview.calls,
58
61
  averageQuota: preview.averageQuota,
59
62
  minQuota: preview.minQuota,
@@ -66,7 +66,10 @@ var PrepareApi = class extends require_onchain_base_MultichainConstruct.Multicha
66
66
  tokenOut
67
67
  });
68
68
  const call = pools.addLiquidity({
69
- collateral: preview.tokenIn,
69
+ collateral: {
70
+ token: preview.tokenIn.token.address,
71
+ balance: preview.tokenIn.value
72
+ },
70
73
  pool: pool.pool,
71
74
  wallet: params.wallet,
72
75
  meta: pools.getDepositMetadata(pool.pool, tokenIn, tokenOut)
@@ -30,7 +30,7 @@ function maxWithdrawCollateral(props) {
30
30
  const underlying = market.pool.underlying;
31
31
  const target = creditAccount.tokens.find((t) => eq(t.token, token));
32
32
  if (!target || target.balance <= 10n) return 0n;
33
- if (creditAccount.accountDebt === 0n) return target.balance;
33
+ if (creditAccount.totalDebt === 0n) return target.balance;
34
34
  const masked = creditAccount.enabledTokensMask !== 0n;
35
35
  const counts = (t) => t.balance > 10n && (!masked || (t.mask & creditAccount.enabledTokensMask) !== 0n);
36
36
  /** What a holding backs, in the check's units: USD × PERCENTAGE_FACTOR. */
@@ -47,7 +47,7 @@ function maxWithdrawCollateral(props) {
47
47
  if (eq(t.token, token) || !counts(t)) continue;
48
48
  otherMoney += weigh(t);
49
49
  }
50
- const borrowed = usd(priceOracle, underlying, creditAccount.accountDebt);
50
+ const borrowed = usd(priceOracle, underlying, creditAccount.totalDebt);
51
51
  if (borrowed === void 0 || borrowed <= 0n) return 0n;
52
52
  const required = borrowed * targetHF;
53
53
  if (required <= otherMoney) return target.balance;
@@ -1,3 +1,4 @@
1
+ import { calcPositionLeverage } from "../../market/math.js";
1
2
  import { IntentPreviewError } from "../../validation/refusal.js";
2
3
  import { assertCanBorrow, assertCollateralised, assertGrowthAllowed, assertMarketOperable, assertQuotaHeadroom } from "./guards.js";
3
4
  import { assertDebtInBand, assertLeverageAtLeastOne, debtForLeverage } from "./math.js";
@@ -37,7 +38,7 @@ async function previewOpenStrategy(props) {
37
38
  underlying,
38
39
  enabledTokensMask: 0n,
39
40
  totalDebtUSD: 0n,
40
- accountDebt: 0n,
41
+ totalDebt: 0n,
41
42
  tokens: []
42
43
  };
43
44
  assertDebtInBand(sdk, debt, suite.creditFacade, underlying);
@@ -87,6 +88,7 @@ async function previewOpenStrategy(props) {
87
88
  const projectedPool = { availableLiquidityChange: -debt };
88
89
  const metrics = {
89
90
  healthFactor: sdk.positions.healthFactor(snapshot),
91
+ safeHealthFactor: sdk.positions.healthFactor(snapshot, { safePrices: true }),
90
92
  borrowRate: sdk.positions.borrowRate(snapshot, projectedPool),
91
93
  timeToLiquidation: sdk.positions.timeToLiquidation(snapshot, projectedPool),
92
94
  liquidationPrice: sdk.positions.liquidationPrice(snapshot)
@@ -98,9 +100,10 @@ async function previewOpenStrategy(props) {
98
100
  toUnderlying: (from, amount) => convert(from, underlying, amount)
99
101
  });
100
102
  return {
101
- debt,
102
- collateral: margin,
103
- totalValue: margin + debt,
103
+ totalDebt: market.toUnderlyingAmount(debt),
104
+ netValue: market.toUnderlyingAmount(margin),
105
+ totalValue: market.toUnderlyingAmount(margin + debt),
106
+ leverage: calcPositionLeverage(margin + debt, debt),
104
107
  priceImpact,
105
108
  averageAssets: averageAssets.map(priced),
106
109
  minAssets: minAssets.map(priced),
@@ -35,7 +35,7 @@ async function realize(steps, props) {
35
35
  const ledger = new OperationLedger({
36
36
  initialAssets: creditAccount.tokens,
37
37
  underlying,
38
- debt: creditAccount.accountDebt,
38
+ debt: creditAccount.totalDebt,
39
39
  convert: price
40
40
  });
41
41
  const operations = [];
@@ -271,7 +271,7 @@ async function realize(steps, props) {
271
271
  totalDebt: debt,
272
272
  totalValue
273
273
  };
274
- const projectedPool = { availableLiquidityChange: creditAccount.accountDebt - debt };
274
+ const projectedPool = { availableLiquidityChange: creditAccount.totalDebt - debt };
275
275
  const metrics = {
276
276
  healthFactor: sdk.positions.healthFactor(snapshot),
277
277
  safeHealthFactor: paysOut ? sdk.positions.healthFactor(snapshot, { safePrices: true }) : void 0,
@@ -285,12 +285,16 @@ async function realize(steps, props) {
285
285
  netValue: totalValue - debt,
286
286
  toUnderlying: (from, amount) => price(from, underlying, amount)
287
287
  });
288
+ const oracle = market.priceOracle;
288
289
  const state = {
289
- totalValue,
290
- accountDebt: debt,
290
+ totalValue: market.toUnderlyingAmount(totalValue),
291
+ totalDebt: market.toUnderlyingAmount(debt),
291
292
  leverage: calcPositionLeverage(totalValue, debt),
292
- assets: assets.map((a) => market.priceOracle.toTokenAmount(a.token, a.balance)),
293
- quotas: quotasAfter,
293
+ assets: assets.map((a) => oracle.toTokenAmount(a.token, a.balance)),
294
+ quotas: Object.values(quotasAfter).map((q) => ({
295
+ token: sdk.tokensMeta.mustGetToken(q.token),
296
+ ...oracle.toAmount(underlying, q.balance)
297
+ })),
294
298
  priceImpact,
295
299
  ...metrics
296
300
  };
@@ -102,15 +102,16 @@ function projectedClaimable(request, phantom, phantomAmount, claim) {
102
102
  */
103
103
  function sliceAfter(creditAccount, after) {
104
104
  const masks = new Map(creditAccount.tokens.map((t) => [t.token.toLowerCase(), t.mask]));
105
+ const quotas = new Map(after.quotas.map((q) => [q.token.address.toLowerCase(), q.value]));
105
106
  return {
106
107
  ...creditAccount,
107
- accountDebt: after.accountDebt,
108
+ totalDebt: after.totalDebt.value,
108
109
  tokens: after.assets.map((a) => {
109
110
  const token = a.token.address.toLowerCase();
110
111
  return {
111
112
  token,
112
113
  balance: a.value,
113
- quota: after.quotas[token]?.balance ?? 0n,
114
+ quota: quotas.get(token) ?? 0n,
114
115
  mask: masks.get(token) ?? 0n,
115
116
  success: true
116
117
  };
@@ -142,7 +142,7 @@ function buildFixtureCreditAccount(args) {
142
142
  underlying: UND,
143
143
  enabledTokensMask: 0n,
144
144
  totalDebtUSD: 0n,
145
- accountDebt: args.accountDebt,
145
+ totalDebt: args.totalDebt,
146
146
  tokens: args.tokens
147
147
  };
148
148
  }
@@ -144,13 +144,30 @@ function buildMockSdk(args) {
144
144
  return price;
145
145
  };
146
146
  const poolPaused = args.poolPaused ?? false;
147
+ /** {@inheritDoc MarketSuite.toUnderlyingAmount} */
148
+ const toUnderlyingAmount = (value) => {
149
+ const usd = safeUsd(args.underlying, value);
150
+ return {
151
+ token: tokenOf(args.rwaAssets?.[args.underlying.toLowerCase()] ?? args.underlying),
152
+ value,
153
+ valueUsd: usd === null ? null : usdToNumber(usd)
154
+ };
155
+ };
147
156
  const market = {
157
+ toUnderlyingAmount,
148
158
  priceOracle: {
149
159
  convert,
150
160
  safeConvert,
151
161
  mainPrice: mainPriceOf,
152
162
  reservePrice: reservePriceOf,
153
163
  convertToUSD: _convertToUSD,
164
+ toAmount: (token, value) => {
165
+ const usd = safeUsd(token, value);
166
+ return {
167
+ value,
168
+ valueUsd: usd === null ? null : usdToNumber(usd)
169
+ };
170
+ },
154
171
  toTokenAmount: (token, value) => {
155
172
  const usd = safeUsd(token, value);
156
173
  return {
@@ -349,7 +366,7 @@ function payloadOf(slice) {
349
366
  owner: slice.creditAccount,
350
367
  expirationDate: 0,
351
368
  enabledTokensMask: slice.enabledTokensMask,
352
- debt: slice.accountDebt,
369
+ debt: slice.totalDebt,
353
370
  accruedInterest: 0n,
354
371
  accruedFees: 0n,
355
372
  totalDebtUSD: slice.totalDebtUSD,
@@ -31,7 +31,7 @@ const case_position_token = {
31
31
  amount: ADD_ANY
32
32
  },
33
33
  tokens: [caToken(UND, BASE_UND)],
34
- accountDebt: DEBT,
34
+ totalDebt: DEBT,
35
35
  totalValue: BASE_UND + valueInUnd(ADD_ANY, ANY),
36
36
  ops: [{
37
37
  type: "addCollateral",
@@ -56,7 +56,7 @@ const case_underlying = {
56
56
  amount: ADD_UND
57
57
  },
58
58
  tokens: [caToken(ANY, ADD_ANY, QUOTA_ANY)],
59
- accountDebt: DEBT,
59
+ totalDebt: DEBT,
60
60
  totalValue: valueInUnd(ADD_ANY, ANY) + ADD_UND,
61
61
  ops: [{
62
62
  type: "addCollateral",
@@ -73,7 +73,7 @@ const case_rwa_asset = {
73
73
  amount: ADD_RWA
74
74
  },
75
75
  tokens: [caToken(UND, BASE_UND)],
76
- accountDebt: DEBT,
76
+ totalDebt: DEBT,
77
77
  totalValue: BASE_UND + valueInUnd(ADD_RWA, RWA_ASSET),
78
78
  ops: [{
79
79
  type: "addCollateral",
@@ -98,7 +98,7 @@ function buildAddCollateralProps(c, sdk) {
98
98
  return {
99
99
  intent: c.intent,
100
100
  creditAccount: buildFixtureCreditAccount({
101
- accountDebt: c.accountDebt,
101
+ totalDebt: c.totalDebt,
102
102
  tokens: c.tokens
103
103
  }),
104
104
  sdk,