@gearbox-protocol/sdk 17.13.0-next.2 → 17.13.0-next.4

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 (83) hide show
  1. package/dist/cjs/model/errors/index.js +3 -0
  2. package/dist/cjs/model/errors/operation-errors.js +27 -0
  3. package/dist/cjs/model/index.js +3 -0
  4. package/dist/cjs/onchain/accounts/intents/index.js +1 -0
  5. package/dist/cjs/onchain/accounts/intents/operations.js +1 -1
  6. package/dist/cjs/onchain/accounts/intents/plan.js +21 -0
  7. package/dist/cjs/onchain/accounts/intents/realize.js +29 -7
  8. package/dist/cjs/onchain/accounts/intents/resolveQuotaUpdate.js +149 -0
  9. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +1 -0
  10. package/dist/cjs/onchain/accounts/intents/tests/update-quota.fixtures.js +102 -0
  11. package/dist/cjs/onchain/accounts/intents/utils/index.js +1 -0
  12. package/dist/cjs/onchain/accounts/intents/utils/quotas-for-update.js +28 -10
  13. package/dist/cjs/onchain/constants/index.js +1 -0
  14. package/dist/cjs/onchain/constants/math.js +6 -0
  15. package/dist/cjs/onchain/index.js +9 -0
  16. package/dist/cjs/onchain/positions/calcHealthFactor.js +1 -1
  17. package/dist/cjs/onchain/preview/preview/CreditAccountState.js +4 -2
  18. package/dist/cjs/onchain/validation/bundles/checkCreditOperation.js +2 -0
  19. package/dist/cjs/onchain/validation/bundles/checkQuotaUpdates.js +45 -0
  20. package/dist/cjs/onchain/validation/bundles/index.js +2 -0
  21. package/dist/cjs/onchain/validation/checks/checkMaxQuota.js +18 -0
  22. package/dist/cjs/onchain/validation/checks/checkQuotaActive.js +10 -0
  23. package/dist/cjs/onchain/validation/checks/checkQuotaChange.js +18 -0
  24. package/dist/cjs/onchain/validation/checks/index.js +6 -0
  25. package/dist/cjs/onchain/validation/index.js +8 -0
  26. package/dist/cjs/sdk/prepare/PrepareApi.js +67 -0
  27. package/dist/esm/model/errors/index.js +2 -2
  28. package/dist/esm/model/errors/operation-errors.js +25 -1
  29. package/dist/esm/model/index.js +2 -2
  30. package/dist/esm/onchain/accounts/intents/index.js +2 -1
  31. package/dist/esm/onchain/accounts/intents/operations.js +1 -1
  32. package/dist/esm/onchain/accounts/intents/plan.js +22 -2
  33. package/dist/esm/onchain/accounts/intents/realize.js +29 -7
  34. package/dist/esm/onchain/accounts/intents/resolveQuotaUpdate.js +148 -0
  35. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +1 -0
  36. package/dist/esm/onchain/accounts/intents/tests/update-quota.fixtures.js +92 -0
  37. package/dist/esm/onchain/accounts/intents/utils/index.js +2 -2
  38. package/dist/esm/onchain/accounts/intents/utils/quotas-for-update.js +28 -11
  39. package/dist/esm/onchain/constants/index.js +2 -2
  40. package/dist/esm/onchain/constants/math.js +6 -1
  41. package/dist/esm/onchain/index.js +6 -2
  42. package/dist/esm/onchain/positions/calcHealthFactor.js +1 -1
  43. package/dist/esm/onchain/preview/preview/CreditAccountState.js +4 -2
  44. package/dist/esm/onchain/validation/bundles/checkCreditOperation.js +2 -0
  45. package/dist/esm/onchain/validation/bundles/checkQuotaUpdates.js +44 -0
  46. package/dist/esm/onchain/validation/bundles/index.js +2 -1
  47. package/dist/esm/onchain/validation/checks/checkMaxQuota.js +17 -0
  48. package/dist/esm/onchain/validation/checks/checkQuotaActive.js +9 -0
  49. package/dist/esm/onchain/validation/checks/checkQuotaChange.js +17 -0
  50. package/dist/esm/onchain/validation/checks/index.js +4 -1
  51. package/dist/esm/onchain/validation/index.js +5 -1
  52. package/dist/esm/sdk/prepare/PrepareApi.js +67 -0
  53. package/dist/types/model/errors/index.d.ts +2 -2
  54. package/dist/types/model/errors/operation-errors.d.ts +39 -1
  55. package/dist/types/model/index.d.ts +2 -2
  56. package/dist/types/onchain/accounts/index.d.ts +2 -2
  57. package/dist/types/onchain/accounts/intents/index.d.ts +2 -2
  58. package/dist/types/onchain/accounts/intents/operations.d.ts +9 -3
  59. package/dist/types/onchain/accounts/intents/plan.d.ts +19 -2
  60. package/dist/types/onchain/accounts/intents/resolveQuotaUpdate.d.ts +39 -0
  61. package/dist/types/onchain/accounts/intents/tests/update-quota.fixtures.d.ts +49 -0
  62. package/dist/types/onchain/accounts/intents/types.d.ts +19 -2
  63. package/dist/types/onchain/accounts/intents/utils/index.d.ts +2 -2
  64. package/dist/types/onchain/accounts/intents/utils/quotas-for-update.d.ts +23 -5
  65. package/dist/types/onchain/constants/index.d.ts +2 -2
  66. package/dist/types/onchain/constants/math.d.ts +6 -1
  67. package/dist/types/onchain/index.d.ts +7 -3
  68. package/dist/types/onchain/preview/preview/CreditAccountState.d.ts +2 -1
  69. package/dist/types/onchain/validation/bundles/checkCreditOperation.d.ts +2 -2
  70. package/dist/types/onchain/validation/bundles/checkQuotaUpdates.d.ts +16 -0
  71. package/dist/types/onchain/validation/bundles/index.d.ts +2 -1
  72. package/dist/types/onchain/validation/checks/checkMaxQuota.d.ts +16 -0
  73. package/dist/types/onchain/validation/checks/checkQuotaActive.d.ts +13 -0
  74. package/dist/types/onchain/validation/checks/checkQuotaChange.d.ts +17 -0
  75. package/dist/types/onchain/validation/checks/index.d.ts +4 -1
  76. package/dist/types/onchain/validation/index.d.ts +5 -1
  77. package/dist/types/onchain/validation/raise.d.ts +2 -2
  78. package/dist/types/sdk/execute/types.d.ts +1 -1
  79. package/dist/types/sdk/index.d.ts +2 -2
  80. package/dist/types/sdk/prepare/PrepareApi.d.ts +11 -3
  81. package/dist/types/sdk/prepare/index.d.ts +2 -2
  82. package/dist/types/sdk/prepare/types.d.ts +42 -3
  83. package/package.json +1 -1
@@ -27,8 +27,11 @@ exports.noStrategyTargetCollateral = require_model_errors_prepare_errors.noStrat
27
27
  exports.notEmergencyLiquidator = require_model_errors_liquidation_errors.notEmergencyLiquidator;
28
28
  exports.poolPaused = require_model_errors_operation_errors.poolPaused;
29
29
  exports.poolSunset = require_model_errors_operation_errors.poolSunset;
30
+ exports.quotaAboveMax = require_model_errors_operation_errors.quotaAboveMax;
30
31
  exports.quotaCountExceeded = require_model_errors_operation_errors.quotaCountExceeded;
32
+ exports.quotaInactive = require_model_errors_operation_errors.quotaInactive;
31
33
  exports.quotaLimitReached = require_model_errors_operation_errors.quotaLimitReached;
34
+ exports.quotaUnchanged = require_model_errors_operation_errors.quotaUnchanged;
32
35
  exports.reservePriceLimited = require_model_errors_operation_errors.reservePriceLimited;
33
36
  exports.rwaOpenRequirementsNotMet = require_model_errors_operation_errors.rwaOpenRequirementsNotMet;
34
37
  exports.unexpectedFailure = require_model_errors_prepare_errors.unexpectedFailure;
@@ -101,6 +101,30 @@ function quotaCountExceeded(count, max) {
101
101
  max
102
102
  };
103
103
  }
104
+ /** {@inheritDoc QuotaInactiveError} */
105
+ function quotaInactive(token) {
106
+ return {
107
+ code: "quotaInactive",
108
+ message: `${token.symbol} has no active quota in this market.`,
109
+ token
110
+ };
111
+ }
112
+ /** {@inheritDoc QuotaUnchangedError} */
113
+ function quotaUnchanged(args) {
114
+ return {
115
+ code: "quotaUnchanged",
116
+ message: `${args.token.symbol} quota of ${args.requested.value} rounds to the current ${args.current.value}.`,
117
+ ...args
118
+ };
119
+ }
120
+ /** {@inheritDoc QuotaAboveMaxError} */
121
+ function quotaAboveMax(args) {
122
+ return {
123
+ code: "quotaAboveMax",
124
+ message: `${args.token.symbol} quota of ${args.requested.value} exceeds maxQuota ${args.maxQuota.value}.`,
125
+ ...args
126
+ };
127
+ }
104
128
  /** {@inheritDoc InsufficientBalanceError} */
105
129
  function insufficientBalance(args = {}) {
106
130
  const { required, held } = args;
@@ -147,7 +171,10 @@ exports.leverageOutOfRange = leverageOutOfRange;
147
171
  exports.marketExpired = marketExpired;
148
172
  exports.poolPaused = poolPaused;
149
173
  exports.poolSunset = poolSunset;
174
+ exports.quotaAboveMax = quotaAboveMax;
150
175
  exports.quotaCountExceeded = quotaCountExceeded;
176
+ exports.quotaInactive = quotaInactive;
151
177
  exports.quotaLimitReached = quotaLimitReached;
178
+ exports.quotaUnchanged = quotaUnchanged;
152
179
  exports.reservePriceLimited = reservePriceLimited;
153
180
  exports.rwaOpenRequirementsNotMet = rwaOpenRequirementsNotMet;
@@ -171,9 +171,12 @@ exports.positionsTotalsSchema = require_model_positions_schema.positionsTotalsSc
171
171
  exports.priceFeedDataSchema = require_model_opportunities_schema.priceFeedDataSchema;
172
172
  exports.priceFeedSummarySchema = require_model_opportunities_schema.priceFeedSummarySchema;
173
173
  exports.protocolChartMetricSchema = require_model_charts_schema.protocolChartMetricSchema;
174
+ exports.quotaAboveMax = require_model_errors_operation_errors.quotaAboveMax;
174
175
  exports.quotaAssetSchema = require_model_opportunities_schema.quotaAssetSchema;
175
176
  exports.quotaCountExceeded = require_model_errors_operation_errors.quotaCountExceeded;
177
+ exports.quotaInactive = require_model_errors_operation_errors.quotaInactive;
176
178
  exports.quotaLimitReached = require_model_errors_operation_errors.quotaLimitReached;
179
+ exports.quotaUnchanged = require_model_errors_operation_errors.quotaUnchanged;
177
180
  exports.rateCurvePointSchema = require_model_opportunities_schema.rateCurvePointSchema;
178
181
  exports.rateCurveSchema = require_model_opportunities_schema.rateCurveSchema;
179
182
  exports.receivedAssetSchema = require_model_liquidations_schema.receivedAssetSchema;
@@ -65,6 +65,7 @@ var CreditAccountOperationsService = class extends require_onchain_base_SDKConst
65
65
  case "DEPOSIT": return require_onchain_accounts_intents_plan.planDeposit(intent, view);
66
66
  case "REPAY": return require_onchain_accounts_intents_plan.planRepay(intent, view);
67
67
  case "WITHDRAW": return require_onchain_accounts_intents_plan.planWithdraw(intent, view);
68
+ case "UPDATE_QUOTA": return require_onchain_accounts_intents_plan.planUpdateQuota(intent, view);
68
69
  default: throw new Error(`${intent.type} - not implemented`);
69
70
  }
70
71
  }, limits));
@@ -68,7 +68,7 @@ function buildQuotaUpdateOperation(input) {
68
68
  const quotaAssets = [...update.quotaIncrease, ...update.quotaDecrease];
69
69
  const calls = quotaAssets.length === 0 ? [] : sdk.accounts.prepareUpdateQuotas(creditAccount.creditFacade, {
70
70
  averageQuota: quotaAssets,
71
- minQuota: quotaAssets
71
+ minQuota: input.minQuota ?? quotaAssets
72
72
  });
73
73
  return {
74
74
  type: "changeQuota",
@@ -87,6 +87,26 @@ function planRepay(intent, view) {
87
87
  ];
88
88
  }
89
89
  /**
90
+ * One token's quota changes; no balance moves and debt is untouched.
91
+ *
92
+ * Only a token the account holds can be quoted here, and only on an account
93
+ * that owes something: the facade refuses any quota change at zero debt.
94
+ */
95
+ function planUpdateQuota(intent, view) {
96
+ const U = view.underlying;
97
+ if (require_onchain_accounts_intents_utils_common.eq(intent.token, U) || require_onchain_constants_math.isZeroBalance(view.balanceOf(intent.token))) throw new require_onchain_validation_raise.IntentPreviewError(require_model_errors_prepare_errors.unsupportedCollateralToken(require_onchain_validation_helpers_token.toToken(view.sdk, intent.token)), `updateQuota: ${intent.token} is the underlying or not held by the account`);
98
+ if (view.debt <= 0n) throw new require_onchain_validation_raise.IntentPreviewError(require_model_errors_operation_errors.debtOutOfRange({
99
+ requested: require_onchain_validation_helpers_token.toTokenAmount(view.sdk, U, 0n),
100
+ minDebt: require_onchain_validation_helpers_token.toTokenAmount(view.sdk, U, view.debtLimits.minDebt),
101
+ maxDebt: require_onchain_validation_helpers_token.toTokenAmount(view.sdk, U, view.debtLimits.maxDebt)
102
+ }), "updateQuota: the account has zero debt");
103
+ return [{
104
+ kind: "updateQuota",
105
+ token: intent.token,
106
+ quota: intent.quota
107
+ }];
108
+ }
109
+ /**
90
110
  * Intent 2.1: `W` of value leaves, debt shrinks by `D0 · W / C0` so leverage
91
111
  * holds. Both are funded by the source `S`.
92
112
  */
@@ -418,6 +438,7 @@ exports.planFinishCloseAccount = planFinishCloseAccount;
418
438
  exports.planFinishDecreaseLeverage = planFinishDecreaseLeverage;
419
439
  exports.planFinishWithdraw = planFinishWithdraw;
420
440
  exports.planRepay = planRepay;
441
+ exports.planUpdateQuota = planUpdateQuota;
421
442
  exports.planWithdraw = planWithdraw;
422
443
  exports.planWithdrawAsset = planWithdrawAsset;
423
444
  exports.planWithdrawDelayed = planWithdrawDelayed;
@@ -14,6 +14,7 @@ const require_onchain_accounts_intents_utils_price_impact = require("./utils/pri
14
14
  const require_onchain_accounts_intents_utils_quotas_for_update = require("./utils/quotas-for-update.js");
15
15
  const require_onchain_accounts_intents_utils_router_path = require("./utils/router-path.js");
16
16
  const require_onchain_accounts_intents_operations = require("./operations.js");
17
+ const require_onchain_accounts_intents_resolveQuotaUpdate = require("./resolveQuotaUpdate.js");
17
18
  const require_onchain_accounts_intents_withdraw_limits = require("./withdraw-limits.js");
18
19
  //#region src/onchain/accounts/intents/realize.ts
19
20
  /**
@@ -99,10 +100,11 @@ async function realize(steps, props) {
99
100
  traded.returnedUnd += underlyingValue(returned);
100
101
  };
101
102
  /**
102
- * Set by a `clearQuotas` step, which settles the quotas mid-walk instead of
103
- * at the end — and settles them at none, whatever the balances turn out to be.
103
+ * Set by a step that settles the quotas itself, mid-walk instead of at the
104
+ * end, whatever the balances turn out to be: `clearQuotas` at none,
105
+ * `updateQuota` at the one the intent names.
104
106
  */
105
- let cleared;
107
+ let plannedQuotas;
106
108
  /**
107
109
  * Whether anything leaves the account, which is what makes the credit manager
108
110
  * judge the closing collateral check at safe prices.
@@ -148,14 +150,34 @@ async function realize(steps, props) {
148
150
  }));
149
151
  break;
150
152
  }
151
- case "clearQuotas":
152
- cleared = require_onchain_accounts_intents_utils_quotas_for_update.clearedQuotas(creditAccount.tokens);
153
+ case "clearQuotas": {
154
+ const cleared = require_onchain_accounts_intents_utils_quotas_for_update.clearedQuotas(creditAccount.tokens);
155
+ plannedQuotas = cleared;
153
156
  if (cleared.quotaDecrease.length > 0) push(require_onchain_accounts_intents_operations.buildQuotaUpdateOperation({
154
157
  update: cleared,
155
158
  creditAccount,
156
159
  sdk
157
160
  }));
158
161
  break;
162
+ }
163
+ case "updateQuota": {
164
+ const { update, minQuota } = require_onchain_accounts_intents_resolveQuotaUpdate.resolveQuotaUpdate({
165
+ sdk,
166
+ creditAccount,
167
+ token: step.token,
168
+ quota: step.quota,
169
+ quotaReserve,
170
+ limits: props.limits
171
+ });
172
+ plannedQuotas = update;
173
+ push(require_onchain_accounts_intents_operations.buildQuotaUpdateOperation({
174
+ update,
175
+ creditAccount,
176
+ sdk,
177
+ minQuota
178
+ }));
179
+ break;
180
+ }
159
181
  case "convert": {
160
182
  const amount = amountOf(step.amount);
161
183
  if (amount <= 0n) {
@@ -336,7 +358,7 @@ async function realize(steps, props) {
336
358
  const floor = ledger.snapshot();
337
359
  const { assets, debt } = floor;
338
360
  const projected = expected.snapshot();
339
- const quotas = cleared ?? require_onchain_accounts_intents_utils_quotas_for_update.withDirectTransferQuota(require_onchain_accounts_intents_utils_quotas_for_update.getQuotasForUpdate({
361
+ const quotas = plannedQuotas ?? require_onchain_accounts_intents_utils_quotas_for_update.withDirectTransferQuota(require_onchain_accounts_intents_utils_quotas_for_update.getQuotasForUpdate({
340
362
  assetsBefore: creditAccount.tokens,
341
363
  assetsAfter: assets,
342
364
  initialQuotas: creditAccount.tokens,
@@ -399,7 +421,7 @@ async function realize(steps, props) {
399
421
  after: projected.assets,
400
422
  limits: props.limits
401
423
  });
402
- if (!cleared && quotas.quotaIncrease.length + quotas.quotaDecrease.length > 0) {
424
+ if (!plannedQuotas && quotas.quotaIncrease.length + quotas.quotaDecrease.length > 0) {
403
425
  require_onchain_accounts_intents_guards.assertQuotaAvailable(sdk, market, quotas.quotaIncrease, props.limits);
404
426
  push(require_onchain_accounts_intents_operations.buildQuotaUpdateOperation({
405
427
  update: quotas,
@@ -0,0 +1,149 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_onchain_utils_bigint_math = require("../../utils/bigint-math.js");
3
+ const require_onchain_constants_math = require("../../constants/math.js");
4
+ const require_onchain_validation_helpers_token = require("../../validation/helpers/token.js");
5
+ const require_onchain_validation_checks_checkForbiddenToken = require("../../validation/checks/checkForbiddenToken.js");
6
+ const require_onchain_validation_checks_checkMaxQuota = require("../../validation/checks/checkMaxQuota.js");
7
+ const require_onchain_validation_checks_checkQuotaActive = require("../../validation/checks/checkQuotaActive.js");
8
+ const require_onchain_validation_checks_checkQuotaChange = require("../../validation/checks/checkQuotaChange.js");
9
+ const require_onchain_validation_checks_checkQuotaLimit = require("../../validation/checks/checkQuotaLimit.js");
10
+ const require_onchain_validation_raise = require("../../validation/raise.js");
11
+ require("../../validation/index.js");
12
+ const require_onchain_accounts_intents_utils_common = require("./utils/common.js");
13
+ const require_onchain_accounts_intents_guards = require("./guards.js");
14
+ const require_onchain_accounts_quota_utils = require("../quota-utils.js");
15
+ const require_onchain_accounts_intents_utils_quotas_for_update = require("./utils/quotas-for-update.js");
16
+ //#region src/onchain/accounts/intents/resolveQuotaUpdate.ts
17
+ /**
18
+ * Synchronous calculation from the SDK's loaded market state; no RPC reads.
19
+ * @throws IntentPreviewError when quota validation rejects the change.
20
+ *
21
+ * The single `updateQuota` an `UPDATE_QUOTA` intent sends, checked against
22
+ * what the facade and the quota keeper would revert on.
23
+ *
24
+ * A target is taken as named and refused when the market cannot meet it. A
25
+ * sized quota is held to what the market can give instead: an increase is capped
26
+ * at the pool's available quota, and `minQuota` accepts a partial fill so long as the
27
+ * token stays enabled.
28
+ */
29
+ function resolveQuotaUpdate(props) {
30
+ const { sdk, creditAccount, quotaReserve, limits } = props;
31
+ const suite = sdk.marketRegister.findCreditManager(creditAccount.creditManager);
32
+ const { market } = suite;
33
+ const { pqk } = market.pool;
34
+ const tokenLc = props.token.toLowerCase();
35
+ const token = require_onchain_validation_helpers_token.toToken(sdk, tokenLc);
36
+ const underlying = require_onchain_validation_helpers_token.toToken(sdk, market.pool.underlying);
37
+ const current = creditAccount.tokens.find((t) => require_onchain_accounts_intents_utils_common.eq(t.token, tokenLc))?.quota ?? 0n;
38
+ require_onchain_validation_raise.raise(require_onchain_validation_checks_checkQuotaActive.checkQuotaActive({
39
+ token,
40
+ isActive: pqk.quotas.get(tokenLc)?.isActive ?? false
41
+ }), `updateQuota: ${tokenLc} has no active quota`);
42
+ let resolved;
43
+ if (props.quota === void 0) {
44
+ const price = (from, to, amount) => market.priceOracle.safeConvert(from, to, amount).value;
45
+ resolved = sizedChange(current, require_onchain_accounts_intents_utils_quotas_for_update.resizedQuota({
46
+ token: tokenLc,
47
+ assets: creditAccount.tokens,
48
+ initialQuotas: creditAccount.tokens,
49
+ quotaReserve,
50
+ underlyingToken: market.pool.underlying,
51
+ liquidationThresholds: suite.creditManager.liquidationThresholds,
52
+ quotas: pqk.quotas,
53
+ maxDebt: suite.creditFacade.maxDebt,
54
+ convert: price
55
+ }), tokenLc, require_onchain_accounts_quota_utils.roundUpQuota(pqk.quotaAvailable(tokenLc)));
56
+ if (resolved.change === 0n && resolved.requested > current) require_onchain_validation_raise.raise(require_onchain_validation_checks_checkQuotaLimit.checkQuotaLimit({
57
+ token,
58
+ requested: resolved.requested - current,
59
+ available: 0n,
60
+ ...limits,
61
+ underlying
62
+ }), `updateQuota: the pool has no quota left for ${tokenLc}`);
63
+ } else resolved = targetChange(current, props.quota);
64
+ const { requested, change, resulting } = resolved;
65
+ require_onchain_validation_raise.raise(require_onchain_validation_checks_checkQuotaChange.checkQuotaChange({
66
+ token,
67
+ current,
68
+ requested,
69
+ change,
70
+ underlying
71
+ }), `updateQuota: ${requested} rounds to the current ${current}`);
72
+ if (change > 0n) require_onchain_validation_raise.raise(require_onchain_validation_checks_checkForbiddenToken.checkForbiddenToken({
73
+ token,
74
+ isForbidden: suite.isForbidden(tokenLc)
75
+ }), `updateQuota: ${tokenLc} is forbidden, its quota cannot grow`);
76
+ if (props.quota !== void 0) {
77
+ const maxQuota = require_onchain_constants_math.MAX_QUOTA_MULTIPLIER * suite.creditFacade.maxDebt;
78
+ require_onchain_validation_raise.raise(require_onchain_validation_checks_checkMaxQuota.checkMaxQuota({
79
+ token,
80
+ requested: resulting,
81
+ maxQuota,
82
+ underlying
83
+ }), `updateQuota: ${resulting} exceeds maxQuota ${maxQuota}`);
84
+ if (change > 0n) require_onchain_accounts_intents_guards.assertQuotaAvailable(sdk, market, [{
85
+ token: tokenLc,
86
+ balance: change
87
+ }], limits);
88
+ }
89
+ const entry = {
90
+ token: tokenLc,
91
+ balance: change
92
+ };
93
+ return {
94
+ update: {
95
+ desiredQuota: { [tokenLc]: {
96
+ token: tokenLc,
97
+ balance: resulting
98
+ } },
99
+ quotaIncrease: change > 0n ? [entry] : [],
100
+ quotaDecrease: change < 0n ? [entry] : []
101
+ },
102
+ minQuota: [{
103
+ token: tokenLc,
104
+ balance: resolved.minQuota
105
+ }]
106
+ };
107
+ }
108
+ function targetChange(current, quota) {
109
+ const target = require_onchain_utils_bigint_math.BigIntMath.max(quota, 0n);
110
+ if (target === 0n) return {
111
+ requested: 0n,
112
+ change: current > 0n ? require_onchain_constants_math.MIN_INT96 : 0n,
113
+ resulting: 0n,
114
+ minQuota: 0n
115
+ };
116
+ const change = require_onchain_accounts_quota_utils.roundUpQuota(target - current);
117
+ return {
118
+ requested: target,
119
+ change,
120
+ resulting: current + change,
121
+ minQuota: current + change
122
+ };
123
+ }
124
+ /**
125
+ * Reads the one token's change back out of {@link resizedQuota}, then caps an
126
+ * increase at `available`.
127
+ */
128
+ function sizedChange(current, sized, token, available) {
129
+ const requested = sized.desiredQuota[token]?.balance ?? current;
130
+ const decrease = sized.quotaDecrease.find((a) => a.token === token)?.balance;
131
+ if (decrease !== void 0) {
132
+ const resulting = decrease === -39614081257132168796771975168n ? 0n : current + decrease;
133
+ return {
134
+ requested,
135
+ change: decrease,
136
+ resulting,
137
+ minQuota: resulting
138
+ };
139
+ }
140
+ const increase = require_onchain_utils_bigint_math.BigIntMath.min(sized.quotaIncrease.find((a) => a.token === token)?.balance ?? 0n, available);
141
+ return {
142
+ requested,
143
+ change: increase,
144
+ resulting: current + increase,
145
+ minQuota: increase > 0n ? require_onchain_utils_bigint_math.BigIntMath.max(current, require_onchain_constants_math.PERCENTAGE_FACTOR) : current
146
+ };
147
+ }
148
+ //#endregion
149
+ exports.resolveQuotaUpdate = resolveQuotaUpdate;
@@ -340,6 +340,7 @@ function buildMockSdk(args) {
340
340
  } }
341
341
  },
342
342
  marketRegister: {
343
+ creditManagers: [creditManagerSuite],
343
344
  findByCreditManager: vitest.vi.fn(() => market),
344
345
  findCreditManager: vitest.vi.fn(() => creditManagerSuite)
345
346
  },
@@ -0,0 +1,102 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_onchain_constants_math = require("../../../constants/math.js");
3
+ const require_market = require("../testing/market.js");
4
+ //#region src/onchain/accounts/intents/tests/update-quota.fixtures.ts
5
+ /**
6
+ * Start update-quota fixtures.
7
+ *
8
+ * The account holds 1000 UND and 2000 ANY (another 1000 UND) against 500 UND of
9
+ * debt. Nothing moves, so every case is a single `changeQuota` and the totals
10
+ * stand still.
11
+ */
12
+ const BASE_UND = 100000000000n;
13
+ const BALANCE_ANY = 2000000000000000000000n;
14
+ const DEBT = 50000000000n;
15
+ /** What 2000 ANY is sized to: 1000 UND × 92%. */
16
+ const SIZED_ANY = 92000000000n;
17
+ const TOTAL_VALUE = BASE_UND + require_market.valueInUnd(BALANCE_ANY, require_market.ANY);
18
+ /** Omitted quota on an unquoted balance: bought at balance × LT. */
19
+ const case_auto_increase = {
20
+ intent: {
21
+ type: "UPDATE_QUOTA",
22
+ token: require_market.ANY
23
+ },
24
+ current: 0n,
25
+ ops: [{
26
+ type: "changeQuota",
27
+ quotaIncrease: [{
28
+ token: require_market.ANY,
29
+ balance: SIZED_ANY
30
+ }],
31
+ quotaDecrease: [],
32
+ desiredQuota: {}
33
+ }],
34
+ quotaAfter: SIZED_ANY,
35
+ minQuota: 10000n
36
+ };
37
+ /** A lower target: the quota drops to exactly it. */
38
+ const case_target_decrease = {
39
+ intent: {
40
+ type: "UPDATE_QUOTA",
41
+ token: require_market.ANY,
42
+ quota: 40000000000n
43
+ },
44
+ current: SIZED_ANY,
45
+ ops: [{
46
+ type: "changeQuota",
47
+ quotaIncrease: [],
48
+ quotaDecrease: [{
49
+ token: require_market.ANY,
50
+ balance: 40000000000n - SIZED_ANY
51
+ }],
52
+ desiredQuota: {}
53
+ }],
54
+ quotaAfter: 40000000000n,
55
+ minQuota: 40000000000n
56
+ };
57
+ /** Target 0: the quota is reset with the sentinel. */
58
+ const case_target_disable = {
59
+ intent: {
60
+ type: "UPDATE_QUOTA",
61
+ token: require_market.ANY,
62
+ quota: 0n
63
+ },
64
+ current: SIZED_ANY,
65
+ ops: [{
66
+ type: "changeQuota",
67
+ quotaIncrease: [],
68
+ quotaDecrease: [{
69
+ token: require_market.ANY,
70
+ balance: require_onchain_constants_math.MIN_INT96
71
+ }],
72
+ desiredQuota: {}
73
+ }],
74
+ quotaAfter: 0n,
75
+ minQuota: 0n
76
+ };
77
+ function buildUpdateQuotaSdk(c) {
78
+ return require_market.buildMarketSdk(c.extras);
79
+ }
80
+ function buildUpdateQuotaProps(c, sdk) {
81
+ return {
82
+ intent: c.intent,
83
+ creditAccount: require_market.buildFixtureCreditAccount({
84
+ totalDebt: c.totalDebt ?? 50000000000n,
85
+ tokens: [...c.others ?? [require_market.caToken("0x3333333333333333333333333333333333333333", 100000000000n)], require_market.caToken(require_market.ANY, BALANCE_ANY, c.current)]
86
+ }),
87
+ sdk,
88
+ quotaReserve: void 0,
89
+ slippage: void 0
90
+ };
91
+ }
92
+ //#endregion
93
+ exports.BALANCE_ANY = BALANCE_ANY;
94
+ exports.BASE_UND = BASE_UND;
95
+ exports.DEBT = DEBT;
96
+ exports.SIZED_ANY = SIZED_ANY;
97
+ exports.TOTAL_VALUE = TOTAL_VALUE;
98
+ exports.buildUpdateQuotaProps = buildUpdateQuotaProps;
99
+ exports.buildUpdateQuotaSdk = buildUpdateQuotaSdk;
100
+ exports.case_auto_increase = case_auto_increase;
101
+ exports.case_target_decrease = case_target_decrease;
102
+ exports.case_target_disable = case_target_disable;
@@ -27,6 +27,7 @@ exports.pickFattestNonPhantomToken = require_onchain_accounts_intents_utils_pick
27
27
  exports.quotaIncreaseLimit = require_onchain_accounts_intents_utils_quotas_for_update.quotaIncreaseLimit;
28
28
  exports.quotasAfterUpdate = require_onchain_accounts_intents_utils_quotas_for_update.quotasAfterUpdate;
29
29
  exports.rankAccountTokens = require_onchain_accounts_intents_utils_pick_token.rankAccountTokens;
30
+ exports.resizedQuota = require_onchain_accounts_intents_utils_quotas_for_update.resizedQuota;
30
31
  exports.resolveCreditManager = require_onchain_accounts_intents_utils_common.resolveCreditManager;
31
32
  exports.startProbe = require_onchain_accounts_intents_utils_price_impact.startProbe;
32
33
  exports.toCreditAccountSlice = require_onchain_accounts_intents_utils_credit_account_slice.toCreditAccountSlice;
@@ -5,17 +5,28 @@ const require_onchain_utils_mappers = require("../../../utils/mappers.js");
5
5
  require("../../../constants/index.js");
6
6
  const require_onchain_accounts_quota_utils = require("../../quota-utils.js");
7
7
  //#region src/onchain/accounts/intents/utils/quotas-for-update.ts
8
- function getQuotasForUpdate({ assetsBefore, assetsAfter, initialQuotas, quotaReserve = 0, liquidationThresholds: liquidationThresholdsMap, quotas: quotasMap, maxDebt, underlyingToken, convert }) {
8
+ function getQuotasForUpdate(props) {
9
+ const assetsAfterLc = lowercased(props.assetsAfter);
10
+ const { spend, obtain } = collectQuotaChange(lowercased(props.assetsBefore), assetsAfterLc);
11
+ return sizeQuotas(assetsAfterLc, spend, obtain, props);
12
+ }
13
+ /**
14
+ * The update that sizes one token's quota to the balance the account holds of
15
+ * it, whatever moved.
16
+ *
17
+ * Sits beside {@link getQuotasForUpdate} because that one only resizes what an
18
+ * operation spent or obtained, and an operation that changes a quota alone
19
+ * moves no balance at all.
20
+ */
21
+ function resizedQuota(props) {
22
+ const entry = [{
23
+ token: props.token.toLowerCase(),
24
+ balance: 0n
25
+ }];
26
+ return sizeQuotas(lowercased(props.assets), entry, entry, props);
27
+ }
28
+ function sizeQuotas(assetsAfterLc, spend, obtain, { initialQuotas, quotaReserve = 0, liquidationThresholds: liquidationThresholdsMap, quotas: quotasMap, maxDebt, underlyingToken, convert }) {
9
29
  const underlyingTokenLc = underlyingToken.toLowerCase();
10
- const assetsBeforeLc = assetsBefore.map((a) => ({
11
- ...a,
12
- token: a.token.toLowerCase()
13
- }));
14
- const assetsAfterLc = assetsAfter.map((a) => ({
15
- ...a,
16
- token: a.token.toLowerCase()
17
- }));
18
- const { spend, obtain } = collectQuotaChange(assetsBeforeLc, assetsAfterLc);
19
30
  const initialQuotasLc = initialQuotas.map((a) => {
20
31
  const tokenLc = a.token.toLowerCase();
21
32
  return [tokenLc, {
@@ -131,6 +142,12 @@ function quotasAfterUpdate(initialQuotas, desiredQuota) {
131
142
  else delete after[token];
132
143
  return after;
133
144
  }
145
+ function lowercased(assets) {
146
+ return assets.map((a) => ({
147
+ ...a,
148
+ token: a.token.toLowerCase()
149
+ }));
150
+ }
134
151
  function collectQuotaChange(assetsBefore, assetsAfter) {
135
152
  const before = new Map(assetsBefore.map((a) => [a.token, a.balance]));
136
153
  const after = new Map(assetsAfter.map((a) => [a.token, a.balance]));
@@ -238,4 +255,5 @@ exports.clearedQuotas = clearedQuotas;
238
255
  exports.getQuotasForUpdate = getQuotasForUpdate;
239
256
  exports.quotaIncreaseLimit = quotaIncreaseLimit;
240
257
  exports.quotasAfterUpdate = quotasAfterUpdate;
258
+ exports.resizedQuota = resizedQuota;
241
259
  exports.withDirectTransferQuota = withDirectTransferQuota;
@@ -46,6 +46,7 @@ exports.BotPermissions = require_onchain_constants_bot_permissions.BotPermission
46
46
  exports.DUST_THRESHOLD = require_onchain_constants_math.DUST_THRESHOLD;
47
47
  exports.LEVERAGE_DECIMALS = require_onchain_constants_math.LEVERAGE_DECIMALS;
48
48
  exports.MAX_INT = require_onchain_constants_math.MAX_INT;
49
+ exports.MAX_QUOTA_MULTIPLIER = require_onchain_constants_math.MAX_QUOTA_MULTIPLIER;
49
50
  exports.MAX_UINT16 = require_onchain_constants_math.MAX_UINT16;
50
51
  exports.MAX_UINT256 = require_onchain_constants_math.MAX_UINT256;
51
52
  exports.MIN_INT96 = require_onchain_constants_math.MIN_INT96;
@@ -18,6 +18,11 @@ const PERCENTAGE_FACTOR_1KK = PERCENTAGE_FACTOR * PERCENTAGE_DECIMALS;
18
18
  const LEVERAGE_DECIMALS = 100n;
19
19
  const SLIPPAGE_DECIMALS = 100n;
20
20
  /**
21
+ * The facade's `maxQuotaMultiplier`: a token's quota may not exceed this many
22
+ * times `maxDebt`. A constant on-chain, so it is not read.
23
+ **/
24
+ const MAX_QUOTA_MULTIPLIER = 2n;
25
+ /**
21
26
  * Token balances at or below this threshold are treated as dust and ignored.
22
27
  **/
23
28
  const DUST_THRESHOLD = 10n;
@@ -35,6 +40,7 @@ function isZeroBalance(balance) {
35
40
  exports.DUST_THRESHOLD = DUST_THRESHOLD;
36
41
  exports.LEVERAGE_DECIMALS = LEVERAGE_DECIMALS;
37
42
  exports.MAX_INT = MAX_INT;
43
+ exports.MAX_QUOTA_MULTIPLIER = MAX_QUOTA_MULTIPLIER;
38
44
  exports.MAX_UINT16 = MAX_UINT16;
39
45
  exports.MAX_UINT256 = MAX_UINT256;
40
46
  exports.MIN_INT96 = MIN_INT96;
@@ -212,9 +212,12 @@ const require_onchain_validation_checks_checkForbiddenToken = require("./validat
212
212
  const require_onchain_validation_checks_checkLeverage = require("./validation/checks/checkLeverage.js");
213
213
  const require_onchain_validation_checks_checkLiquidatorEligible = require("./validation/checks/checkLiquidatorEligible.js");
214
214
  const require_onchain_validation_checks_checkMarketExpired = require("./validation/checks/checkMarketExpired.js");
215
+ const require_onchain_validation_checks_checkMaxQuota = require("./validation/checks/checkMaxQuota.js");
215
216
  const require_onchain_validation_checks_checkPoolLiquidity = require("./validation/checks/checkPoolLiquidity.js");
216
217
  const require_onchain_validation_checks_checkPoolPaused = require("./validation/checks/checkPoolPaused.js");
217
218
  const require_onchain_validation_checks_checkPoolSunset = require("./validation/checks/checkPoolSunset.js");
219
+ const require_onchain_validation_checks_checkQuotaActive = require("./validation/checks/checkQuotaActive.js");
220
+ const require_onchain_validation_checks_checkQuotaChange = require("./validation/checks/checkQuotaChange.js");
218
221
  const require_onchain_validation_checks_checkQuotaCount = require("./validation/checks/checkQuotaCount.js");
219
222
  const require_onchain_validation_checks_checkQuotaLimit = require("./validation/checks/checkQuotaLimit.js");
220
223
  const require_onchain_validation_checks_checkReservePriceLimited = require("./validation/checks/checkReservePriceLimited.js");
@@ -227,6 +230,7 @@ const require_onchain_validation_bundles_checkIncreaseDebt = require("./validati
227
230
  const require_onchain_validation_bundles_checkIncreaseQuota = require("./validation/bundles/checkIncreaseQuota.js");
228
231
  const require_onchain_validation_bundles_checkMarket = require("./validation/bundles/checkMarket.js");
229
232
  const require_onchain_validation_bundles_checkObtained = require("./validation/bundles/checkObtained.js");
233
+ const require_onchain_validation_bundles_checkQuotaUpdates = require("./validation/bundles/checkQuotaUpdates.js");
230
234
  const require_onchain_validation_bundles_checkMidasAccountGreenlist = require("./validation/bundles/checkMidasAccountGreenlist.js");
231
235
  const require_onchain_validation_bundles_checkRWAOpenRequirements = require("./validation/bundles/checkRWAOpenRequirements.js");
232
236
  const require_onchain_validation_bundles_checkRWAOpening = require("./validation/bundles/checkRWAOpening.js");
@@ -421,6 +425,7 @@ exports.LinearInterestRateModelContract = require_onchain_market_pool_LinearInte
421
425
  exports.LiquidationsService = require_onchain_accounts_liquidations_LiquidationsService.LiquidationsService;
422
426
  exports.MAX_INT = require_onchain_constants_math.MAX_INT;
423
427
  exports.MAX_LEVERAGE_BUFFER_BPS = require_onchain_market_math.MAX_LEVERAGE_BUFFER_BPS;
428
+ exports.MAX_QUOTA_MULTIPLIER = require_onchain_constants_math.MAX_QUOTA_MULTIPLIER;
424
429
  exports.MAX_UINT16 = require_onchain_constants_math.MAX_UINT16;
425
430
  exports.MAX_UINT256 = require_onchain_constants_math.MAX_UINT256;
426
431
  exports.MIN_HEALTH_FACTOR_FACADE = require_onchain_validation_helpers_health_factor_limits.MIN_HEALTH_FACTOR_FACADE;
@@ -588,6 +593,7 @@ exports.checkLiquidationFunding = require_onchain_validation_bundles_checkLiquid
588
593
  exports.checkLiquidatorEligible = require_onchain_validation_checks_checkLiquidatorEligible.checkLiquidatorEligible;
589
594
  exports.checkMarket = require_onchain_validation_bundles_checkMarket.checkMarket;
590
595
  exports.checkMarketExpired = require_onchain_validation_checks_checkMarketExpired.checkMarketExpired;
596
+ exports.checkMaxQuota = require_onchain_validation_checks_checkMaxQuota.checkMaxQuota;
591
597
  exports.checkMidasAccountGreenlist = require_onchain_validation_bundles_checkMidasAccountGreenlist.checkMidasAccountGreenlist;
592
598
  exports.checkObtained = require_onchain_validation_bundles_checkObtained.checkObtained;
593
599
  exports.checkOperation = require_onchain_validation_checkOperation.checkOperation;
@@ -596,8 +602,11 @@ exports.checkPoolLiquidity = require_onchain_validation_checks_checkPoolLiquidit
596
602
  exports.checkPoolOperation = require_onchain_validation_bundles_checkPoolOperation.checkPoolOperation;
597
603
  exports.checkPoolPaused = require_onchain_validation_checks_checkPoolPaused.checkPoolPaused;
598
604
  exports.checkPoolSunset = require_onchain_validation_checks_checkPoolSunset.checkPoolSunset;
605
+ exports.checkQuotaActive = require_onchain_validation_checks_checkQuotaActive.checkQuotaActive;
606
+ exports.checkQuotaChange = require_onchain_validation_checks_checkQuotaChange.checkQuotaChange;
599
607
  exports.checkQuotaCount = require_onchain_validation_checks_checkQuotaCount.checkQuotaCount;
600
608
  exports.checkQuotaLimit = require_onchain_validation_checks_checkQuotaLimit.checkQuotaLimit;
609
+ exports.checkQuotaUpdates = require_onchain_validation_bundles_checkQuotaUpdates.checkQuotaUpdates;
601
610
  exports.checkRWAOpenRequirements = require_onchain_validation_bundles_checkRWAOpenRequirements.checkRWAOpenRequirements;
602
611
  exports.checkRWAOpening = require_onchain_validation_bundles_checkRWAOpening.checkRWAOpening;
603
612
  exports.checkReservePriceLimited = require_onchain_validation_checks_checkReservePriceLimited.checkReservePriceLimited;
@@ -43,7 +43,7 @@ function calcHealthFactor(props) {
43
43
  const quota = snapshot.quotas.find((q) => (0, viem.isAddressEqual)(q.token, token));
44
44
  const quotaBalance = quota && (active.get(token) ?? false) ? quota.balance : 0n;
45
45
  const quotaWeighted = (convertToUSD(underlying, quotaBalance) ?? 0n) * require_onchain_constants_math.PERCENTAGE_FACTOR;
46
- return acc + (quota ? require_onchain_utils_bigint_math.BigIntMath.min(quotaWeighted, tokenLtWeighted) : tokenLtWeighted);
46
+ return acc + (quota || active.get(token) ? require_onchain_utils_bigint_math.BigIntMath.min(quotaWeighted, tokenLtWeighted) : tokenLtWeighted);
47
47
  }, 0n);
48
48
  const borrowedValue = convertToUSD(underlying, snapshot.totalDebt) ?? 0n;
49
49
  const hf = borrowedValue > 0n ? assetValue / borrowedValue : 0n;
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_onchain_utils_AssetsMap = require("../../utils/AssetsMap.js");
3
3
  const require_onchain_constants_math = require("../../constants/math.js");
4
+ const require_onchain_accounts_quota_utils = require("../../accounts/quota-utils.js");
4
5
  let viem = require("viem");
5
6
  //#region src/onchain/preview/preview/CreditAccountState.ts
6
7
  /**
@@ -130,7 +131,8 @@ var CreditAccountState = class CreditAccountState {
130
131
  /**
131
132
  * Applies a relative `updateQuota` change to the token's quota:
132
133
  * `MIN_INT96` is the facade "disable quota" sentinel and zeroes it, other
133
- * changes are added with the result clamped at zero (quotas cannot go
134
+ * changes are rounded toward zero to a `PERCENTAGE_FACTOR` step, as the
135
+ * facade does, and added with the result clamped at zero (quotas cannot go
134
136
  * negative on-chain).
135
137
  */
136
138
  updateQuota(token, change) {
@@ -138,7 +140,7 @@ var CreditAccountState = class CreditAccountState {
138
140
  this.quotas.upsert(token, 0n);
139
141
  return;
140
142
  }
141
- const next = this.quotas.getOrZero(token) + change;
143
+ const next = this.quotas.getOrZero(token) + require_onchain_accounts_quota_utils.roundUpQuota(change);
142
144
  this.quotas.upsert(token, next > 0n ? next : 0n);
143
145
  }
144
146
  };