@gearbox-protocol/sdk 16.0.0-next.17 → 16.0.0-next.19

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 (197) hide show
  1. package/dist/cjs/common-utils/index.js +3 -21
  2. package/dist/cjs/common-utils/test-utils/index.js +4 -3
  3. package/dist/cjs/common-utils/utils/index.js +3 -22
  4. package/dist/cjs/common-utils/utils/strategies/index.js +3 -0
  5. package/dist/cjs/common-utils/utils/strategies/strategy-info/cm-availability-condition.js +5 -5
  6. package/dist/cjs/common-utils/utils/strategies/strategy-info/credit-manager-issues.js +135 -0
  7. package/dist/cjs/common-utils/utils/strategies/strategy-info/get-cm-you-can-earn.js +12 -23
  8. package/dist/cjs/common-utils/utils/strategies/strategy-info/index.js +3 -0
  9. package/dist/cjs/onchain/accounts/index.js +2 -3
  10. package/dist/cjs/onchain/accounts/intents/guards.js +55 -50
  11. package/dist/cjs/onchain/accounts/intents/index.js +24 -16
  12. package/dist/cjs/onchain/accounts/intents/leverage-band.js +2 -2
  13. package/dist/cjs/onchain/accounts/intents/math.js +15 -22
  14. package/dist/cjs/onchain/accounts/intents/open-strategy.js +5 -5
  15. package/dist/cjs/onchain/accounts/intents/plan.js +27 -41
  16. package/dist/cjs/onchain/accounts/intents/realize.js +14 -21
  17. package/dist/cjs/onchain/accounts/intents/tail.js +2 -2
  18. package/dist/cjs/onchain/accounts/intents/testing/sdk-mock.js +2 -1
  19. package/dist/cjs/onchain/accounts/intents/view.js +1 -0
  20. package/dist/cjs/onchain/constants/index.js +1 -0
  21. package/dist/cjs/onchain/constants/math.js +11 -0
  22. package/dist/cjs/onchain/index.js +32 -3
  23. package/dist/cjs/onchain/market/credit/CreditManagerV310Contract.js +2 -2
  24. package/dist/cjs/onchain/market/math.js +23 -11
  25. package/dist/cjs/onchain/validation/checks.js +250 -0
  26. package/dist/cjs/onchain/validation/index.js +29 -0
  27. package/dist/cjs/onchain/{accounts/intents → validation}/refusal.js +12 -1
  28. package/dist/cjs/onchain/validation/token.js +29 -0
  29. package/dist/cjs/preview/index.js +10 -0
  30. package/dist/cjs/preview/preview/buildDelayedPreview.js +1 -0
  31. package/dist/cjs/preview/preview/previewAdjustCreditAccount.js +1 -0
  32. package/dist/cjs/preview/preview/previewOpenCreditAccount.js +1 -0
  33. package/dist/cjs/preview/validate/checkOperation.js +173 -0
  34. package/dist/cjs/preview/validate/checkSimulation.js +52 -0
  35. package/dist/cjs/preview/validate/index.js +6 -0
  36. package/dist/cjs/sdk/index.js +4 -0
  37. package/dist/cjs/sdk/prepare/PrepareApi.js +23 -17
  38. package/dist/cjs/sdk/prepare/index.js +4 -0
  39. package/dist/cjs/sdk/prepare/types.js +4 -0
  40. package/dist/esm/common-utils/index.js +2 -11
  41. package/dist/esm/common-utils/test-utils/index.js +4 -3
  42. package/dist/esm/common-utils/utils/index.js +2 -12
  43. package/dist/esm/common-utils/utils/strategies/index.js +2 -1
  44. package/dist/esm/common-utils/utils/strategies/strategy-info/cm-availability-condition.js +5 -5
  45. package/dist/esm/common-utils/utils/strategies/strategy-info/credit-manager-issues.js +133 -0
  46. package/dist/esm/common-utils/utils/strategies/strategy-info/get-cm-you-can-earn.js +12 -23
  47. package/dist/esm/common-utils/utils/strategies/strategy-info/index.js +2 -1
  48. package/dist/esm/dev/AccountOpener.js +1 -1
  49. package/dist/esm/dev/withdrawalUtils.js +1 -1
  50. package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +2 -2
  51. package/dist/esm/onchain/accounts/index.js +2 -2
  52. package/dist/esm/onchain/accounts/intents/guards.js +55 -50
  53. package/dist/esm/onchain/accounts/intents/index.js +23 -14
  54. package/dist/esm/onchain/accounts/intents/leverage-band.js +2 -2
  55. package/dist/esm/onchain/accounts/intents/math.js +14 -21
  56. package/dist/esm/onchain/accounts/intents/open-strategy.js +4 -4
  57. package/dist/esm/onchain/accounts/intents/plan.js +15 -29
  58. package/dist/esm/onchain/accounts/intents/realize.js +12 -19
  59. package/dist/esm/onchain/accounts/intents/tail.js +1 -1
  60. package/dist/esm/onchain/accounts/intents/testing/sdk-mock.js +2 -1
  61. package/dist/esm/onchain/accounts/intents/view.js +1 -0
  62. package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +1 -1
  63. package/dist/esm/onchain/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
  64. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
  65. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
  66. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
  67. package/dist/esm/onchain/base/TokensMeta.js +3 -3
  68. package/dist/esm/onchain/chain/detectNetwork.js +1 -1
  69. package/dist/esm/onchain/constants/index.js +2 -2
  70. package/dist/esm/onchain/constants/math.js +11 -1
  71. package/dist/esm/onchain/core/createAddressProvider.js +1 -1
  72. package/dist/esm/onchain/index.js +7 -3
  73. package/dist/esm/onchain/market/adapters/contracts/AccountMigratorAdapterContract.js +1 -1
  74. package/dist/esm/onchain/market/adapters/contracts/ERC4626AdapterContract.js +1 -1
  75. package/dist/esm/onchain/market/credit/CreditFacadeV310BaseContract.js +1 -1
  76. package/dist/esm/onchain/market/credit/CreditManagerV310Contract.js +2 -2
  77. package/dist/esm/onchain/market/math.js +23 -11
  78. package/dist/esm/onchain/market/pool/PoolV310Contract.js +1 -1
  79. package/dist/esm/onchain/market/zapper/IETHZapperContract.js +1 -1
  80. package/dist/esm/onchain/market/zapper/ZapperContract.js +1 -1
  81. package/dist/esm/onchain/pools/PoolService.js +1 -1
  82. package/dist/esm/onchain/utils/viem/simulateWithPriceUpdates.js +1 -1
  83. package/dist/esm/onchain/validation/checks.js +230 -0
  84. package/dist/esm/onchain/validation/index.js +4 -0
  85. package/dist/esm/onchain/{accounts/intents → validation}/refusal.js +12 -2
  86. package/dist/esm/onchain/validation/token.js +27 -0
  87. package/dist/esm/preview/index.js +5 -1
  88. package/dist/esm/preview/preview/buildDelayedPreview.js +1 -0
  89. package/dist/esm/preview/preview/previewAdjustCreditAccount.js +1 -0
  90. package/dist/esm/preview/preview/previewOpenCreditAccount.js +1 -0
  91. package/dist/esm/preview/simulate/simulatePoolOperation.js +1 -1
  92. package/dist/esm/preview/trace/extractTransfers.js +1 -1
  93. package/dist/esm/preview/validate/checkOperation.js +171 -0
  94. package/dist/esm/preview/validate/checkSimulation.js +51 -0
  95. package/dist/esm/preview/validate/index.js +3 -0
  96. package/dist/esm/sdk/index.js +2 -1
  97. package/dist/esm/sdk/prepare/PrepareApi.js +21 -15
  98. package/dist/esm/sdk/prepare/index.js +2 -1
  99. package/dist/esm/sdk/prepare/types.js +2 -1
  100. package/dist/types/common-utils/index.d.ts +2 -12
  101. package/dist/types/common-utils/utils/index.d.ts +2 -13
  102. package/dist/types/common-utils/utils/strategies/index.d.ts +2 -1
  103. package/dist/types/common-utils/utils/strategies/strategy-info/credit-manager-issues.d.ts +34 -0
  104. package/dist/types/common-utils/utils/strategies/strategy-info/index.d.ts +2 -1
  105. package/dist/types/model/previews.d.ts +22 -0
  106. package/dist/types/onchain/accounts/index.d.ts +2 -2
  107. package/dist/types/onchain/accounts/intents/guards.d.ts +8 -4
  108. package/dist/types/onchain/accounts/intents/index.d.ts +20 -10
  109. package/dist/types/onchain/accounts/intents/leverage-band.d.ts +7 -2
  110. package/dist/types/onchain/accounts/intents/math.d.ts +2 -1
  111. package/dist/types/onchain/accounts/intents/plan.d.ts +3 -0
  112. package/dist/types/onchain/accounts/intents/types.d.ts +7 -1
  113. package/dist/types/onchain/constants/index.d.ts +2 -2
  114. package/dist/types/onchain/constants/math.d.ts +9 -1
  115. package/dist/types/onchain/index.d.ts +7 -3
  116. package/dist/types/onchain/market/credit/CreditManagerV310Contract.d.ts +1 -1
  117. package/dist/types/onchain/market/credit/types.d.ts +4 -3
  118. package/dist/types/onchain/market/math.d.ts +20 -9
  119. package/dist/types/onchain/validation/checks.d.ts +167 -0
  120. package/dist/types/onchain/validation/index.d.ts +4 -0
  121. package/dist/types/onchain/{accounts/intents → validation}/refusal.d.ts +100 -31
  122. package/dist/types/onchain/validation/token.d.ts +17 -0
  123. package/dist/types/preview/index.d.ts +5 -1
  124. package/dist/types/preview/validate/checkOperation.d.ts +46 -0
  125. package/dist/types/preview/validate/checkSimulation.d.ts +34 -0
  126. package/dist/types/preview/validate/index.d.ts +3 -0
  127. package/dist/types/sdk/index.d.ts +2 -2
  128. package/dist/types/sdk/prepare/PrepareApi.d.ts +3 -3
  129. package/dist/types/sdk/prepare/index.d.ts +2 -2
  130. package/dist/types/sdk/prepare/types.d.ts +8 -4
  131. package/package.json +1 -1
  132. package/dist/cjs/common-utils/utils/strategies/strategy-info/get-cm-you-can-earn.spec.js +0 -267
  133. package/dist/cjs/common-utils/utils/validation/index.js +0 -23
  134. package/dist/cjs/common-utils/utils/validation/is-zero-balance.js +0 -7
  135. package/dist/cjs/common-utils/utils/validation/validate-balance.js +0 -22
  136. package/dist/cjs/common-utils/utils/validation/validate-balance.spec.js +0 -54
  137. package/dist/cjs/common-utils/utils/validation/validate-balances.js +0 -17
  138. package/dist/cjs/common-utils/utils/validation/validate-balances.spec.js +0 -45
  139. package/dist/cjs/common-utils/utils/validation/validate-credit-manager.js +0 -8
  140. package/dist/cjs/common-utils/utils/validation/validate-credit-manager.spec.js +0 -36
  141. package/dist/cjs/common-utils/utils/validation/validate-hf.js +0 -10
  142. package/dist/cjs/common-utils/utils/validation/validate-hf.spec.js +0 -26
  143. package/dist/cjs/common-utils/utils/validation/validate-open-account-pool-quota-status.js +0 -14
  144. package/dist/cjs/common-utils/utils/validation/validate-open-account-pool-quota-status.spec.js +0 -29
  145. package/dist/cjs/common-utils/utils/validation/validate-open-account-pool-status.js +0 -37
  146. package/dist/cjs/common-utils/utils/validation/validate-open-account-pool-status.spec.js +0 -98
  147. package/dist/cjs/common-utils/utils/validation/validate-open-account.js +0 -18
  148. package/dist/cjs/common-utils/utils/validation/validate-open-account.spec.js +0 -56
  149. package/dist/cjs/common-utils/utils/validation/validate-quota.js +0 -23
  150. package/dist/cjs/common-utils/utils/validation/validate-quota.spec.js +0 -88
  151. package/dist/cjs/common-utils/utils/validation/validate-token-to-obtain.js +0 -18
  152. package/dist/cjs/common-utils/utils/validation/validate-token-to-obtain.spec.js +0 -36
  153. package/dist/cjs/common-utils/utils/validation/validation-types.js +0 -1
  154. package/dist/esm/common-utils/utils/strategies/strategy-info/get-cm-you-can-earn.spec.js +0 -264
  155. package/dist/esm/common-utils/utils/validation/index.js +0 -12
  156. package/dist/esm/common-utils/utils/validation/is-zero-balance.js +0 -6
  157. package/dist/esm/common-utils/utils/validation/validate-balance.js +0 -21
  158. package/dist/esm/common-utils/utils/validation/validate-balance.spec.js +0 -54
  159. package/dist/esm/common-utils/utils/validation/validate-balances.js +0 -16
  160. package/dist/esm/common-utils/utils/validation/validate-balances.spec.js +0 -45
  161. package/dist/esm/common-utils/utils/validation/validate-credit-manager.js +0 -7
  162. package/dist/esm/common-utils/utils/validation/validate-credit-manager.spec.js +0 -36
  163. package/dist/esm/common-utils/utils/validation/validate-hf.js +0 -8
  164. package/dist/esm/common-utils/utils/validation/validate-hf.spec.js +0 -26
  165. package/dist/esm/common-utils/utils/validation/validate-open-account-pool-quota-status.js +0 -13
  166. package/dist/esm/common-utils/utils/validation/validate-open-account-pool-quota-status.spec.js +0 -29
  167. package/dist/esm/common-utils/utils/validation/validate-open-account-pool-status.js +0 -36
  168. package/dist/esm/common-utils/utils/validation/validate-open-account-pool-status.spec.js +0 -98
  169. package/dist/esm/common-utils/utils/validation/validate-open-account.js +0 -17
  170. package/dist/esm/common-utils/utils/validation/validate-open-account.spec.js +0 -56
  171. package/dist/esm/common-utils/utils/validation/validate-quota.js +0 -22
  172. package/dist/esm/common-utils/utils/validation/validate-quota.spec.js +0 -88
  173. package/dist/esm/common-utils/utils/validation/validate-token-to-obtain.js +0 -17
  174. package/dist/esm/common-utils/utils/validation/validate-token-to-obtain.spec.js +0 -36
  175. package/dist/esm/common-utils/utils/validation/validation-types.js +0 -1
  176. package/dist/types/common-utils/utils/strategies/strategy-info/get-cm-you-can-earn.spec.d.ts +0 -1
  177. package/dist/types/common-utils/utils/validation/index.d.ts +0 -12
  178. package/dist/types/common-utils/utils/validation/is-zero-balance.d.ts +0 -4
  179. package/dist/types/common-utils/utils/validation/validate-balance.d.ts +0 -25
  180. package/dist/types/common-utils/utils/validation/validate-balance.spec.d.ts +0 -1
  181. package/dist/types/common-utils/utils/validation/validate-balances.d.ts +0 -13
  182. package/dist/types/common-utils/utils/validation/validate-balances.spec.d.ts +0 -1
  183. package/dist/types/common-utils/utils/validation/validate-credit-manager.d.ts +0 -13
  184. package/dist/types/common-utils/utils/validation/validate-credit-manager.spec.d.ts +0 -1
  185. package/dist/types/common-utils/utils/validation/validate-hf.d.ts +0 -12
  186. package/dist/types/common-utils/utils/validation/validate-hf.spec.d.ts +0 -1
  187. package/dist/types/common-utils/utils/validation/validate-open-account-pool-quota-status.d.ts +0 -10
  188. package/dist/types/common-utils/utils/validation/validate-open-account-pool-quota-status.spec.d.ts +0 -1
  189. package/dist/types/common-utils/utils/validation/validate-open-account-pool-status.d.ts +0 -26
  190. package/dist/types/common-utils/utils/validation/validate-open-account-pool-status.spec.d.ts +0 -1
  191. package/dist/types/common-utils/utils/validation/validate-open-account.d.ts +0 -25
  192. package/dist/types/common-utils/utils/validation/validate-open-account.spec.d.ts +0 -1
  193. package/dist/types/common-utils/utils/validation/validate-quota.d.ts +0 -24
  194. package/dist/types/common-utils/utils/validation/validate-quota.spec.d.ts +0 -1
  195. package/dist/types/common-utils/utils/validation/validate-token-to-obtain.d.ts +0 -17
  196. package/dist/types/common-utils/utils/validation/validate-token-to-obtain.spec.d.ts +0 -1
  197. package/dist/types/common-utils/utils/validation/validation-types.d.ts +0 -10
@@ -0,0 +1,230 @@
1
+ //#region src/onchain/validation/checks.ts
2
+ /**
3
+ * Every verdict the protocol can pass on an operation, as values.
4
+ *
5
+ * Each check is handed the numbers it compares — never a suite, a market or an
6
+ * SDK — so the engine, `checkOperation` and the strategy lists share one
7
+ * implementation.
8
+ *
9
+ * Ladders stay with the caller because they differ deliberately: the engine
10
+ * reports the tightest ceiling it found, the account-opening path the first one
11
+ * exceeded in its own order.
12
+ */
13
+ /** A factor at or below this is refused; kept for the callers that size on it. */
14
+ const MIN_HF_LIMITED = 10100n;
15
+ /** The same bar as a `required` argument — the lowest factor that passes. */
16
+ const MIN_HEALTH_FACTOR_FORM = 10101;
17
+ /** The bar the facade itself enforces: an account may end exactly at 1.0. */
18
+ const MIN_HEALTH_FACTOR_FACADE = 1e4;
19
+ /**
20
+ * The safe-price bar a form holds an account to. A step above the facade's,
21
+ * because a factor of exactly 1.0 at safe prices is already a refusal.
22
+ */
23
+ const MIN_SAFE_HEALTH_FACTOR_FORM = 10001;
24
+ /** A refusal names what a limit was measured in, never what it is worth. */
25
+ function amountOf(token, value) {
26
+ return {
27
+ token,
28
+ value,
29
+ valueUsd: null
30
+ };
31
+ }
32
+ /** The credit manager takes no multicall while it is paused. */
33
+ function checkCreditManagerPaused(args) {
34
+ if (!args.isPaused) return null;
35
+ return {
36
+ reason: "marketPaused",
37
+ detail: { creditManager: args.creditManager }
38
+ };
39
+ }
40
+ /** Past its expiration date the facade takes no more multicalls. */
41
+ function checkMarketExpired(args) {
42
+ if (!args.isExpired) return null;
43
+ return {
44
+ reason: "marketExpired",
45
+ detail: {
46
+ creditManager: args.creditManager,
47
+ expirationDate: args.expirationDate
48
+ }
49
+ };
50
+ }
51
+ /** A paused pool neither takes deposits nor pays out. */
52
+ function checkPoolPaused(args) {
53
+ return args.isPaused ? {
54
+ reason: "marketPaused",
55
+ detail: { pool: args.pool }
56
+ } : null;
57
+ }
58
+ /**
59
+ * A pool winding down still pays out, so only what puts money in is refused.
60
+ */
61
+ function checkPoolSunset(args) {
62
+ return args.isSunset && args.isDeposit ? {
63
+ reason: "poolSunset",
64
+ detail: { pool: args.pool }
65
+ } : null;
66
+ }
67
+ /**
68
+ * What the pool will hand over, against what is asked for.
69
+ *
70
+ * `binding` and `available` are the caller's answer to "which ceiling stands in
71
+ * the way", not this check's: see the ladder note above. `solutionAmount` is
72
+ * the largest position still openable, left out when none is.
73
+ */
74
+ function checkBorrowLimit(args) {
75
+ if (args.requested <= args.available) return null;
76
+ return {
77
+ reason: "insufficientPoolLiquidity",
78
+ detail: {
79
+ requested: amountOf(args.underlying, args.requested),
80
+ available: amountOf(args.underlying, args.available),
81
+ binding: args.binding,
82
+ ...args.solutionAmount === void 0 ? {} : { solutionAmount: amountOf(args.underlying, args.solutionAmount) }
83
+ }
84
+ };
85
+ }
86
+ /**
87
+ * What the pool can pay out, against what is being taken out.
88
+ *
89
+ * The operator is not `checkBorrowLimit`'s: a pool holding exactly the amount
90
+ * asked for still cannot serve it, so equality is already a refusal. That is
91
+ * the rule the legacy withdrawal validator enforced and it is preserved to the
92
+ * unit.
93
+ */
94
+ function checkPoolPayout(args) {
95
+ if (args.requested < args.available) return null;
96
+ return {
97
+ reason: "insufficientPoolLiquidity",
98
+ detail: {
99
+ requested: amountOf(args.underlying, args.requested),
100
+ available: amountOf(args.underlying, args.available),
101
+ binding: "poolAvailableLiquidity"
102
+ }
103
+ };
104
+ }
105
+ /**
106
+ * A debt the facade would revert on.
107
+ *
108
+ * `allowZero` is the one place the two callers genuinely disagree: an account
109
+ * being adjusted may end owing nothing, while one being opened may not — so the
110
+ * exemption is stated rather than assumed.
111
+ */
112
+ function checkDebtInBand(args) {
113
+ const { debt, minDebt, maxDebt, underlying, allowZero } = args;
114
+ if (!(debt > maxDebt || debt < minDebt && !(allowZero && debt === 0n))) return null;
115
+ return {
116
+ reason: "debtOutOfRange",
117
+ detail: {
118
+ requested: amountOf(underlying, debt),
119
+ minDebt: amountOf(underlying, minDebt),
120
+ maxDebt: amountOf(underlying, maxDebt)
121
+ }
122
+ };
123
+ }
124
+ /** Leverage below 1x is not a position, it is a withdrawal. */
125
+ function checkLeverageAtLeastOne(args) {
126
+ return args.leverage < args.min ? {
127
+ reason: "leverageOutOfRange",
128
+ detail: {
129
+ requested: args.leverage,
130
+ min: args.min
131
+ }
132
+ } : null;
133
+ }
134
+ /**
135
+ * The account against its debt, at whichever bar the caller holds it to.
136
+ *
137
+ * An unread factor counts as failing: a check that cannot see the number is not
138
+ * evidence that the number is fine.
139
+ */
140
+ function checkCollateralised(args) {
141
+ const { healthFactor, required, safePrices, improvesFrom } = args;
142
+ if (healthFactor === void 0) return {
143
+ reason: "insufficientCollateral",
144
+ detail: {
145
+ healthFactor: 0,
146
+ required,
147
+ safePrices
148
+ }
149
+ };
150
+ if (healthFactor >= required || improvesFrom !== void 0 && healthFactor > improvesFrom) return null;
151
+ return {
152
+ reason: "insufficientCollateral",
153
+ detail: {
154
+ healthFactor,
155
+ required,
156
+ safePrices
157
+ }
158
+ };
159
+ }
160
+ /** A token the market will not let the account hold. */
161
+ function checkForbiddenToken(args) {
162
+ return args.isForbidden ? {
163
+ reason: "forbiddenToken",
164
+ detail: { token: args.token }
165
+ } : null;
166
+ }
167
+ /**
168
+ * The room the keeper still has for a token's quota, in the underlying.
169
+ *
170
+ * `requested` is absent for a token the market opened no quota for at all —
171
+ * nothing was weighed against a limit, the token simply counts as no collateral.
172
+ */
173
+ function checkQuotaLimit(args) {
174
+ const { token, requested, available, underlying } = args;
175
+ if (requested !== void 0 && requested <= available) return null;
176
+ return {
177
+ reason: "quotaLimitReached",
178
+ detail: {
179
+ token,
180
+ requested: requested === void 0 ? void 0 : amountOf(underlying, requested),
181
+ available: amountOf(underlying, available)
182
+ }
183
+ };
184
+ }
185
+ /** How many quoted tokens the facade enables at once. */
186
+ function checkQuotaCount(args) {
187
+ return args.count > args.max ? {
188
+ reason: "quotaCountExceeded",
189
+ detail: {
190
+ count: args.count,
191
+ max: args.max
192
+ }
193
+ } : null;
194
+ }
195
+ /** What the operation is funded from, against what is there. */
196
+ function checkFunding(args) {
197
+ const { token, required, held } = args;
198
+ if (required <= held) return null;
199
+ return {
200
+ reason: "insufficientSourceBalance",
201
+ detail: {
202
+ required: amountOf(token, required),
203
+ held: amountOf(token, held)
204
+ }
205
+ };
206
+ }
207
+ /**
208
+ * The SDK could not replay the transaction.
209
+ *
210
+ * Only the 1xxx class lands here. A 2xxx error says the transaction is fine and
211
+ * the SDK could not fully evaluate it, which is a caveat on the numbers rather
212
+ * than a reason to refuse — it stays on the preview for the caller to surface.
213
+ */
214
+ function checkPreviewError(error) {
215
+ if (!error || !isMalformedPreviewError(error)) return null;
216
+ return {
217
+ reason: "malformedTransaction",
218
+ detail: error
219
+ };
220
+ }
221
+ /**
222
+ * The class boundary the preview error codes are written against: 1xxx means
223
+ * the transaction itself is malformed, 2xxx that only the evaluation was
224
+ * incomplete. A range, so a future 1007 classifies itself.
225
+ */
226
+ function isMalformedPreviewError(error) {
227
+ return error.code >= 1e3 && error.code < 2e3;
228
+ }
229
+ //#endregion
230
+ export { MIN_HEALTH_FACTOR_FACADE, MIN_HEALTH_FACTOR_FORM, MIN_HF_LIMITED, MIN_SAFE_HEALTH_FACTOR_FORM, amountOf, checkBorrowLimit, checkCollateralised, checkCreditManagerPaused, checkDebtInBand, checkForbiddenToken, checkFunding, checkLeverageAtLeastOne, checkMarketExpired, checkPoolPaused, checkPoolPayout, checkPoolSunset, checkPreviewError, checkQuotaCount, checkQuotaLimit, isMalformedPreviewError };
@@ -0,0 +1,4 @@
1
+ import { MIN_HEALTH_FACTOR_FACADE, MIN_HEALTH_FACTOR_FORM, MIN_HF_LIMITED, MIN_SAFE_HEALTH_FACTOR_FORM, amountOf, checkBorrowLimit, checkCollateralised, checkCreditManagerPaused, checkDebtInBand, checkForbiddenToken, checkFunding, checkLeverageAtLeastOne, checkMarketExpired, checkPoolPaused, checkPoolPayout, checkPoolSunset, checkPreviewError, checkQuotaCount, checkQuotaLimit, isMalformedPreviewError } from "./checks.js";
2
+ import { IntentPreviewError, raise, refuse } from "./refusal.js";
3
+ import { toToken, toTokenAmount } from "./token.js";
4
+ export { IntentPreviewError, MIN_HEALTH_FACTOR_FACADE, MIN_HEALTH_FACTOR_FORM, MIN_HF_LIMITED, MIN_SAFE_HEALTH_FACTOR_FORM, amountOf, checkBorrowLimit, checkCollateralised, checkCreditManagerPaused, checkDebtInBand, checkForbiddenToken, checkFunding, checkLeverageAtLeastOne, checkMarketExpired, checkPoolPaused, checkPoolPayout, checkPoolSunset, checkPreviewError, checkQuotaCount, checkQuotaLimit, isMalformedPreviewError, raise, refuse, toToken, toTokenAmount };
@@ -1,4 +1,4 @@
1
- //#region src/onchain/accounts/intents/refusal.ts
1
+ //#region src/onchain/validation/refusal.ts
2
2
  /** Builds the refusal a caller sees. */
3
3
  function refuse(reason, detail) {
4
4
  return {
@@ -22,5 +22,15 @@ var IntentPreviewError = class extends Error {
22
22
  this.detail = detail;
23
23
  }
24
24
  };
25
+ /**
26
+ * Throws the issue a check found, with the sentence the engine logs for it.
27
+ *
28
+ * Returns normally when there is nothing to raise, so it cannot narrow a type
29
+ * the way a bare `throw` does — a site that guards a value for the code below
30
+ * it keeps throwing directly.
31
+ */
32
+ function raise(issue, message) {
33
+ if (issue) throw new IntentPreviewError(issue.reason, issue.detail, message);
34
+ }
25
35
  //#endregion
26
- export { IntentPreviewError, refuse };
36
+ export { IntentPreviewError, raise, refuse };
@@ -0,0 +1,27 @@
1
+ import { shortAddress } from "../utils/formatter.js";
2
+ import { amountOf } from "./checks.js";
3
+ //#region src/onchain/validation/token.ts
4
+ /**
5
+ * The token behind an address, for the refusal details that inline one.
6
+ *
7
+ * A token the registry does not know falls back to its own shortened address
8
+ * as a symbol and `decimals: 0` — an unknown token has no scale, and guessing
9
+ * 18 would silently misformat every amount denominated in it.
10
+ */
11
+ function toToken(sdk, address) {
12
+ const known = sdk.tokensMeta.getToken(address);
13
+ if (known) return known;
14
+ return {
15
+ chainId: sdk.chainId,
16
+ address,
17
+ symbol: shortAddress(address),
18
+ name: "",
19
+ decimals: 0
20
+ };
21
+ }
22
+ /** {@link toToken} plus an amount denominated in it. */
23
+ function toTokenAmount(sdk, address, value) {
24
+ return amountOf(toToken(sdk, address), value);
25
+ }
26
+ //#endregion
27
+ export { toToken, toTokenAmount };
@@ -1,4 +1,5 @@
1
1
  import { UnsupportedZapperFunctionError } from "../onchain/market/zapper/errors.js";
2
+ import { IntentPreviewError, raise, refuse } from "../onchain/validation/refusal.js";
2
3
  import { TransferAlignmentError, UnexpectedFacadeEventOrderError, UnknownAdapterError, UnknownFacadeCallError, WithdrawCollateralAlignmentError } from "./trace/errors.js";
3
4
  import { extractAdapterCallTraces } from "./trace/extractAdapterCallTraces.js";
4
5
  import { extractTransfers } from "./trace/extractTransfers.js";
@@ -31,4 +32,7 @@ import { previewCloseOrRepayCreditAccount } from "./preview/previewCloseOrRepayC
31
32
  import { previewOperation } from "./preview/previewOperation.js";
32
33
  import "./preview/index.js";
33
34
  import "./types.js";
34
- export { AllowancePrerequisite, BalancePrerequisite, CreditAccountState, Prerequisite, RWAOpenRequirementsPrerequisite, TransferAlignmentError, UnexpectedFacadeEventOrderError, UnknownAdapterError, UnknownFacadeCallError, UnsupportedOperationError, UnsupportedPoolFunctionError, UnsupportedTargetError, UnsupportedZapperFunctionError, WithdrawCollateralAlignmentError, buildDelayedPreview, checkPrerequisites, classifyCloseOrRepay, classifyInnerOperations, detectDelayedClaim, detectDelayedOperation, extractAdapterCallTraces, extractTransfers, findFacadeCalls, isCloseOrRepay, isPoolOperation, isRWAOperation, makeReplayState, parseFacadeOperationCalldata, parseOperationCalldata, parsePoolOperationCalldata, parseRWAFactoryOperationCalldata, previewAdjustCreditAccount, previewCloseOrRepayCreditAccount, previewOperation, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
35
+ import { checkOperation, collateralIssuesOf } from "./validate/checkOperation.js";
36
+ import { checkSimulation } from "./validate/checkSimulation.js";
37
+ import "./validate/index.js";
38
+ export { AllowancePrerequisite, BalancePrerequisite, CreditAccountState, IntentPreviewError, Prerequisite, RWAOpenRequirementsPrerequisite, TransferAlignmentError, UnexpectedFacadeEventOrderError, UnknownAdapterError, UnknownFacadeCallError, UnsupportedOperationError, UnsupportedPoolFunctionError, UnsupportedTargetError, UnsupportedZapperFunctionError, WithdrawCollateralAlignmentError, buildDelayedPreview, checkOperation, checkPrerequisites, checkSimulation, classifyCloseOrRepay, classifyInnerOperations, collateralIssuesOf, detectDelayedClaim, detectDelayedOperation, extractAdapterCallTraces, extractTransfers, findFacadeCalls, isCloseOrRepay, isPoolOperation, isRWAOperation, makeReplayState, parseFacadeOperationCalldata, parseOperationCalldata, parsePoolOperationCalldata, parseRWAFactoryOperationCalldata, previewAdjustCreditAccount, previewCloseOrRepayCreditAccount, previewOperation, raise, refuse, replayInnerOperations, replayMulticall, resolveDelayedClaimIntent };
@@ -203,6 +203,7 @@ function buildAdjustPreview(post, before, collateralWithdrawn, converter, sdk) {
203
203
  assetsChange: post.balances.difference(before.balances).toAssets(DUST_THRESHOLD).map((a) => oracle.toTokenAmount(a.token, a.balance)),
204
204
  error: converter.error,
205
205
  healthFactor: sdk.positions.healthFactor(snap),
206
+ safeHealthFactor: sdk.positions.healthFactor(snap, { safePrices: true }),
206
207
  borrowRate: sdk.positions.borrowRate(snap, { availableLiquidityChange: before.totalDebt - post.totalDebt }),
207
208
  timeToLiquidation: sdk.positions.timeToLiquidation(snap, { availableLiquidityChange: before.totalDebt - post.totalDebt }),
208
209
  liquidationPrice: sdk.positions.liquidationPrice(snap),
@@ -60,6 +60,7 @@ async function previewAdjustCreditAccount(input, operation, options) {
60
60
  assetsChange: assetsChange.map((a) => oracle.toTokenAmount(a.token, a.balance)),
61
61
  error,
62
62
  healthFactor: sdk.positions.healthFactor(snap),
63
+ safeHealthFactor: sdk.positions.healthFactor(snap, { safePrices: true }),
63
64
  borrowRate: sdk.positions.borrowRate(snap, { availableLiquidityChange: before.totalDebt - account.totalDebt }),
64
65
  timeToLiquidation: sdk.positions.timeToLiquidation(snap, { availableLiquidityChange: before.totalDebt - account.totalDebt }),
65
66
  liquidationPrice: sdk.positions.liquidationPrice(snap),
@@ -50,6 +50,7 @@ async function previewOpenCreditAccount(input, operation) {
50
50
  assets: assets.map((a) => oracle.toTokenAmount(a.token, a.balance)),
51
51
  error,
52
52
  healthFactor: sdk.positions.healthFactor(snap),
53
+ safeHealthFactor: sdk.positions.healthFactor(snap, { safePrices: true }),
53
54
  borrowRate: sdk.positions.borrowRate(snap, { availableLiquidityChange: -account.totalDebt }),
54
55
  timeToLiquidation: sdk.positions.timeToLiquidation(snap, { availableLiquidityChange: -account.totalDebt }),
55
56
  liquidationPrice: sdk.positions.liquidationPrice(snap),
@@ -1,5 +1,5 @@
1
- import { iPoolV310Abi } from "../../abi/310/generated.js";
2
1
  import { iZapperAbi } from "../../abi/iZapper.js";
2
+ import { iPoolV310Abi } from "../../abi/310/generated.js";
3
3
  import { asPreviewSimulationError } from "./errors.js";
4
4
  //#region src/preview/simulate/simulatePoolOperation.ts
5
5
  function previewRead(operation) {
@@ -1,6 +1,6 @@
1
+ import { ierc20Abi } from "../../abi/iERC20.js";
1
2
  import { iCreditFacadeV310Abi } from "../../abi/310/generated.js";
2
3
  import { AddressMap } from "../../onchain/utils/AddressMap.js";
3
- import { ierc20Abi } from "../../abi/iERC20.js";
4
4
  import "../../onchain/index.js";
5
5
  import { UnexpectedFacadeEventOrderError } from "./errors.js";
6
6
  import { getAddress, isAddressEqual, parseEventLogs } from "viem";
@@ -0,0 +1,171 @@
1
+ import { checkBorrowLimit, checkCollateralised, checkCreditManagerPaused, checkDebtInBand, checkForbiddenToken, checkFunding, checkMarketExpired, checkPoolPaused, checkPoolPayout, checkPoolSunset, checkPreviewError, checkQuotaCount, checkQuotaLimit } from "../../onchain/validation/checks.js";
2
+ import { toToken } from "../../onchain/validation/token.js";
3
+ import { borrowable } from "../../onchain/accounts/intents/guards.js";
4
+ import "../../onchain/index.js";
5
+ import { isAddressEqual } from "viem";
6
+ //#region src/preview/validate/checkOperation.ts
7
+ /**
8
+ * Whether a parsed operation may be signed at all — the protocol state that
9
+ * `checkPrerequisites` leaves out, since that one covers only what the sender
10
+ * can fix themselves.
11
+ *
12
+ * Synchronous: the preview carries the numbers and the market is attached.
13
+ * Reports the most fundamental issue it finds and stops there, which is the one
14
+ * a caller acts on.
15
+ */
16
+ function checkOperation(input, options = {}) {
17
+ const { sdk, preview } = input;
18
+ const malformed = checkPreviewError("error" in preview ? preview.error : void 0);
19
+ if (malformed) return malformed;
20
+ switch (preview.operation) {
21
+ case "Deposit":
22
+ case "Mint": return poolIssues(sdk, preview, options, true);
23
+ case "Withdraw":
24
+ case "Redeem": return poolIssues(sdk, preview, options, false);
25
+ case "DelayedCreditAccountOperation": return checkOperation({
26
+ sdk,
27
+ preview: preview.instantPreview
28
+ }, options);
29
+ case "OpenCreditAccount":
30
+ case "RWAOpenCreditAccount":
31
+ case "AdjustCreditAccount": return creditIssues(sdk, preview, options);
32
+ case "CloseCreditAccount":
33
+ case "RepayCreditAccount": return marketIssues(sdk, preview.creditManager);
34
+ }
35
+ }
36
+ function poolIssues(sdk, preview, options, isDeposit) {
37
+ const market = sdk.marketRegister.findByPool(preview.pool);
38
+ return checkPoolPaused({
39
+ isPaused: market.pool.pool.isPaused,
40
+ pool: preview.pool
41
+ }) || checkPoolSunset({
42
+ isSunset: market.sunset,
43
+ isDeposit,
44
+ pool: preview.pool
45
+ }) || (isDeposit ? null : checkPoolPayout({
46
+ requested: preview.tokenOut.value,
47
+ available: market.pool.pool.availableLiquidity,
48
+ underlying: preview.tokenOut.token
49
+ })) || fundingIssue(options, [preview.tokenIn]);
50
+ }
51
+ /** What the market itself refuses, whatever the operation does. */
52
+ function marketIssues(sdk, creditManager) {
53
+ const suite = sdk.marketRegister.findCreditManager(creditManager);
54
+ return checkCreditManagerPaused({
55
+ isPaused: suite.isPaused,
56
+ creditManager
57
+ }) || checkMarketExpired({
58
+ isExpired: suite.isExpired,
59
+ creditManager,
60
+ expirationDate: suite.creditFacade.expirationDate
61
+ });
62
+ }
63
+ function creditIssues(sdk, preview, options) {
64
+ const suite = sdk.marketRegister.findCreditManager(preview.creditManager);
65
+ const market = suite.market;
66
+ const underlying = toToken(sdk, market.pool.underlying);
67
+ const isOpening = preview.operation === "OpenCreditAccount" || preview.operation === "RWAOpenCreditAccount";
68
+ return marketIssues(sdk, preview.creditManager) || checkDebtInBand({
69
+ debt: preview.debt,
70
+ minDebt: suite.creditFacade.minDebt,
71
+ maxDebt: suite.creditFacade.maxDebt,
72
+ underlying,
73
+ allowZero: !isOpening
74
+ }) || borrowIssue(suite, preview, underlying) || forbiddenIssue(suite, preview) || checkQuotaCount({
75
+ count: preview.quotas.filter((q) => q.value > 0n).length,
76
+ max: suite.creditManager.maxEnabledTokens
77
+ }) || quotaIssue(market, preview, underlying) || (preview.debt === 0n ? null : collateralIssue(preview, options)) || fundingIssue(options, collateralOf(preview));
78
+ }
79
+ /**
80
+ * What the transaction draws, against what the market can lend right now.
81
+ *
82
+ * Only a draw is weighed: repaying, or leaving the debt alone, can never exceed
83
+ * a ceiling. Opening borrows the whole debt; adjusting borrows `debtChange`.
84
+ *
85
+ * The engine holds every simulation to this already (`assertCanBorrow`), so
86
+ * this is here for the transactions it never saw — a pasted calldata reaches
87
+ * the confirm screen with nothing else standing between it and a revert.
88
+ */
89
+ function borrowIssue(suite, preview, underlying) {
90
+ const drawn = preview.operation === "AdjustCreditAccount" ? preview.debtChange : preview.debt;
91
+ if (drawn <= 0n) return null;
92
+ const { limit, binding } = borrowable(suite);
93
+ return checkBorrowLimit({
94
+ requested: drawn,
95
+ available: limit,
96
+ binding,
97
+ underlying
98
+ });
99
+ }
100
+ /** The account against whichever bars the caller holds it to. */
101
+ function collateralIssue(preview, options) {
102
+ return collateralIssuesOf({
103
+ healthFactor: preview.healthFactor,
104
+ safeHealthFactor: preview.safeHealthFactor
105
+ }, options);
106
+ }
107
+ /** The wallet's side of the operation, against the balances it was given. */
108
+ function fundingIssue(options, puts) {
109
+ const { balances } = options;
110
+ if (!balances) return null;
111
+ for (const { token, value } of puts) {
112
+ const issue = checkFunding({
113
+ token,
114
+ required: value,
115
+ held: balances.get(token.address) ?? 0n
116
+ });
117
+ if (issue) return issue;
118
+ }
119
+ return null;
120
+ }
121
+ /** What the wallet puts in, which is what its balances have to cover. */
122
+ function collateralOf(preview) {
123
+ if ("collateral" in preview) return preview.collateral;
124
+ if ("collateralAdded" in preview) return preview.collateralAdded;
125
+ return [];
126
+ }
127
+ function forbiddenIssue(suite, preview) {
128
+ const obtained = preview.operation === "AdjustCreditAccount" ? preview.assetsChange : preview.assets;
129
+ const forbidden = suite.forbiddenTokens;
130
+ for (const asset of obtained) {
131
+ if (asset.value <= 0n) continue;
132
+ const issue = checkForbiddenToken({
133
+ token: asset.token,
134
+ isForbidden: forbidden.some((f) => isAddressEqual(f, asset.token.address))
135
+ });
136
+ if (issue) return issue;
137
+ }
138
+ return null;
139
+ }
140
+ function quotaIssue(market, preview, underlying) {
141
+ const increases = preview.operation === "AdjustCreditAccount" ? preview.quotasChange : preview.quotas;
142
+ const { pqk } = market.pool;
143
+ for (const q of increases) {
144
+ if (q.value <= 0n) continue;
145
+ const quota = pqk.hasActiveQuota(q.token.address) ? pqk.quotas.get(q.token.address) : void 0;
146
+ const issue = checkQuotaLimit({
147
+ token: q.token,
148
+ requested: quota ? q.value : void 0,
149
+ available: (quota?.limit ?? 0n) - (quota?.totalQuoted ?? 0n),
150
+ underlying
151
+ });
152
+ if (issue) return issue;
153
+ }
154
+ return null;
155
+ }
156
+ /** The two collateral bars, shared by the preview and the simulation paths. */
157
+ function collateralIssuesOf(factors, options) {
158
+ const { minHealthFactor, minSafeHealthFactor, currentHealthFactor } = options;
159
+ return (minHealthFactor === void 0 ? null : checkCollateralised({
160
+ healthFactor: factors.healthFactor,
161
+ required: minHealthFactor,
162
+ safePrices: false,
163
+ improvesFrom: currentHealthFactor
164
+ })) || (minSafeHealthFactor === void 0 || factors.safeHealthFactor === void 0 ? null : checkCollateralised({
165
+ healthFactor: factors.safeHealthFactor,
166
+ required: minSafeHealthFactor,
167
+ safePrices: true
168
+ }));
169
+ }
170
+ //#endregion
171
+ export { checkOperation, collateralIssuesOf };
@@ -0,0 +1,51 @@
1
+ import { checkCreditManagerPaused, checkDebtInBand, checkMarketExpired, checkQuotaCount } from "../../onchain/validation/checks.js";
2
+ import { toToken } from "../../onchain/validation/token.js";
3
+ import "../../onchain/index.js";
4
+ import { collateralIssuesOf } from "./checkOperation.js";
5
+ //#region src/preview/validate/checkSimulation.ts
6
+ /**
7
+ * Whether a simulated operation clears the caller's own bars.
8
+ *
9
+ * The engine holds an account to the facade's `1.0`, because its guards answer
10
+ * "would this revert". A form is wiser to ask for more, and the engine's own
11
+ * note says so — a caller wanting the stricter bar applies it itself. This is
12
+ * that second opinion, over the numbers the engine already reported.
13
+ *
14
+ * Three of the checks below the engine does not make at all: both health-factor
15
+ * bars are its own `1.0`, and the quota count it never weighs. The other two run
16
+ * against the same numbers the engine used, and are here so that a change in the
17
+ * engine cannot pass silently.
18
+ *
19
+ * What is deliberately absent: the forbidden-token, quota-limit and funding
20
+ * checks all need the *delta* an operation applies, and `OperationState` reports
21
+ * only the state after it. Weighing them against absolutes would refuse a
22
+ * forbidden token the account merely holds, or a quota the operation never
23
+ * touched. The engine performed all three during the walk, so a simulation that
24
+ * came back `ok` has already passed them.
25
+ */
26
+ function checkSimulation(input, options = {}) {
27
+ const { sdk, state, creditManager } = input;
28
+ const suite = sdk.marketRegister.findCreditManager(creditManager);
29
+ return checkCreditManagerPaused({
30
+ isPaused: suite.isPaused,
31
+ creditManager
32
+ }) || checkMarketExpired({
33
+ isExpired: suite.isExpired,
34
+ creditManager,
35
+ expirationDate: suite.creditFacade.expirationDate
36
+ }) || checkDebtInBand({
37
+ debt: state.accountDebt,
38
+ minDebt: suite.creditFacade.minDebt,
39
+ maxDebt: suite.creditFacade.maxDebt,
40
+ underlying: toToken(sdk, suite.market.pool.underlying),
41
+ allowZero: true
42
+ }) || checkQuotaCount({
43
+ count: Object.values(state.quotas).filter((q) => q.balance > 0n).length,
44
+ max: suite.creditManager.maxEnabledTokens
45
+ }) || (state.accountDebt === 0n ? null : collateralIssuesOf({
46
+ healthFactor: state.healthFactor,
47
+ safeHealthFactor: state.safeHealthFactor
48
+ }, options));
49
+ }
50
+ //#endregion
51
+ export { checkSimulation };
@@ -0,0 +1,3 @@
1
+ import { checkOperation, collateralIssuesOf } from "./checkOperation.js";
2
+ import { checkSimulation } from "./checkSimulation.js";
3
+ export { checkOperation, checkSimulation, collateralIssuesOf };
@@ -1,3 +1,4 @@
1
+ import { IntentPreviewError, raise, refuse } from "../onchain/validation/refusal.js";
1
2
  import { AllSourcesFailedError } from "./errors/AllSourcesFailedError.js";
2
3
  import { SourceChainMismatchError } from "./errors/SourceChainMismatchError.js";
3
4
  import { assertSameChains } from "./errors/assertSameChains.js";
@@ -24,4 +25,4 @@ import { PreviewNamespace } from "./preview/PreviewNamespace.js";
24
25
  import "./preview/index.js";
25
26
  import { DEFAULT_MAX_STATE_AGE, GearboxSDK } from "./GearboxSDK.js";
26
27
  import "./types.js";
27
- export { AbstractNamespace, AllSourcesFailedError, DEFAULT_MAX_OFFCHAIN_LAG, DEFAULT_MAX_STATE_AGE, ExecuteApi, GearboxSDK, LiquidationsNamespace, MissingSourceError, NoSourceServedError, OpportunitiesNamespace, PositionsNamespace, PrepareApi, PreviewNamespace, SourceChainMismatchError, SourceUnavailableError, assertSameChains, everyChainFailed, filterResponse, mergeChainList, mergeChainOne };
28
+ export { AbstractNamespace, AllSourcesFailedError, DEFAULT_MAX_OFFCHAIN_LAG, DEFAULT_MAX_STATE_AGE, ExecuteApi, GearboxSDK, IntentPreviewError, LiquidationsNamespace, MissingSourceError, NoSourceServedError, OpportunitiesNamespace, PositionsNamespace, PrepareApi, PreviewNamespace, SourceChainMismatchError, SourceUnavailableError, assertSameChains, everyChainFailed, filterResponse, mergeChainList, mergeChainOne, raise, refuse };