@gearbox-protocol/sdk 18.2.0-next.10 → 18.2.0-next.12

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 (56) hide show
  1. package/dist/cjs/permissionless/api/index.js +30 -0
  2. package/dist/cjs/permissionless/api/oracles/PermissionlessOracles.js +191 -0
  3. package/dist/cjs/permissionless/api/oracles/index.js +32 -0
  4. package/dist/cjs/permissionless/api/oracles/schemas.js +17 -0
  5. package/dist/cjs/permissionless/api/oracles/score/formula.js +61 -0
  6. package/dist/cjs/permissionless/api/oracles/score/index.js +11 -0
  7. package/dist/cjs/permissionless/api/oracles/score/run.js +171 -0
  8. package/dist/cjs/permissionless/api/oracles/score/types.js +1 -0
  9. package/dist/cjs/permissionless/api/oracles/stress/classify.js +258 -0
  10. package/dist/cjs/permissionless/api/oracles/stress/index.js +23 -0
  11. package/dist/cjs/permissionless/api/oracles/stress/override.js +125 -0
  12. package/dist/cjs/permissionless/api/oracles/stress/run.js +435 -0
  13. package/dist/cjs/permissionless/api/oracles/stress/score.js +98 -0
  14. package/dist/cjs/permissionless/api/oracles/stress/types.js +1 -0
  15. package/dist/cjs/permissionless/index.js +31 -0
  16. package/dist/cjs/permissionless/utils/index.js +1 -0
  17. package/dist/cjs/permissionless/utils/price-update/get-prices.js +39 -0
  18. package/dist/cjs/permissionless/utils/price-update/index.js +1 -0
  19. package/dist/esm/permissionless/api/index.js +7 -1
  20. package/dist/esm/permissionless/api/oracles/PermissionlessOracles.js +193 -2
  21. package/dist/esm/permissionless/api/oracles/index.js +10 -1
  22. package/dist/esm/permissionless/api/oracles/schemas.js +16 -1
  23. package/dist/esm/permissionless/api/oracles/score/formula.js +55 -0
  24. package/dist/esm/permissionless/api/oracles/score/index.js +4 -0
  25. package/dist/esm/permissionless/api/oracles/score/run.js +170 -0
  26. package/dist/esm/permissionless/api/oracles/score/types.js +1 -0
  27. package/dist/esm/permissionless/api/oracles/stress/classify.js +256 -0
  28. package/dist/esm/permissionless/api/oracles/stress/index.js +6 -0
  29. package/dist/esm/permissionless/api/oracles/stress/override.js +119 -0
  30. package/dist/esm/permissionless/api/oracles/stress/run.js +429 -0
  31. package/dist/esm/permissionless/api/oracles/stress/score.js +95 -0
  32. package/dist/esm/permissionless/api/oracles/stress/types.js +1 -0
  33. package/dist/esm/permissionless/index.js +8 -2
  34. package/dist/esm/permissionless/utils/index.js +2 -2
  35. package/dist/esm/permissionless/utils/price-update/get-prices.js +39 -1
  36. package/dist/esm/permissionless/utils/price-update/index.js +2 -2
  37. package/dist/types/permissionless/api/index.d.ts +10 -2
  38. package/dist/types/permissionless/api/oracles/PermissionlessOracles.d.ts +115 -1
  39. package/dist/types/permissionless/api/oracles/index.d.ts +12 -2
  40. package/dist/types/permissionless/api/oracles/schemas.d.ts +47 -0
  41. package/dist/types/permissionless/api/oracles/score/formula.d.ts +39 -0
  42. package/dist/types/permissionless/api/oracles/score/index.d.ts +4 -0
  43. package/dist/types/permissionless/api/oracles/score/run.d.ts +24 -0
  44. package/dist/types/permissionless/api/oracles/score/types.d.ts +113 -0
  45. package/dist/types/permissionless/api/oracles/stress/classify.d.ts +57 -0
  46. package/dist/types/permissionless/api/oracles/stress/index.d.ts +6 -0
  47. package/dist/types/permissionless/api/oracles/stress/override.d.ts +59 -0
  48. package/dist/types/permissionless/api/oracles/stress/run.d.ts +89 -0
  49. package/dist/types/permissionless/api/oracles/stress/score.d.ts +57 -0
  50. package/dist/types/permissionless/api/oracles/stress/types.d.ts +272 -0
  51. package/dist/types/permissionless/api/oracles/types.d.ts +58 -0
  52. package/dist/types/permissionless/index.d.ts +11 -3
  53. package/dist/types/permissionless/utils/index.d.ts +2 -2
  54. package/dist/types/permissionless/utils/price-update/get-prices.d.ts +16 -0
  55. package/dist/types/permissionless/utils/price-update/index.d.ts +2 -2
  56. package/package.json +1 -1
@@ -0,0 +1,57 @@
1
+ import { GroupScenarioOutcome, SlotOutcome } from "./types.js";
2
+ //#region src/permissionless/api/oracles/stress/score.d.ts
3
+ /**
4
+ * Turning what a group did into a mark out of ten.
5
+ *
6
+ * Any single number over a thing this shaped is a judgement, so the one here
7
+ * is spelled out rather than tuned: what it weighs, and why each term is
8
+ * weighed that way, is in the comments below, and every figure it is computed
9
+ * from stays in the report so a reader who disagrees can reweigh them.
10
+ **/
11
+ /**
12
+ * How bad one slot's outcome is, on nought to one.
13
+ *
14
+ * Two kinds of harm, which are not the same kind of problem:
15
+ *
16
+ * - a wrong price. The collateral is valued against the market's underlying,
17
+ * so what matters is the ratio and not either leg: a market whose
18
+ * collateral and underlying both doubled has not moved. Overvalued
19
+ * collateral is borrowed against and the loan is never repaid; undervalued
20
+ * collateral is liquidated out from under an account that was solvent.
21
+ * Both are counted, because a reader asking what a source can do to them
22
+ * is exposed to each.
23
+ *
24
+ * - a price that stopped. The slot reverted where it used to answer, which
25
+ * freezes the market: nothing can be borrowed and, worse, nothing can be
26
+ * liquidated. Scored at half a full mispricing — it is a liveness failure
27
+ * rather than a licence to drain, and it is also loud, where a wrong number
28
+ * is silent.
29
+ *
30
+ * A hundredfold move in the ratio is full harm. Ten times is a half, and the
31
+ * curve is logarithmic between them because the damage is: a position is
32
+ * liquidatable somewhere around a tenth of a move, and everything past that is
33
+ * degrees of already-gone.
34
+ */
35
+ export declare function slotHarm(slot: SlotOutcome): number;
36
+ /**
37
+ * The group's mark, over every scenario it was put through.
38
+ *
39
+ * Two views of the same slots, because either alone misleads. Weighing harm by
40
+ * the quota riding on it is what a reader with money in the protocol wants —
41
+ * a source that can only move a market with nothing in it has not done much.
42
+ * But a market with nothing in it today is where tomorrow's deposit goes, so
43
+ * the worst slot regardless of size is carried too, at a smaller weight.
44
+ *
45
+ * Ten is a group that moved nothing. Nought is one that revalued everything
46
+ * the chain has out.
47
+ */
48
+ export declare function scoreGroup(outcomes: GroupScenarioOutcome[]): number;
49
+ /**
50
+ * The one line the score stands for.
51
+ *
52
+ * Says which of the two failures the group causes, because the remedies
53
+ * differ: a wrong price is answered with bounds and a second feed, a dead one
54
+ * with a reserve feed and a staleness period.
55
+ */
56
+ export declare function verdictOf(group: string, score: number, outcomes: GroupScenarioOutcome[], reachableSlots: number, reachableUsd: number, responsive: number, silentSources: number, undefendedPositions: number, selfContained: boolean): string;
57
+ //#endregion
@@ -0,0 +1,272 @@
1
+ import { Address } from "viem";
2
+ //#region src/permissionless/api/oracles/stress/types.d.ts
3
+ /**
4
+ * How a source is made to lie.
5
+ *
6
+ * `feed` is a price feed that reads nothing else on chain — a Chainlink
7
+ * aggregator, a Redstone or Pyth feed, a protocol's own rate adapter — and is
8
+ * perturbed by overriding what it answers.
9
+ *
10
+ * `rate` is the contract a Gearbox LP feed reads an exchange rate from: the
11
+ * wstETH token, an ERC-4626 vault, a Curve pool. The feed itself is not
12
+ * overridden, because it also reads the price of what the rate is denominated
13
+ * in — overriding the whole feed would charge the protocol with a failure of
14
+ * whatever prices its underlying.
15
+ **/
16
+ export type StressSourceKind = "feed" | "rate";
17
+ /**
18
+ * One thing that can lie, and what happens downstream when it does.
19
+ *
20
+ * A source is not a feed. Several feeds can read the same aggregator, and
21
+ * several of an oracle's trees can carry the same node; what the test varies
22
+ * is the contract, once, and then looks at every feed built over it.
23
+ **/
24
+ export interface StressSource {
25
+ chainId: number;
26
+ /**
27
+ * The set it fails with.
28
+ *
29
+ * Sources sharing a group are taken to fail together, which is the whole
30
+ * reason for grouping: Chainlink's feeds share an operator and an
31
+ * infrastructure, so a reader who trusts one trusts all of them. A source
32
+ * nothing else is correlated with is a group of one, which is the honest
33
+ * answer rather than a bucket named "other".
34
+ */
35
+ group: string;
36
+ kind: StressSourceKind;
37
+ /** The contract overridden. */
38
+ target: Address;
39
+ /**
40
+ * The feed the source governs, which for a `feed` source is the target
41
+ * itself and for a `rate` source is the LP feed reading it.
42
+ */
43
+ feed: Address;
44
+ /** Gearbox contract type of that feed, or `""` for one it never deployed. */
45
+ contractType: string;
46
+ /** What the feed says it is, which is how most sources are identified. */
47
+ description: string;
48
+ /**
49
+ * Whether the group was recognised or only inferred from the feed itself.
50
+ *
51
+ * `false` is not a failure — the source is still perturbed and still
52
+ * scored — but it is a group of one named after a description, so a reader
53
+ * cannot tell whether it shares a fate with anything else. The share of
54
+ * value behind unidentified sources is this analysis's blind spot and is
55
+ * reported as such.
56
+ */
57
+ identified: boolean;
58
+ /** Which rule named the group, so a reader can audit the partition. */
59
+ via: string;
60
+ /**
61
+ * Whether anything feeds this source at all.
62
+ *
63
+ * `false` for a feed that carries its answer in its own code — a constant,
64
+ * a zero — which cannot report a wrong price because nobody reports one to
65
+ * it. Such a feed is still a risk, but the risk is whoever can replace the
66
+ * contract, not whoever publishes to it, and overriding it would be
67
+ * measuring the wrong thing. Reported and not simulated.
68
+ */
69
+ perturbable: boolean;
70
+ /**
71
+ * What the source reports now, or `null` for one that is not answering.
72
+ *
73
+ * A source with no baseline is left out of every override: a contract that
74
+ * says nothing cannot be made to say something else, and inventing a figure
75
+ * for it would be testing a feed that does not exist. A group whose sources
76
+ * are all like this scores well because it can do nothing — which is worth
77
+ * knowing, but is not the same as being safe, and is why this is reported.
78
+ */
79
+ baseline: bigint | null;
80
+ }
81
+ /** One perturbation, as a multiple of what the source reports now. */
82
+ export interface StressScenario {
83
+ label: string;
84
+ /**
85
+ * What the source's answer is multiplied by.
86
+ *
87
+ * `Infinity` and `0` stand for the two unbounded ends and are realised as
88
+ * the largest and smallest values the feed's own type can carry, which is as
89
+ * infinite as a `int256` gets.
90
+ */
91
+ multiplier: number;
92
+ }
93
+ /**
94
+ * What one feed answered under one scenario.
95
+ *
96
+ * `null` is a read that reverted, which is a different outcome from a wrong
97
+ * number and is scored differently: a market whose oracle reverts cannot be
98
+ * borrowed from or liquidated, where one that answers a wrong number can be
99
+ * drained.
100
+ **/
101
+ export interface FeedOutcome {
102
+ feed: Address;
103
+ /** What it answers now, with nothing overridden. */
104
+ base: bigint | null;
105
+ /** What it answers under the scenario. */
106
+ stressed: bigint | null;
107
+ /**
108
+ * `stressed / base`, or `null` where either end could not be read.
109
+ *
110
+ * The headline number: 1 is a feed the group cannot move, and anything far
111
+ * from it is a feed it can.
112
+ */
113
+ factor: number | null;
114
+ }
115
+ /**
116
+ * What one market's slot looked like under one scenario.
117
+ *
118
+ * A slot and not a market: a token's main and reserve feeds are two slots, and
119
+ * their disagreement is one of the things worth seeing.
120
+ **/
121
+ export interface SlotOutcome {
122
+ market: Address;
123
+ marketName: string | null;
124
+ curatorName: string | null;
125
+ token: Address;
126
+ tokenSymbol: string | null;
127
+ reserve: boolean;
128
+ isUnderlying: boolean;
129
+ feed: FeedOutcome;
130
+ /**
131
+ * How the collateral's price moved against the market's own underlying.
132
+ *
133
+ * What a position is actually valued by: a market whose underlying and
134
+ * collateral both doubled has not moved at all, and one where only the
135
+ * collateral did has doubled every account's health. `null` where either
136
+ * side could not be priced.
137
+ */
138
+ ratioFactor: number | null;
139
+ /** What the market has quoted against the token, in USD at current prices. */
140
+ quotaUsedUsd: number | null;
141
+ }
142
+ /**
143
+ * What one group of sources does to one chain, under one scenario.
144
+ **/
145
+ export interface GroupScenarioOutcome {
146
+ scenario: StressScenario;
147
+ slots: SlotOutcome[];
148
+ /** Largest `ratioFactor` over the slots, and the smallest. */
149
+ worstInflation: number | null;
150
+ worstDeflation: number | null;
151
+ /** Slots whose feed stopped answering, which it did answer before. */
152
+ brokenSlots: number;
153
+ /**
154
+ * Slots whose feed does not answer even with nothing overridden.
155
+ *
156
+ * Not this group's doing and not a result of the sweep, but reported with
157
+ * it: a slot priced through a feed that is reverting right now cannot be
158
+ * made worse by anything, and a group that reaches only such slots would
159
+ * otherwise score as harmless when what it really is, is moot.
160
+ */
161
+ deadSlots: number;
162
+ /**
163
+ * Quota in USD riding on the slots this scenario moved at all, over the
164
+ * quota riding on every slot — how much of the chain the group reaches.
165
+ */
166
+ valueAtRisk: number;
167
+ }
168
+ /**
169
+ * Where a group starts to matter, found by bisection on the multiplier.
170
+ *
171
+ * `null` means no multiplier in the searched range moved the market past the
172
+ * threshold, which for a group that reaches nothing is the expected answer.
173
+ **/
174
+ export interface BreakingPoint {
175
+ market: Address;
176
+ token: Address;
177
+ /** Smallest upward multiple of the source that moves the ratio past 2×. */
178
+ inflation: number | null;
179
+ /** Largest downward multiple that moves it past ½×. */
180
+ deflation: number | null;
181
+ }
182
+ /** What one group of sources can do to one chain. */
183
+ export interface GroupReport {
184
+ chainId: number;
185
+ group: string;
186
+ sources: StressSource[];
187
+ /** Whether every source in it was recognised rather than inferred. */
188
+ identified: boolean;
189
+ /** Market slots that read a feed built over any of its sources. */
190
+ reachableSlots: number;
191
+ /** Quota in USD riding on those slots, counted once per `(market, token)`. */
192
+ reachableUsd: number;
193
+ /**
194
+ * Positions whose main feed and reserve feed both read something of this
195
+ * group.
196
+ *
197
+ * A reserve feed exists so that a market has something to fall back on. One
198
+ * that reads the same source as the feed it is backing up falls back onto
199
+ * the same failure, and nothing about the pair says so — both are perfectly
200
+ * healthy feeds from two different vendors with one number underneath.
201
+ */
202
+ undefendedPositions: number;
203
+ outcomes: GroupScenarioOutcome[];
204
+ breakingPoints: BreakingPoint[];
205
+ /**
206
+ * How many of its reachable slots answered differently under a perturbation
207
+ * far too small for any bound to object to, over how many were reachable.
208
+ *
209
+ * The control. A group that moves nothing under the unbounded ends has
210
+ * either been stopped by something — a bound, a sanity check, a second feed
211
+ * — or was never really perturbed at all, and from the big scenarios alone
212
+ * those two look identical. A slot that responds to a tenth of a percent is
213
+ * a slot this test is genuinely driving; one that does not is a slot whose
214
+ * every other result should be read as "unknown" rather than as "safe".
215
+ */
216
+ responsive: number;
217
+ /**
218
+ * Sources of the group that are not answering as it stands, so nothing
219
+ * could be perturbed about them.
220
+ */
221
+ silentSources: number;
222
+ /**
223
+ * 0 to 10, where 10 is a group that can do nothing and 0 one that can
224
+ * revalue the whole chain. See `score.ts` for what goes into it.
225
+ */
226
+ score: number;
227
+ /** One line a reader can act on. */
228
+ verdict: string;
229
+ }
230
+ /** Everything one run looked at. */
231
+ export interface StressReport {
232
+ chainId: number;
233
+ /** Slots read, before any grouping. */
234
+ slots: number;
235
+ /** Distinct feeds the markets read. */
236
+ roots: number;
237
+ /** Distinct nodes in all the oracles' trees. */
238
+ nodes: number;
239
+ /**
240
+ * Slots whose feed does not answer at the current block, before anything is
241
+ * perturbed — a standing fault rather than a finding of this test, and the
242
+ * first thing to look at in its output.
243
+ */
244
+ deadSlots: number;
245
+ sources: StressSource[];
246
+ /**
247
+ * Quota in USD this chain's markets have out, and the share of it priced
248
+ * through at least one unidentified source.
249
+ *
250
+ * The second figure is the blind spot: value whose source could be named
251
+ * only by its own description, so nothing says what else fails with it.
252
+ */
253
+ totalUsd: number;
254
+ unidentifiedUsd: number;
255
+ groups: GroupReport[];
256
+ }
257
+ /** Args of {@link PermissionlessOracles.stressTest}. */
258
+ export interface StressTestArgs {
259
+ chainId: number;
260
+ /**
261
+ * Which perturbations to apply. Defaults to the two unbounded ends.
262
+ */
263
+ scenarios?: StressScenario[];
264
+ /**
265
+ * Also bisect for each market's breaking point, which costs a few more
266
+ * calls per group. On by default.
267
+ */
268
+ thresholds?: boolean;
269
+ /** Only these groups, for a second look at one of them. */
270
+ groups?: string[];
271
+ }
272
+ //#endregion
@@ -129,6 +129,44 @@ export interface PermissionlessPriceFeedMarket extends PermissionlessIndexedPric
129
129
  */
130
130
  marketStalenessPeriod: number | null;
131
131
  }
132
+ /**
133
+ * One `(market, token, role)` slot of a chain, with the feed holding it.
134
+ *
135
+ * The same row {@link PermissionlessIndexedPriceFeedMarket} is, read from the
136
+ * chain's end rather than from one feed's: the feed is a column here because
137
+ * it is no longer what was asked for, and the chain is named because the read
138
+ * spans several.
139
+ *
140
+ * Unpivoted — a token's main and reserve feeds are two rows. What reads them
141
+ * this way is analysis over every slot at once, where the two roles of a
142
+ * token are the pair being compared and folding them together would hide it.
143
+ **/
144
+ export interface PermissionlessMarketSlot extends PermissionlessIndexedPriceFeedMarket {
145
+ chainId: number;
146
+ /** The market's underlying, which its quota figures are denominated in. */
147
+ underlyingToken: Address;
148
+ /**
149
+ * The market has been shut down: no new borrowing, but its open accounts
150
+ * are quoting all the same.
151
+ */
152
+ isShutdown: boolean;
153
+ /** The feed in force for the slot. */
154
+ priceFeed: Address;
155
+ /** Display name the store recorded, or `null` for a feed it never had. */
156
+ priceFeedName: string | null;
157
+ /**
158
+ * Whether the PriceFeedStore still carries that feed.
159
+ *
160
+ * `false` is the case worth looking at: the market goes on pricing with
161
+ * something the store has removed, or never had.
162
+ */
163
+ priceFeedInStore: boolean;
164
+ /**
165
+ * The feed the market prices its own underlying with, which is what
166
+ * converts this row's quota figures. `null` for a market that has none.
167
+ */
168
+ underlyingPriceFeed: Address | null;
169
+ }
132
170
  /**
133
171
  * One feed of the store, with everywhere the store lets it be used.
134
172
  *
@@ -373,6 +411,26 @@ export interface PriceFeedRef {
373
411
  export interface PriceFeedPrice extends PriceFeedRef {
374
412
  price: bigint | null;
375
413
  }
414
+ /**
415
+ * How many decimals a feed's answer carries, as
416
+ * {@link PermissionlessOracles.getDecimals} answers.
417
+ *
418
+ * Its own call rather than a field of {@link PriceFeedPrice}, because the two
419
+ * are not read on the same schedule: a price is the figure that moves and is
420
+ * re-read for it, while a deployed feed's decimals never change, so a caller
421
+ * reads these once and keeps them.
422
+ *
423
+ * Needed wherever the feeds are not only the ones a market reads. Every
424
+ * Gearbox feed an oracle holds reports 8, which is why most of this namespace
425
+ * can assume it — but a composite's own dependencies are whatever the
426
+ * aggregator underneath happens to be, and a rate leg of one is routinely 18.
427
+ *
428
+ * `null` is a feed that would not answer `decimals()` at all, which a caller
429
+ * showing the figure should treat as unknown rather than as 8.
430
+ **/
431
+ export interface PriceFeedDecimals extends PriceFeedRef {
432
+ decimals: number | null;
433
+ }
376
434
  /**
377
435
  * One asset with the feeds to value it through.
378
436
  *
@@ -13,7 +13,9 @@ import "./core/index.js";
13
13
  import { FunctionParams, ValueParams, encodeFunctionParams } from "./utils/abi-encoder.js";
14
14
  import { DeployArgs, DeployContractArgs, DeployPriceFeedArgs, PreparedDeployment, PreparedPriceFeedDeployment } from "./api/deploy/types.js";
15
15
  import { DEFAULT_DEPLOY_SALT, PermissionlessDeploy, priceFeedSalt } from "./api/deploy/PermissionlessDeploy.js";
16
- import { AssetArgs, AssetCap, AssetsArgs, FeedCap, MarketCap, PermissionlessAsset, PermissionlessAssetDetails, PermissionlessAssetMarket, PermissionlessAssetMarketFeed, PermissionlessAssetQuota, PermissionlessAssetSummary, PermissionlessIndexedAssetDetails, PermissionlessIndexedAssetSummary, PermissionlessIndexedPriceFeedDetails, PermissionlessIndexedPriceFeedMarket, PermissionlessMarket, PermissionlessPriceFeedAsset, PermissionlessPriceFeedDetails, PermissionlessPriceFeedMarket, PermissionlessPriceFeedStore, PermissionlessQuotaTotals, PriceFeedArgs, PriceFeedPrice, PriceFeedRef } from "./api/oracles/types.js";
16
+ import { AssetScore, AssetScoresArgs, GroupImpact, MarketScore, ScoredFeed } from "./api/oracles/score/types.js";
17
+ import { BreakingPoint, FeedOutcome, GroupReport, GroupScenarioOutcome, SlotOutcome, StressReport, StressScenario, StressSource, StressSourceKind, StressTestArgs } from "./api/oracles/stress/types.js";
18
+ import { AssetArgs, AssetCap, AssetsArgs, FeedCap, MarketCap, PermissionlessAsset, PermissionlessAssetDetails, PermissionlessAssetMarket, PermissionlessAssetMarketFeed, PermissionlessAssetQuota, PermissionlessAssetSummary, PermissionlessIndexedAssetDetails, PermissionlessIndexedAssetSummary, PermissionlessIndexedPriceFeedDetails, PermissionlessIndexedPriceFeedMarket, PermissionlessMarket, PermissionlessMarketSlot, PermissionlessPriceFeedAsset, PermissionlessPriceFeedDetails, PermissionlessPriceFeedMarket, PermissionlessPriceFeedStore, PermissionlessQuotaTotals, PriceFeedArgs, PriceFeedDecimals, PriceFeedPrice, PriceFeedRef } from "./api/oracles/types.js";
17
19
  import { GET_PRICES_CHUNK_SIZE, GET_PRICES_GAS_LIMIT_BY_CHAIN_ID, PermissionlessOracles } from "./api/oracles/PermissionlessOracles.js";
18
20
  import { AddressProviderContract } from "./bindings/address-provider.js";
19
21
  import { BytecodeRepositoryContract } from "./bindings/bytecode-repository.js";
@@ -38,6 +40,12 @@ import { InstanceOwnerTransactions } from "./api/transactions/InstanceOwnerTrans
38
40
  import { GearboxPermissionless } from "./api/GearboxPermissionless.js";
39
41
  import { deriveEffectiveStalenessPeriod } from "./api/deploy/effective-staleness.js";
40
42
  import { PermissionlessChainUnreachableError, PermissionlessNotAttachedError, PriceFeedNotInStoreError, PriceFeedSaltMissingError, PriceFeedStalenessUnknownError } from "./api/errors.js";
43
+ import { REVERT_SCORE, SCORE_MULTIPLIER, factorOf, finalPrice, scoreOfFactor, worstOf } from "./api/oracles/score/formula.js";
44
+ import { runAssetScores } from "./api/oracles/score/run.js";
45
+ import { TreeNode, classifySources, sourcesByFeed } from "./api/oracles/stress/classify.js";
46
+ import { UNBOUNDED_DOWN, UNBOUNDED_UP, groupOverride, perturb, rateStub, roundDataStub } from "./api/oracles/stress/override.js";
47
+ import { DEFAULT_SCENARIOS, RATE_FEED_TYPE, readForest, readRateTargets, readUnder, runStressTest } from "./api/oracles/stress/run.js";
48
+ import { scoreGroup, slotHarm, verdictOf } from "./api/oracles/stress/score.js";
41
49
  import "./api/index.js";
42
50
  import { ArchiveTransport, ArchiveTransportConfig } from "./chains/archive-transport.js";
43
51
  import { chunkedLogsTransport } from "./chains/chunked-log-transport.js";
@@ -50,8 +58,8 @@ import { calculateChecksum, convertRawTxToSafeMultisigTx, getSafeBatch, getSafeB
50
58
  import { convertQueueBatchToExecuteTx } from "./utils/governance/timelock-txs.js";
51
59
  import { BYTECODE_REPOSITORY, CROSS_CHAIN_GOVERNANCE, CROSS_CHAIN_MULTISIG, INSTANCE_MANAGER, MARKET_CONFIGURATOR_FACTORY, PRICE_FEED_STORE, TOKEN_COMPRESSOR } from "./utils/literals.js";
52
60
  import { getPriceUpdateTx } from "./utils/price-update/get-price-update-tx.js";
53
- import { getLatestPrices, getPrices } from "./utils/price-update/get-prices.js";
61
+ import { getFeedDecimals, getLatestPrices, getPrices } from "./utils/price-update/get-prices.js";
54
62
  import { GetUpdatablePriceFeedsArgs, getUpdatablePriceFeeds } from "./utils/price-update/get-updatable-feeds.js";
55
63
  import { normalizeSignature } from "./utils/signature.js";
56
64
  import "./utils/index.js";
57
- export { AccessMode, AddAssetParams, AddFeedsArgs, AddressProviderContract, Addresses, AllowTokenParams, ArchiveTransport, ArchiveTransportConfig, AssetArgs, AssetCap, AssetsArgs, AttachChainsArgs, AuditEvent, Auditor, BYTECODE_REPOSITORY, Batch, Bytecode, BytecodeRepositoryContract, CCMConstructorParams, CROSS_CHAIN_GOVERNANCE, CROSS_CHAIN_MULTISIG, ChainScope, ChainSummaryArgs, ChainsNamespace, ChangeNamesArgs, ChangeStalenessPeriodsArgs, ConstructorParams, CreditManagerFees, CrossChainCall, CrossChainMultisigContract, DEFAULT_DEPLOY_SALT, DeployArgs, DeployContractArgs, DeployParams, DeployPriceFeedArgs, Deployment, DeploymentExtended, FeedCap, ForbidAdapterParams, ForbidFeedsArgs, ForbidTokenParams, FunctionParams, GET_PRICES_CHUNK_SIZE, GET_PRICES_GAS_LIMIT_BY_CHAIN_ID, GearboxPermissionless, GearboxPermissionlessOptions, GetUpdatablePriceFeedsArgs, GovernorContract, INSTANCE_MANAGER, InputValueParams, InstanceManagerContract, InstanceOwnerTransactions, InstanceTxs, InstanceTxsArgs, MAINNET_CCM_CONSTRUCTOR_PARAMS, MAINNET_DEPLOYMENT_BLOCK, MAINNET_DEPLOYMENT_CCM_SALT, MAINNET_DEPLOYMENT_IM_SALT, MARKET_CONFIGURATOR_FACTORY, Market, MarketCap, MarketConfiguratorContract, MarketConfiguratorFactoryContract, PRICE_FEED_STORE, PUBLIC_CREATE2_FACTORY, PauseCreditManagerParams, PeripheryDomain, PermissionlessAnalytics, PermissionlessAsset, PermissionlessAssetDetails, PermissionlessAssetMarket, PermissionlessAssetMarketFeed, PermissionlessAssetQuota, PermissionlessAssetSummary, PermissionlessChain, PermissionlessChainSummary, PermissionlessChainUnreachableError, PermissionlessDeploy, PermissionlessIndexedAssetDetails, PermissionlessIndexedAssetSummary, PermissionlessIndexedPriceFeedDetails, PermissionlessIndexedPriceFeedMarket, PermissionlessMarket, PermissionlessNotAttachedError, PermissionlessOracles, PermissionlessPriceFeedAsset, PermissionlessPriceFeedDetails, PermissionlessPriceFeedMarket, PermissionlessPriceFeedStore, PermissionlessQuotaTotals, PreparedDeployment, PreparedPriceFeedDeployment, PriceChartArgs, PriceFeed, PriceFeedArgs, PriceFeedChartPoint, PriceFeedConstructorParam, PriceFeedNotInStoreError, PriceFeedPair, PriceFeedParamType, PriceFeedParams, PriceFeedPrice, PriceFeedPriceChart, PriceFeedRef, PriceFeedSaltMissingError, PriceFeedSetupParams, PriceFeedStalenessUnknownError, PriceFeedStoreContract, Proposal, QueuedAndExecutedTransaction, RecoveryMessage, RoutingManagerContract, SafeBatch, SafeMeta, SafeTx, SetExpirationDateParams, SetFeesParams, SetPriceFeedParams, SetReservePriceFeedParams, SetTokenQuotaIncreaseFeeParams, Signature, TOKEN_COMPRESSOR, TimeLockContract, TimelockTransaction, TimelockTxParams, TimelockTxs, TokenCompressorContract, TreasurySplitterContract, UnpauseCreditManagerParams, ValueParams, WithdrawalCompressorContract, calculateChecksum, checkCreate2Deployment, checkCreate2DeploymentAddress, chunkedLogsTransport, convertPercent, convertQueueBatchToExecuteTx, convertRawTxToSafeMultisigTx, createCallData, createCreate2DeployRawTx, deepJsonParse, deployUsingPublicCreate2, deriveEffectiveStalenessPeriod, encodeFunctionParams, formatBytecodeSize, formatBytecodeVersion, getBlockNumberByTimestamp, getCreate2AddressPublicFactory, getCreate2DeploymentAddress, getLatestPrices, getPriceUpdateTx, getPrices, getSafeBatch, getSafeBatches, getUpdatablePriceFeeds, handleSalt, normalizeSignature, priceFeedSalt, priceFeedSetupParams, shortenHash, significantTrunc };
65
+ export { AccessMode, AddAssetParams, AddFeedsArgs, AddressProviderContract, Addresses, AllowTokenParams, ArchiveTransport, ArchiveTransportConfig, AssetArgs, AssetCap, AssetScore, AssetScoresArgs, AssetsArgs, AttachChainsArgs, AuditEvent, Auditor, BYTECODE_REPOSITORY, Batch, BreakingPoint, Bytecode, BytecodeRepositoryContract, CCMConstructorParams, CROSS_CHAIN_GOVERNANCE, CROSS_CHAIN_MULTISIG, ChainScope, ChainSummaryArgs, ChainsNamespace, ChangeNamesArgs, ChangeStalenessPeriodsArgs, ConstructorParams, CreditManagerFees, CrossChainCall, CrossChainMultisigContract, DEFAULT_DEPLOY_SALT, DEFAULT_SCENARIOS, DeployArgs, DeployContractArgs, DeployParams, DeployPriceFeedArgs, Deployment, DeploymentExtended, FeedCap, FeedOutcome, ForbidAdapterParams, ForbidFeedsArgs, ForbidTokenParams, FunctionParams, GET_PRICES_CHUNK_SIZE, GET_PRICES_GAS_LIMIT_BY_CHAIN_ID, GearboxPermissionless, GearboxPermissionlessOptions, GetUpdatablePriceFeedsArgs, GovernorContract, GroupImpact, GroupReport, GroupScenarioOutcome, INSTANCE_MANAGER, InputValueParams, InstanceManagerContract, InstanceOwnerTransactions, InstanceTxs, InstanceTxsArgs, MAINNET_CCM_CONSTRUCTOR_PARAMS, MAINNET_DEPLOYMENT_BLOCK, MAINNET_DEPLOYMENT_CCM_SALT, MAINNET_DEPLOYMENT_IM_SALT, MARKET_CONFIGURATOR_FACTORY, Market, MarketCap, MarketConfiguratorContract, MarketConfiguratorFactoryContract, MarketScore, PRICE_FEED_STORE, PUBLIC_CREATE2_FACTORY, PauseCreditManagerParams, PeripheryDomain, PermissionlessAnalytics, PermissionlessAsset, PermissionlessAssetDetails, PermissionlessAssetMarket, PermissionlessAssetMarketFeed, PermissionlessAssetQuota, PermissionlessAssetSummary, PermissionlessChain, PermissionlessChainSummary, PermissionlessChainUnreachableError, PermissionlessDeploy, PermissionlessIndexedAssetDetails, PermissionlessIndexedAssetSummary, PermissionlessIndexedPriceFeedDetails, PermissionlessIndexedPriceFeedMarket, PermissionlessMarket, PermissionlessMarketSlot, PermissionlessNotAttachedError, PermissionlessOracles, PermissionlessPriceFeedAsset, PermissionlessPriceFeedDetails, PermissionlessPriceFeedMarket, PermissionlessPriceFeedStore, PermissionlessQuotaTotals, PreparedDeployment, PreparedPriceFeedDeployment, PriceChartArgs, PriceFeed, PriceFeedArgs, PriceFeedChartPoint, PriceFeedConstructorParam, PriceFeedDecimals, PriceFeedNotInStoreError, PriceFeedPair, PriceFeedParamType, PriceFeedParams, PriceFeedPrice, PriceFeedPriceChart, PriceFeedRef, PriceFeedSaltMissingError, PriceFeedSetupParams, PriceFeedStalenessUnknownError, PriceFeedStoreContract, Proposal, QueuedAndExecutedTransaction, RATE_FEED_TYPE, REVERT_SCORE, RecoveryMessage, RoutingManagerContract, SCORE_MULTIPLIER, SafeBatch, SafeMeta, SafeTx, ScoredFeed, SetExpirationDateParams, SetFeesParams, SetPriceFeedParams, SetReservePriceFeedParams, SetTokenQuotaIncreaseFeeParams, Signature, SlotOutcome, StressReport, StressScenario, StressSource, StressSourceKind, StressTestArgs, TOKEN_COMPRESSOR, TimeLockContract, TimelockTransaction, TimelockTxParams, TimelockTxs, TokenCompressorContract, TreasurySplitterContract, TreeNode, UNBOUNDED_DOWN, UNBOUNDED_UP, UnpauseCreditManagerParams, ValueParams, WithdrawalCompressorContract, calculateChecksum, checkCreate2Deployment, checkCreate2DeploymentAddress, chunkedLogsTransport, classifySources, convertPercent, convertQueueBatchToExecuteTx, convertRawTxToSafeMultisigTx, createCallData, createCreate2DeployRawTx, deepJsonParse, deployUsingPublicCreate2, deriveEffectiveStalenessPeriod, encodeFunctionParams, factorOf, finalPrice, formatBytecodeSize, formatBytecodeVersion, getBlockNumberByTimestamp, getCreate2AddressPublicFactory, getCreate2DeploymentAddress, getFeedDecimals, getLatestPrices, getPriceUpdateTx, getPrices, getSafeBatch, getSafeBatches, getUpdatablePriceFeeds, groupOverride, handleSalt, normalizeSignature, perturb, priceFeedSalt, priceFeedSetupParams, rateStub, readForest, readRateTargets, readUnder, roundDataStub, runAssetScores, runStressTest, scoreGroup, scoreOfFactor, shortenHash, significantTrunc, slotHarm, sourcesByFeed, verdictOf, worstOf };
@@ -8,8 +8,8 @@ import { convertQueueBatchToExecuteTx } from "./governance/timelock-txs.js";
8
8
  import "./governance/index.js";
9
9
  import { BYTECODE_REPOSITORY, CROSS_CHAIN_GOVERNANCE, CROSS_CHAIN_MULTISIG, INSTANCE_MANAGER, MARKET_CONFIGURATOR_FACTORY, PRICE_FEED_STORE, TOKEN_COMPRESSOR } from "./literals.js";
10
10
  import { getPriceUpdateTx } from "./price-update/get-price-update-tx.js";
11
- import { getLatestPrices, getPrices } from "./price-update/get-prices.js";
11
+ import { getFeedDecimals, getLatestPrices, getPrices } from "./price-update/get-prices.js";
12
12
  import { GetUpdatablePriceFeedsArgs, getUpdatablePriceFeeds } from "./price-update/get-updatable-feeds.js";
13
13
  import "./price-update/index.js";
14
14
  import { normalizeSignature } from "./signature.js";
15
- export { BYTECODE_REPOSITORY, CROSS_CHAIN_GOVERNANCE, CROSS_CHAIN_MULTISIG, FunctionParams, GetUpdatablePriceFeedsArgs, INSTANCE_MANAGER, InstanceTxs, MARKET_CONFIGURATOR_FACTORY, PRICE_FEED_STORE, PUBLIC_CREATE2_FACTORY, TOKEN_COMPRESSOR, TimelockTxs, ValueParams, calculateChecksum, checkCreate2Deployment, checkCreate2DeploymentAddress, convertPercent, convertQueueBatchToExecuteTx, convertRawTxToSafeMultisigTx, createCreate2DeployRawTx, deepJsonParse, deployUsingPublicCreate2, encodeFunctionParams, formatBytecodeSize, formatBytecodeVersion, getBlockNumberByTimestamp, getCreate2AddressPublicFactory, getCreate2DeploymentAddress, getLatestPrices, getPriceUpdateTx, getPrices, getSafeBatch, getSafeBatches, getUpdatablePriceFeeds, handleSalt, normalizeSignature, shortenHash, significantTrunc };
15
+ export { BYTECODE_REPOSITORY, CROSS_CHAIN_GOVERNANCE, CROSS_CHAIN_MULTISIG, FunctionParams, GetUpdatablePriceFeedsArgs, INSTANCE_MANAGER, InstanceTxs, MARKET_CONFIGURATOR_FACTORY, PRICE_FEED_STORE, PUBLIC_CREATE2_FACTORY, TOKEN_COMPRESSOR, TimelockTxs, ValueParams, calculateChecksum, checkCreate2Deployment, checkCreate2DeploymentAddress, convertPercent, convertQueueBatchToExecuteTx, convertRawTxToSafeMultisigTx, createCreate2DeployRawTx, deepJsonParse, deployUsingPublicCreate2, encodeFunctionParams, formatBytecodeSize, formatBytecodeVersion, getBlockNumberByTimestamp, getCreate2AddressPublicFactory, getCreate2DeploymentAddress, getFeedDecimals, getLatestPrices, getPriceUpdateTx, getPrices, getSafeBatch, getSafeBatches, getUpdatablePriceFeeds, handleSalt, normalizeSignature, shortenHash, significantTrunc };
@@ -1,5 +1,21 @@
1
1
  import { Address, PublicClient } from "viem";
2
2
  //#region src/permissionless/utils/price-update/get-prices.d.ts
3
+ /**
4
+ * The scale each feed's answer is in, in one multicall.
5
+ *
6
+ * Part of the Chainlink interface every feed in a Gearbox tree implements,
7
+ * and the only way to read an answer that is not an oracle's own: a feed an
8
+ * oracle holds reports 8 decimals by construction, while the feeds beneath a
9
+ * composite are whatever was deployed — an ETH/USD aggregator at 8 and a
10
+ * rate leg at 18 sit under the same parent.
11
+ *
12
+ * `null` is a feed that would not answer, which a caller should treat as
13
+ * unknown rather than defaulting it to 8.
14
+ */
15
+ export declare function getFeedDecimals({ client, priceFeeds }: {
16
+ client: PublicClient;
17
+ priceFeeds: Address[];
18
+ }): Promise<Record<Address, number | null>>;
3
19
  /**
4
20
  * What the feeds report as they stand, in one multicall.
5
21
  *
@@ -1,4 +1,4 @@
1
1
  import { getPriceUpdateTx } from "./get-price-update-tx.js";
2
- import { getLatestPrices, getPrices } from "./get-prices.js";
2
+ import { getFeedDecimals, getLatestPrices, getPrices } from "./get-prices.js";
3
3
  import { GetUpdatablePriceFeedsArgs, getUpdatablePriceFeeds } from "./get-updatable-feeds.js";
4
- export { GetUpdatablePriceFeedsArgs, getLatestPrices, getPriceUpdateTx, getPrices, getUpdatablePriceFeeds };
4
+ export { GetUpdatablePriceFeedsArgs, getFeedDecimals, getLatestPrices, getPriceUpdateTx, getPrices, getUpdatablePriceFeeds };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "18.2.0-next.10",
3
+ "version": "18.2.0-next.12",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "repository": {