@gearbox-protocol/sdk 18.2.0-next.1 → 18.2.0-next.11

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 (135) hide show
  1. package/dist/cjs/abi/compressors/subcompressors/liquidation/treehouseLiquidationSubcompressor.js +179 -0
  2. package/dist/cjs/abi/compressors/subcompressors/withdrawal/treehouseWithdrawalSubcompressor.js +534 -0
  3. package/dist/cjs/abi/router/treehouseWorker.js +885 -0
  4. package/dist/cjs/dev/AccountOpener.js +1 -1
  5. package/dist/cjs/dev/withdrawalUtils.js +1 -1
  6. package/dist/cjs/history/trace/extractTransfers.js +1 -1
  7. package/dist/cjs/onchain/accounts/CreditAccountsServiceV310.js +2 -2
  8. package/dist/cjs/onchain/accounts/liquidations/LiquidationsService.js +1 -1
  9. package/dist/cjs/onchain/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -2
  10. package/dist/cjs/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -2
  11. package/dist/cjs/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -2
  12. package/dist/cjs/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
  13. package/dist/cjs/onchain/base/TokensMeta.js +3 -3
  14. package/dist/cjs/onchain/core/createAddressProvider.js +1 -1
  15. package/dist/cjs/onchain/market/adapters/abi/actionAbi.js +1 -0
  16. package/dist/cjs/onchain/market/adapters/abi/conctructorAbi.js +3 -0
  17. package/dist/cjs/onchain/market/adapters/contracts/AccountMigratorAdapterContract.js +1 -1
  18. package/dist/cjs/onchain/market/adapters/contracts/ERC4626AdapterContract.js +1 -1
  19. package/dist/cjs/onchain/market/adapters/types.js +3 -0
  20. package/dist/cjs/onchain/market/credit/CreditFacadeV310BaseContract.js +1 -1
  21. package/dist/cjs/onchain/market/pool/PoolV310Contract.js +1 -1
  22. package/dist/cjs/onchain/market/rwa/createDegenNFT.js +1 -1
  23. package/dist/cjs/onchain/market/zapper/IETHZapperContract.js +1 -2
  24. package/dist/cjs/onchain/market/zapper/ZapperContract.js +1 -1
  25. package/dist/cjs/onchain/preview/preview/previewPoolPositionOperation.js +2 -2
  26. package/dist/cjs/onchain/utils/viem/simulateWithPriceUpdates.js +1 -1
  27. package/dist/cjs/permissionless/api/index.js +26 -0
  28. package/dist/cjs/permissionless/api/oracles/PermissionlessOracles.js +585 -47
  29. package/dist/cjs/permissionless/api/oracles/enrich.js +99 -0
  30. package/dist/cjs/permissionless/api/oracles/index.js +28 -0
  31. package/dist/cjs/permissionless/api/oracles/schemas.js +102 -35
  32. package/dist/cjs/permissionless/api/oracles/score/formula.js +99 -0
  33. package/dist/cjs/permissionless/api/oracles/score/index.js +8 -0
  34. package/dist/cjs/permissionless/api/oracles/score/run.js +88 -0
  35. package/dist/cjs/permissionless/api/oracles/score/types.js +1 -0
  36. package/dist/cjs/permissionless/api/oracles/stress/classify.js +258 -0
  37. package/dist/cjs/permissionless/api/oracles/stress/index.js +22 -0
  38. package/dist/cjs/permissionless/api/oracles/stress/override.js +125 -0
  39. package/dist/cjs/permissionless/api/oracles/stress/run.js +432 -0
  40. package/dist/cjs/permissionless/api/oracles/stress/score.js +98 -0
  41. package/dist/cjs/permissionless/api/oracles/stress/types.js +1 -0
  42. package/dist/cjs/permissionless/api/schemas.js +0 -3
  43. package/dist/cjs/permissionless/bindings/index.js +1 -1
  44. package/dist/cjs/permissionless/index.js +29 -1
  45. package/dist/cjs/permissionless/utils/index.js +2 -0
  46. package/dist/cjs/permissionless/utils/price-update/get-prices.js +64 -0
  47. package/dist/cjs/permissionless/utils/price-update/index.js +2 -0
  48. package/dist/cjs/testnets/TestnetsAPI.js +179 -0
  49. package/dist/cjs/testnets/errors/TestnetNotFoundError.js +15 -0
  50. package/dist/cjs/testnets/errors/TestnetRequestFailedError.js +24 -0
  51. package/dist/cjs/testnets/errors/TestnetStatusError.js +19 -0
  52. package/dist/cjs/testnets/errors/TestnetValidationError.js +24 -0
  53. package/dist/cjs/testnets/errors/TestnetWaitTimeoutError.js +30 -0
  54. package/dist/cjs/testnets/errors/TestnetsError.js +34 -0
  55. package/dist/cjs/testnets/errors/index.js +13 -0
  56. package/dist/cjs/testnets/index.js +32 -0
  57. package/dist/cjs/testnets/package.json +1 -0
  58. package/dist/cjs/testnets/schemas.js +242 -0
  59. package/dist/cjs/testnets/types.js +1 -0
  60. package/dist/esm/abi/compressors/subcompressors/liquidation/treehouseLiquidationSubcompressor.js +178 -0
  61. package/dist/esm/abi/compressors/subcompressors/withdrawal/treehouseWithdrawalSubcompressor.js +533 -0
  62. package/dist/esm/abi/router/treehouseWorker.js +884 -0
  63. package/dist/esm/onchain/market/adapters/abi/actionAbi.js +1 -0
  64. package/dist/esm/onchain/market/adapters/abi/conctructorAbi.js +3 -0
  65. package/dist/esm/onchain/market/adapters/types.js +3 -0
  66. package/dist/esm/permissionless/api/index.js +7 -1
  67. package/dist/esm/permissionless/api/oracles/PermissionlessOracles.js +587 -49
  68. package/dist/esm/permissionless/api/oracles/enrich.js +94 -0
  69. package/dist/esm/permissionless/api/oracles/index.js +10 -1
  70. package/dist/esm/permissionless/api/oracles/schemas.js +95 -35
  71. package/dist/esm/permissionless/api/oracles/score/formula.js +96 -0
  72. package/dist/esm/permissionless/api/oracles/score/index.js +4 -0
  73. package/dist/esm/permissionless/api/oracles/score/run.js +87 -0
  74. package/dist/esm/permissionless/api/oracles/score/types.js +1 -0
  75. package/dist/esm/permissionless/api/oracles/stress/classify.js +256 -0
  76. package/dist/esm/permissionless/api/oracles/stress/index.js +6 -0
  77. package/dist/esm/permissionless/api/oracles/stress/override.js +119 -0
  78. package/dist/esm/permissionless/api/oracles/stress/run.js +427 -0
  79. package/dist/esm/permissionless/api/oracles/stress/score.js +95 -0
  80. package/dist/esm/permissionless/api/oracles/stress/types.js +1 -0
  81. package/dist/esm/permissionless/api/schemas.js +2 -4
  82. package/dist/esm/permissionless/bindings/index.js +1 -1
  83. package/dist/esm/permissionless/index.js +9 -3
  84. package/dist/esm/permissionless/utils/index.js +2 -2
  85. package/dist/esm/permissionless/utils/price-update/get-prices.js +63 -1
  86. package/dist/esm/permissionless/utils/price-update/index.js +2 -2
  87. package/dist/esm/testnets/TestnetsAPI.js +178 -0
  88. package/dist/esm/testnets/errors/TestnetNotFoundError.js +14 -0
  89. package/dist/esm/testnets/errors/TestnetRequestFailedError.js +23 -0
  90. package/dist/esm/testnets/errors/TestnetStatusError.js +18 -0
  91. package/dist/esm/testnets/errors/TestnetValidationError.js +23 -0
  92. package/dist/esm/testnets/errors/TestnetWaitTimeoutError.js +29 -0
  93. package/dist/esm/testnets/errors/TestnetsError.js +33 -0
  94. package/dist/esm/testnets/errors/index.js +7 -0
  95. package/dist/esm/testnets/index.js +11 -0
  96. package/dist/esm/testnets/package.json +1 -0
  97. package/dist/esm/testnets/schemas.js +228 -0
  98. package/dist/esm/testnets/types.js +1 -0
  99. package/dist/types/abi/compressors/subcompressors/liquidation/treehouseLiquidationSubcompressor.d.ts +148 -0
  100. package/dist/types/abi/compressors/subcompressors/withdrawal/treehouseWithdrawalSubcompressor.d.ts +440 -0
  101. package/dist/types/abi/router/treehouseWorker.d.ts +728 -0
  102. package/dist/types/onchain/market/adapters/types.d.ts +4 -1
  103. package/dist/types/permissionless/api/index.d.ts +10 -2
  104. package/dist/types/permissionless/api/oracles/PermissionlessOracles.d.ts +232 -35
  105. package/dist/types/permissionless/api/oracles/enrich.d.ts +59 -0
  106. package/dist/types/permissionless/api/oracles/index.d.ts +12 -2
  107. package/dist/types/permissionless/api/oracles/schemas.d.ts +209 -22
  108. package/dist/types/permissionless/api/oracles/score/formula.d.ts +46 -0
  109. package/dist/types/permissionless/api/oracles/score/index.d.ts +4 -0
  110. package/dist/types/permissionless/api/oracles/score/run.d.ts +21 -0
  111. package/dist/types/permissionless/api/oracles/score/types.d.ts +85 -0
  112. package/dist/types/permissionless/api/oracles/stress/classify.d.ts +57 -0
  113. package/dist/types/permissionless/api/oracles/stress/index.d.ts +6 -0
  114. package/dist/types/permissionless/api/oracles/stress/override.d.ts +59 -0
  115. package/dist/types/permissionless/api/oracles/stress/run.d.ts +73 -0
  116. package/dist/types/permissionless/api/oracles/stress/score.d.ts +57 -0
  117. package/dist/types/permissionless/api/oracles/stress/types.d.ts +272 -0
  118. package/dist/types/permissionless/api/oracles/types.d.ts +408 -63
  119. package/dist/types/permissionless/api/schemas.d.ts +0 -2
  120. package/dist/types/permissionless/index.d.ts +11 -3
  121. package/dist/types/permissionless/utils/index.d.ts +2 -2
  122. package/dist/types/permissionless/utils/price-update/get-prices.d.ts +33 -0
  123. package/dist/types/permissionless/utils/price-update/index.d.ts +2 -2
  124. package/dist/types/testnets/TestnetsAPI.d.ts +108 -0
  125. package/dist/types/testnets/errors/TestnetNotFoundError.d.ts +12 -0
  126. package/dist/types/testnets/errors/TestnetRequestFailedError.d.ts +11 -0
  127. package/dist/types/testnets/errors/TestnetStatusError.d.ts +15 -0
  128. package/dist/types/testnets/errors/TestnetValidationError.d.ts +16 -0
  129. package/dist/types/testnets/errors/TestnetWaitTimeoutError.d.ts +21 -0
  130. package/dist/types/testnets/errors/TestnetsError.d.ts +47 -0
  131. package/dist/types/testnets/errors/index.d.ts +7 -0
  132. package/dist/types/testnets/index.d.ts +11 -0
  133. package/dist/types/testnets/schemas.d.ts +554 -0
  134. package/dist/types/testnets/types.d.ts +717 -0
  135. package/package.json +9 -3
@@ -0,0 +1,99 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let viem = require("viem");
3
+ //#region src/permissionless/api/oracles/enrich.ts
4
+ /**
5
+ * What the oracles namespace works out for itself once the backend has
6
+ * answered.
7
+ *
8
+ * All of it used to be the backend's, and all of it needs the chain: a quota
9
+ * is denominated in its market's own underlying and a market cap is a supply
10
+ * times a price, so none of these can be indexed — they can only be read at
11
+ * the block the reader is on. Keeping them here means one description of each
12
+ * rule rather than one per service that wants it, and a backend that holds no
13
+ * viem client at all.
14
+ **/
15
+ /** Identifies a feed across chains, since an address alone does not. */
16
+ function feedKey(chainId, address) {
17
+ return `${chainId}:${address.toLowerCase()}`;
18
+ }
19
+ /** Prices looked up the way {@link totalQuotas} and the caps need them. */
20
+ function pricesByFeed(prices) {
21
+ return new Map(prices.map(({ chainId, address, price }) => [feedKey(chainId, address), price]));
22
+ }
23
+ /**
24
+ * The asset's quota across its markets, totalled in USD.
25
+ *
26
+ * Each market's figures are converted at the price that market's own oracle
27
+ * holds for its underlying, which is the same number that market's accounting
28
+ * uses.
29
+ *
30
+ * Limits count only the markets still running, because a shut down market's
31
+ * limit is not borrowable; what is already quoted counts everywhere, because
32
+ * debt outstanding is exposure either way. A market whose underlying could not
33
+ * be priced is skipped, which makes both figures floors, and `null` is nothing
34
+ * to total rather than a zero.
35
+ *
36
+ * @param priceOf - The price each underlying feed reports, in the 8 decimals
37
+ * every Gearbox feed uses.
38
+ */
39
+ function totalQuotas(quotas, priceOf) {
40
+ let limit = 0;
41
+ let used = 0;
42
+ let anyLimit = false;
43
+ let anyUsed = false;
44
+ for (const quota of quotas) {
45
+ const raw = quota.underlyingPriceFeed === null ? null : priceOf(quota.underlyingPriceFeed);
46
+ if (raw === null || raw === void 0) continue;
47
+ const price = Number((0, viem.formatUnits)(raw, 8));
48
+ if (quota.quotaUsed !== null) {
49
+ used += quota.quotaUsed * price;
50
+ anyUsed = true;
51
+ }
52
+ if (quota.quotaLimit !== null && !quota.isShutdown) {
53
+ limit += quota.quotaLimit * price;
54
+ anyLimit = true;
55
+ }
56
+ }
57
+ return {
58
+ quotaLimitUsd: anyLimit ? limit : null,
59
+ quotaUsedUsd: anyUsed ? used : null
60
+ };
61
+ }
62
+ /**
63
+ * What one feed values one asset's supply at: `price × totalSupply`.
64
+ *
65
+ * Multiplied as integers and formatted once, rather than through two floats:
66
+ * an 8-decimal price times an 18-decimal supply loses its small end to a JS
67
+ * number long before it loses the large one, and the figure is a total rather
68
+ * than an estimate.
69
+ *
70
+ * `null` if either side could not be read — an asset nobody could price is
71
+ * not an asset worth nothing.
72
+ */
73
+ function toCap(price, totalSupply, decimals) {
74
+ if (price === null || price === void 0 || totalSupply === null || totalSupply === void 0) return null;
75
+ return (0, viem.formatUnits)(price * totalSupply, 8 + decimals);
76
+ }
77
+ /** Larger first, with `null` after every figure including a real zero. */
78
+ function descending(a, b) {
79
+ return (b ?? -1) - (a ?? -1);
80
+ }
81
+ /**
82
+ * Assets ordered the way a reader scans them: what the protocol is built on
83
+ * first, then what is actually borrowed against it, then what it is merely
84
+ * allowed to be borrowed against.
85
+ *
86
+ * Applied here and not by the backend because the two middle terms are the
87
+ * converted quotas, which only exist once the chain has been read. The
88
+ * backend orders by the first term and the tie-breakers, so a caller reading
89
+ * the route directly still gets a stable order; this refines it.
90
+ */
91
+ function byCentrality(a, b) {
92
+ return b.underlyingMarketCount - a.underlyingMarketCount || descending(a.quotaUsedUsd, b.quotaUsedUsd) || descending(a.quotaLimitUsd, b.quotaLimitUsd) || a.symbol.localeCompare(b.symbol) || a.address.localeCompare(b.address) || a.chainId - b.chainId;
93
+ }
94
+ //#endregion
95
+ exports.byCentrality = byCentrality;
96
+ exports.feedKey = feedKey;
97
+ exports.pricesByFeed = pricesByFeed;
98
+ exports.toCap = toCap;
99
+ exports.totalQuotas = totalQuotas;
@@ -1,6 +1,34 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_permissionless_api_oracles_stress_classify = require("./stress/classify.js");
3
+ const require_permissionless_api_oracles_stress_override = require("./stress/override.js");
4
+ const require_permissionless_api_oracles_stress_score = require("./stress/score.js");
5
+ const require_permissionless_api_oracles_stress_run = require("./stress/run.js");
6
+ const require_permissionless_api_oracles_score_formula = require("./score/formula.js");
7
+ const require_permissionless_api_oracles_score_run = require("./score/run.js");
2
8
  const require_permissionless_api_oracles_PermissionlessOracles = require("./PermissionlessOracles.js");
9
+ require("./score/index.js");
10
+ require("./stress/index.js");
3
11
  require("./types.js");
12
+ exports.BOUND_WEIGHT = require_permissionless_api_oracles_score_formula.BOUND_WEIGHT;
13
+ exports.DEFAULT_SCENARIOS = require_permissionless_api_oracles_stress_run.DEFAULT_SCENARIOS;
4
14
  exports.GET_PRICES_CHUNK_SIZE = require_permissionless_api_oracles_PermissionlessOracles.GET_PRICES_CHUNK_SIZE;
5
15
  exports.GET_PRICES_GAS_LIMIT_BY_CHAIN_ID = require_permissionless_api_oracles_PermissionlessOracles.GET_PRICES_GAS_LIMIT_BY_CHAIN_ID;
16
+ exports.INDEPENDENCE_WEIGHT = require_permissionless_api_oracles_score_formula.INDEPENDENCE_WEIGHT;
6
17
  exports.PermissionlessOracles = require_permissionless_api_oracles_PermissionlessOracles.PermissionlessOracles;
18
+ exports.RATE_FEED_TYPE = require_permissionless_api_oracles_stress_run.RATE_FEED_TYPE;
19
+ exports.UNBOUNDED_DOWN = require_permissionless_api_oracles_stress_override.UNBOUNDED_DOWN;
20
+ exports.UNBOUNDED_UP = require_permissionless_api_oracles_stress_override.UNBOUNDED_UP;
21
+ exports.classifySources = require_permissionless_api_oracles_stress_classify.classifySources;
22
+ exports.groupOverride = require_permissionless_api_oracles_stress_override.groupOverride;
23
+ exports.perturb = require_permissionless_api_oracles_stress_override.perturb;
24
+ exports.rateStub = require_permissionless_api_oracles_stress_override.rateStub;
25
+ exports.readForest = require_permissionless_api_oracles_stress_run.readForest;
26
+ exports.readRateTargets = require_permissionless_api_oracles_stress_run.readRateTargets;
27
+ exports.roundDataStub = require_permissionless_api_oracles_stress_override.roundDataStub;
28
+ exports.runAssetScores = require_permissionless_api_oracles_score_run.runAssetScores;
29
+ exports.runStressTest = require_permissionless_api_oracles_stress_run.runStressTest;
30
+ exports.scoreGroup = require_permissionless_api_oracles_stress_score.scoreGroup;
31
+ exports.scoreMarket = require_permissionless_api_oracles_score_formula.scoreMarket;
32
+ exports.slotHarm = require_permissionless_api_oracles_stress_score.slotHarm;
33
+ exports.sourcesByFeed = require_permissionless_api_oracles_stress_classify.sourcesByFeed;
34
+ exports.verdictOf = require_permissionless_api_oracles_stress_score.verdictOf;
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_permissionless_api_chains_schemas = require("../chains/schemas.js");
2
3
  const require_permissionless_api_schemas = require("../schemas.js");
3
4
  let zod_v4 = require("zod/v4");
4
5
  //#region src/permissionless/api/oracles/schemas.ts
@@ -19,69 +20,135 @@ const priceFeedSchema = zod_v4.z.looseObject({
19
20
  stalenessPeriod: zod_v4.z.number(),
20
21
  name: zod_v4.z.string()
21
22
  });
22
- /** {@link PermissionlessAsset} */
23
- const assetSchema = zod_v4.z.looseObject({
23
+ /**
24
+ * {@link PermissionlessPriceFeedAsset}
25
+ *
26
+ * What identifies an asset, which is all a feed's own listing of one says.
27
+ **/
28
+ const priceFeedAssetSchema = zod_v4.z.looseObject({
24
29
  address: require_permissionless_api_schemas.addressSchema,
25
30
  symbol: zod_v4.z.string(),
26
31
  name: zod_v4.z.string(),
27
- decimals: zod_v4.z.number(),
32
+ decimals: zod_v4.z.number()
33
+ });
34
+ /** {@link PermissionlessAsset} — identified as above, plus what prices it. */
35
+ const assetSchema = priceFeedAssetSchema.extend({
28
36
  owner: require_permissionless_api_schemas.addressSchema,
29
37
  priceFeeds: zod_v4.z.array(priceFeedSchema)
30
38
  });
31
- /** {@link PermissionlessPriceFeedStore} */
32
- const priceFeedStoreSchema = zod_v4.z.looseObject({
33
- chainId: zod_v4.z.number(),
34
- name: zod_v4.z.string(),
35
- isPublic: zod_v4.z.boolean(),
36
- isActivated: zod_v4.z.boolean(),
37
- explorerUrl: zod_v4.z.string(),
39
+ /**
40
+ * {@link PermissionlessPriceFeedStore}
41
+ *
42
+ * A store is a chain's, and is described by the same five fields the chain
43
+ * list answers with, so those are extended rather than restated.
44
+ **/
45
+ const priceFeedStoreSchema = require_permissionless_api_chains_schemas.chainSchema.extend({
38
46
  assets: zod_v4.z.array(assetSchema),
39
47
  priceFeeds: zod_v4.z.array(priceFeedSchema)
40
48
  });
41
- /** {@link PermissionlessPrices} */
42
- const pricesSchema = zod_v4.z.looseObject({
43
- prices: require_permissionless_api_schemas.addressRecord(zod_v4.z.string().nullable()),
44
- marketCaps: require_permissionless_api_schemas.addressRecord(require_permissionless_api_schemas.addressRecord(zod_v4.z.string().nullable())),
45
- time: zod_v4.z.number()
46
- });
47
- /** {@link PermissionlessPriceFeedAsset} */
48
- const priceFeedAssetSchema = zod_v4.z.looseObject({
49
- address: require_permissionless_api_schemas.addressSchema,
50
- symbol: zod_v4.z.string(),
51
- name: zod_v4.z.string(),
52
- decimals: zod_v4.z.number()
53
- });
54
- /** {@link PermissionlessPriceFeedMarket} */
55
- const priceFeedMarketSchema = zod_v4.z.looseObject({
49
+ /** Every chain's {@link PermissionlessPriceFeedStore}, one per chain. */
50
+ const priceFeedStoresSchema = zod_v4.z.array(priceFeedStoreSchema);
51
+ /**
52
+ * What names a market, whichever side it is being listed from.
53
+ *
54
+ * A feed's markets and an asset's markets are different reads, but they
55
+ * answer with the same market: who curates it, what it is denominated in and
56
+ * how much of the quota is taken. Only what the read is about differs, which
57
+ * is what each of the two below adds.
58
+ **/
59
+ const marketSchema = zod_v4.z.looseObject({
56
60
  market: require_permissionless_api_schemas.addressSchema,
57
61
  marketConfigurator: require_permissionless_api_schemas.addressSchema,
58
62
  curatorName: zod_v4.z.string().nullable(),
59
63
  marketName: zod_v4.z.string().nullable(),
64
+ underlyingSymbol: zod_v4.z.string().nullable(),
65
+ isUnderlying: zod_v4.z.boolean(),
66
+ quotaLimit: zod_v4.z.number().nullable(),
67
+ quotaUsed: zod_v4.z.number().nullable()
68
+ });
69
+ /**
70
+ * {@link PermissionlessIndexedPriceFeedMarket} — the market as the feed's slot
71
+ * in it, before the oracle is asked what period it holds for the slot.
72
+ **/
73
+ const priceFeedMarketSchema = marketSchema.extend({
60
74
  token: require_permissionless_api_schemas.addressSchema,
61
75
  tokenSymbol: zod_v4.z.string().nullable(),
62
- underlyingSymbol: zod_v4.z.string().nullable(),
63
76
  reserve: zod_v4.z.boolean(),
64
- isUnderlying: zod_v4.z.boolean(),
65
- quotaLimit: zod_v4.z.number().nullable()
77
+ priceOracle: require_permissionless_api_schemas.addressSchema
78
+ });
79
+ /**
80
+ * {@link PermissionlessMarketSlot} — the same slot read from the chain's end,
81
+ * so the feed is a column rather than what was asked for.
82
+ **/
83
+ const marketSlotSchema = priceFeedMarketSchema.extend({
84
+ chainId: zod_v4.z.number(),
85
+ underlyingToken: require_permissionless_api_schemas.addressSchema,
86
+ isShutdown: zod_v4.z.boolean(),
87
+ priceFeed: require_permissionless_api_schemas.addressSchema,
88
+ priceFeedName: zod_v4.z.string().nullable(),
89
+ priceFeedInStore: zod_v4.z.boolean(),
90
+ underlyingPriceFeed: require_permissionless_api_schemas.addressSchema.nullable()
66
91
  });
67
- /** {@link PermissionlessPriceFeedDetails} */
92
+ /** Every slot in scope, across whichever chains the read covered. */
93
+ const marketSlotsSchema = zod_v4.z.array(marketSlotSchema);
94
+ /** {@link PermissionlessIndexedPriceFeedDetails} */
68
95
  const priceFeedDetailsSchema = zod_v4.z.looseObject({
69
96
  chainId: zod_v4.z.number(),
70
97
  priceFeed: priceFeedSchema,
71
98
  assets: zod_v4.z.array(priceFeedAssetSchema),
72
99
  markets: zod_v4.z.array(priceFeedMarketSchema)
73
100
  });
74
- /** {@link PermissionlessPriceFeedMarketCaps} */
75
- const priceFeedMarketCapsSchema = zod_v4.z.looseObject({
76
- marketCaps: require_permissionless_api_schemas.addressRecord(zod_v4.z.string().nullable()),
77
- time: zod_v4.z.number()
101
+ /** {@link PermissionlessAssetMarketFeed} */
102
+ const assetMarketFeedSchema = zod_v4.z.looseObject({
103
+ address: require_permissionless_api_schemas.addressSchema,
104
+ name: zod_v4.z.string().nullable(),
105
+ inStore: zod_v4.z.boolean()
106
+ });
107
+ /** {@link PermissionlessAssetMarket} — the market as what prices the asset in it. */
108
+ const assetMarketSchema = marketSchema.extend({
109
+ underlyingToken: require_permissionless_api_schemas.addressSchema,
110
+ underlyingPriceFeed: require_permissionless_api_schemas.addressSchema.nullable(),
111
+ isShutdown: zod_v4.z.boolean(),
112
+ mainFeed: assetMarketFeedSchema.nullable(),
113
+ reserveFeed: assetMarketFeedSchema.nullable()
114
+ });
115
+ /** {@link PermissionlessIndexedAssetDetails} */
116
+ const assetDetailsSchema = zod_v4.z.looseObject({
117
+ chainId: zod_v4.z.number(),
118
+ asset: priceFeedAssetSchema,
119
+ priceFeeds: zod_v4.z.array(priceFeedSchema),
120
+ markets: zod_v4.z.array(assetMarketSchema)
121
+ });
122
+ /** {@link PermissionlessAssetQuota} */
123
+ const assetQuotaSchema = zod_v4.z.looseObject({
124
+ quotaLimit: zod_v4.z.number().nullable(),
125
+ quotaUsed: zod_v4.z.number().nullable(),
126
+ isShutdown: zod_v4.z.boolean(),
127
+ underlyingPriceFeed: require_permissionless_api_schemas.addressSchema.nullable()
128
+ });
129
+ /** {@link PermissionlessIndexedAssetSummary} */
130
+ const assetSummarySchema = zod_v4.z.looseObject({
131
+ chainId: zod_v4.z.number(),
132
+ address: require_permissionless_api_schemas.addressSchema,
133
+ symbol: zod_v4.z.string(),
134
+ underlyingMarketCount: zod_v4.z.number(),
135
+ marketQuotas: zod_v4.z.array(assetQuotaSchema)
78
136
  });
137
+ /** The list of {@link PermissionlessAssetSummary}, already ordered. */
138
+ const assetSummariesSchema = zod_v4.z.array(assetSummarySchema);
79
139
  //#endregion
140
+ exports.assetDetailsSchema = assetDetailsSchema;
141
+ exports.assetMarketFeedSchema = assetMarketFeedSchema;
142
+ exports.assetMarketSchema = assetMarketSchema;
143
+ exports.assetQuotaSchema = assetQuotaSchema;
80
144
  exports.assetSchema = assetSchema;
145
+ exports.assetSummariesSchema = assetSummariesSchema;
146
+ exports.assetSummarySchema = assetSummarySchema;
147
+ exports.marketSlotSchema = marketSlotSchema;
148
+ exports.marketSlotsSchema = marketSlotsSchema;
81
149
  exports.priceFeedAssetSchema = priceFeedAssetSchema;
82
150
  exports.priceFeedDetailsSchema = priceFeedDetailsSchema;
83
- exports.priceFeedMarketCapsSchema = priceFeedMarketCapsSchema;
84
151
  exports.priceFeedMarketSchema = priceFeedMarketSchema;
85
152
  exports.priceFeedSchema = priceFeedSchema;
86
153
  exports.priceFeedStoreSchema = priceFeedStoreSchema;
87
- exports.pricesSchema = pricesSchema;
154
+ exports.priceFeedStoresSchema = priceFeedStoresSchema;
@@ -0,0 +1,99 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/permissionless/api/oracles/score/formula.ts
3
+ /**
4
+ * How well a market guards an asset's price, from its two feeds alone.
5
+ *
6
+ * Two questions, and the points are lost for each separately:
7
+ *
8
+ * - Would the reserve disagree with a main feed that has gone wrong? Only if
9
+ * it is a second feed on other sources. A missing reserve, a
10
+ * `ZeroPriceFeed`, the main feed again, and a different feed on the same
11
+ * sources all answer no.
12
+ * - Is either feed bounded? A `BoundedPriceFeed` caps the answer from above,
13
+ * and a Gearbox LP feed clamps its exchange rate to a window.
14
+ *
15
+ * Independence costs more than the bound, 6 points against 5, because it is
16
+ * the broader protection: a bounded feed caps only from above, and an LP
17
+ * feed's window holds only its rate, not the price of what the rate is in.
18
+ * Either failure alone lands a market at 4 or 5; both together at 0.
19
+ */
20
+ const INDEPENDENCE_WEIGHT = 6;
21
+ const BOUND_WEIGHT = 5;
22
+ /**
23
+ * The feed types that bound what they answer: the `BoundedPriceFeed`, and
24
+ * every Gearbox LP feed, all of which clamp the rate they read.
25
+ */
26
+ const BOUNDED_TYPE = /::(BOUNDED|ERC4626|CURVE_\w+|WSTETH|YEARN|MELLOW\w*|BALANCER\w*)$/;
27
+ const ZERO_TYPE = "PRICE_FEED::ZERO";
28
+ /**
29
+ * The share of the two sides' sources that are not shared, by key.
30
+ *
31
+ * Nothing on either side — two hardcoded prices — is 0, because a reserve is
32
+ * there to be a second opinion and neither of them is one.
33
+ */
34
+ function independenceOf(main, reserve) {
35
+ const a = new Set(main.map((source) => source.key));
36
+ const b = new Set(reserve.map((source) => source.key));
37
+ const union = /* @__PURE__ */ new Set([...a, ...b]);
38
+ if (union.size === 0) return 0;
39
+ return 1 - [...a].filter((key) => b.has(key)).length / union.size;
40
+ }
41
+ /** Down to the half point, so that a score is never rounded up into a band. */
42
+ function toHalf(value) {
43
+ return Math.floor(value * 2 + 1e-9) / 2;
44
+ }
45
+ /**
46
+ * One market's score for one asset.
47
+ *
48
+ * `reserve` is `null` where the market holds no reserve for the asset at all.
49
+ * A source is passed per side and keyed by the caller, which is where it is
50
+ * decided that an unnamed source is its own contract and a named one is its
51
+ * group.
52
+ */
53
+ function scoreMarket(market, main, reserve) {
54
+ const reasons = [];
55
+ let hasReserve = true;
56
+ if (reserve === null) {
57
+ hasReserve = false;
58
+ reasons.push("no reserve feed");
59
+ } else if (reserve.feed.contractType === ZERO_TYPE) {
60
+ hasReserve = false;
61
+ reasons.push("reserve is a ZeroPriceFeed");
62
+ } else if (reserve.feed.feed.toLowerCase() === main.feed.feed.toLowerCase()) {
63
+ hasReserve = false;
64
+ reasons.push("reserve is the main feed");
65
+ }
66
+ const reserveSources = hasReserve && reserve ? reserve.sources : [];
67
+ const independence = hasReserve ? independenceOf(main.sources, reserveSources) : 0;
68
+ const reserveKeys = new Set(reserveSources.map((source) => source.key));
69
+ const mainKeys = new Set(main.sources.map((source) => source.key));
70
+ const shared = main.sources.filter((source) => reserveKeys.has(source.key));
71
+ const names = (sources) => [...new Set(sources.map((source) => source.name))];
72
+ if (hasReserve && independence < 1) reasons.push(shared.length > 0 ? `main and reserve share ${names(shared).join(", ")}` : "neither feed reads a price source");
73
+ const unverified = hasReserve && [...main.sources.filter((source) => !reserveKeys.has(source.key)), ...reserveSources.filter((source) => !mainKeys.has(source.key))].some((source) => !source.identified);
74
+ const bounded = BOUNDED_TYPE.test(main.feed.contractType) || reserve !== null && BOUNDED_TYPE.test(reserve.feed.contractType);
75
+ if (!bounded) reasons.push("neither feed is bounded");
76
+ const score = toHalf(Math.max(0, 10 - 6 * (1 - independence) - 5 * (bounded ? 0 : 1)));
77
+ return {
78
+ ...market,
79
+ main: {
80
+ ...main.feed,
81
+ sources: names(main.sources)
82
+ },
83
+ reserve: reserve ? {
84
+ ...reserve.feed,
85
+ sources: names(reserve.sources)
86
+ } : null,
87
+ hasReserve,
88
+ independence,
89
+ bounded,
90
+ sharedSources: names(shared),
91
+ unverified,
92
+ score,
93
+ reasons
94
+ };
95
+ }
96
+ //#endregion
97
+ exports.BOUND_WEIGHT = BOUND_WEIGHT;
98
+ exports.INDEPENDENCE_WEIGHT = INDEPENDENCE_WEIGHT;
99
+ exports.scoreMarket = scoreMarket;
@@ -0,0 +1,8 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_permissionless_api_oracles_score_formula = require("./formula.js");
3
+ const require_permissionless_api_oracles_score_run = require("./run.js");
4
+ require("./types.js");
5
+ exports.BOUND_WEIGHT = require_permissionless_api_oracles_score_formula.BOUND_WEIGHT;
6
+ exports.INDEPENDENCE_WEIGHT = require_permissionless_api_oracles_score_formula.INDEPENDENCE_WEIGHT;
7
+ exports.runAssetScores = require_permissionless_api_oracles_score_run.runAssetScores;
8
+ exports.scoreMarket = require_permissionless_api_oracles_score_formula.scoreMarket;
@@ -0,0 +1,88 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_permissionless_api_oracles_stress_classify = require("../stress/classify.js");
3
+ const require_permissionless_api_oracles_stress_run = require("../stress/run.js");
4
+ const require_permissionless_api_oracles_score_formula = require("./formula.js");
5
+ //#region src/permissionless/api/oracles/score/run.ts
6
+ /**
7
+ * How a source is told apart from another when two feeds are compared.
8
+ *
9
+ * A named source by its group, since two Chainlink aggregators are one
10
+ * provider failing together. An unnamed one by its contract, since nothing
11
+ * says what else it fails with — so the same contract on both sides is
12
+ * shared, and two different ones are not.
13
+ */
14
+ function toScoreSource(source) {
15
+ return {
16
+ key: source.identified ? `group:${source.group}` : `contract:${source.target}`,
17
+ name: source.group,
18
+ identified: source.identified
19
+ };
20
+ }
21
+ /**
22
+ * Every asset of one chain, scored by how its running markets price it.
23
+ *
24
+ * One read of every oracle's feed tree and one of the LP feeds' rate
25
+ * contracts, both multicalls: the score is a reading of the trees and needs
26
+ * no simulation.
27
+ **/
28
+ async function runAssetScores({ client, chainId, slots, compressor, logger }) {
29
+ const running = slots.filter((slot) => !slot.isShutdown);
30
+ const oracles = [...new Set(running.map((slot) => slot.priceOracle.toLowerCase()))];
31
+ const { nodes, unreadableOracles } = await require_permissionless_api_oracles_stress_run.readForest(client, compressor, oracles);
32
+ for (const oracle of unreadableOracles) logger?.warn(`price oracle ${oracle} of chain ${chainId} would not report its feed tree; the markets on it are not scored`);
33
+ const { targets } = await require_permissionless_api_oracles_stress_run.readRateTargets(client, [...nodes.values()].filter((node) => require_permissionless_api_oracles_stress_run.RATE_FEED_TYPE.test(node.contractType)).map((node) => node.address));
34
+ const { sources } = require_permissionless_api_oracles_stress_classify.classifySources(chainId, [...nodes.values()], targets, () => null);
35
+ const byTarget = new Map(sources.filter((source) => source.perturbable).map((source) => [source.target, toScoreSource(source)]));
36
+ const feedOf = (slot) => slot.priceFeed.toLowerCase();
37
+ const reach = require_permissionless_api_oracles_stress_classify.sourcesByFeed([...new Set(running.map(feedOf))], nodes, sources);
38
+ const sourcesOf = (feed) => [...reach.get(feed) ?? []].map((target) => byTarget.get(target)).filter((source) => source !== void 0);
39
+ const positions = /* @__PURE__ */ new Map();
40
+ for (const slot of running) {
41
+ const key = `${slot.market.toLowerCase()}:${slot.token.toLowerCase()}`;
42
+ const position = positions.get(key) ?? {};
43
+ position[slot.reserve ? "reserve" : "main"] = slot;
44
+ positions.set(key, position);
45
+ }
46
+ const byAsset = /* @__PURE__ */ new Map();
47
+ for (const { main, reserve } of positions.values()) {
48
+ if (!main || main.isUnderlying) continue;
49
+ const asset = main.token.toLowerCase();
50
+ const entry = byAsset.get(asset) ?? {
51
+ symbol: main.tokenSymbol,
52
+ markets: []
53
+ };
54
+ byAsset.set(asset, entry);
55
+ const mainNode = nodes.get(feedOf(main));
56
+ if (!mainNode) continue;
57
+ if (mainNode.contractType === "PRICE_FEED::ZERO") continue;
58
+ const side = (slot) => ({
59
+ feed: {
60
+ feed: feedOf(slot),
61
+ name: slot.priceFeedName,
62
+ contractType: nodes.get(feedOf(slot))?.contractType ?? ""
63
+ },
64
+ sources: sourcesOf(feedOf(slot))
65
+ });
66
+ entry.markets.push(require_permissionless_api_oracles_score_formula.scoreMarket({
67
+ market: main.market,
68
+ marketName: main.marketName,
69
+ marketConfigurator: main.marketConfigurator,
70
+ curatorName: main.curatorName
71
+ }, side(main), reserve ? side(reserve) : null));
72
+ }
73
+ return [...byAsset].map(([asset, { symbol, markets }]) => {
74
+ const sorted = markets.sort((a, b) => a.score - b.score);
75
+ const worst = sorted[0] ?? null;
76
+ return {
77
+ chainId,
78
+ asset,
79
+ symbol,
80
+ score: worst?.score ?? null,
81
+ unverified: sorted.some((market) => market.unverified),
82
+ worst,
83
+ markets: sorted
84
+ };
85
+ });
86
+ }
87
+ //#endregion
88
+ exports.runAssetScores = runAssetScores;
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });