@gearbox-protocol/sdk 16.0.0-next.54 → 16.0.0-next.56

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 (106) hide show
  1. package/dist/cjs/dev/mode-parity/compareOpportunities.js +3 -4
  2. package/dist/cjs/dev/mode-parity/comparePositions.js +5 -6
  3. package/dist/cjs/dev/mode-parity/fieldDiff.js +4 -6
  4. package/dist/cjs/dev/mode-parity/scriptUtils.js +145 -5
  5. package/dist/cjs/model/analytics.schema.js +44 -1
  6. package/dist/cjs/model/charts.js +15 -1
  7. package/dist/cjs/model/charts.schema.js +9 -3
  8. package/dist/cjs/model/index.js +9 -4
  9. package/dist/cjs/model/liquidations.schema.js +1 -1
  10. package/dist/cjs/model/opportunities.schema.js +2 -2
  11. package/dist/cjs/model/positions.schema.js +2 -2
  12. package/dist/cjs/offchain/analytics/OffchainAnalytics.js +25 -2
  13. package/dist/cjs/rewards/errors.js +27 -0
  14. package/dist/cjs/rewards/index.js +6 -7
  15. package/dist/cjs/rewards/merkl-api.js +45 -0
  16. package/dist/cjs/rewards/multichain.js +40 -0
  17. package/dist/cjs/rewards/{rewards/api.js → toMerklRewards.js} +26 -28
  18. package/dist/cjs/sdk/analytics/AnalyticsNamespace.js +6 -0
  19. package/dist/esm/dev/AccountOpener.js +1 -1
  20. package/dist/esm/dev/mode-parity/compareOpportunities.js +3 -4
  21. package/dist/esm/dev/mode-parity/comparePositions.js +5 -6
  22. package/dist/esm/dev/mode-parity/fieldDiff.js +4 -6
  23. package/dist/esm/dev/mode-parity/scriptUtils.js +142 -6
  24. package/dist/esm/dev/withdrawalUtils.js +1 -1
  25. package/dist/esm/model/analytics.schema.js +42 -2
  26. package/dist/esm/model/charts.js +15 -2
  27. package/dist/esm/model/charts.schema.js +9 -4
  28. package/dist/esm/model/index.js +6 -6
  29. package/dist/esm/model/liquidations.schema.js +1 -1
  30. package/dist/esm/model/opportunities.schema.js +2 -2
  31. package/dist/esm/model/positions.schema.js +2 -2
  32. package/dist/esm/offchain/analytics/OffchainAnalytics.js +25 -2
  33. package/dist/esm/onchain/accounts/CreditAccountsServiceV310.js +2 -2
  34. package/dist/esm/onchain/accounts/liquidations/LiquidationsService.js +1 -1
  35. package/dist/esm/onchain/accounts/withdrawal-compressor/RedemptionLoggerV310Contract.js +1 -1
  36. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV310Contract.js +1 -1
  37. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV311Contract.js +1 -1
  38. package/dist/esm/onchain/accounts/withdrawal-compressor/WithdrawalCompressorV313Contract.js +1 -1
  39. package/dist/esm/onchain/base/TokensMeta.js +3 -3
  40. package/dist/esm/onchain/core/createAddressProvider.js +1 -1
  41. package/dist/esm/onchain/market/adapters/contracts/AccountMigratorAdapterContract.js +1 -1
  42. package/dist/esm/onchain/market/adapters/contracts/ERC4626AdapterContract.js +1 -1
  43. package/dist/esm/onchain/market/credit/CreditFacadeV310BaseContract.js +1 -1
  44. package/dist/esm/onchain/market/pool/PoolV310Contract.js +1 -1
  45. package/dist/esm/onchain/market/zapper/IETHZapperContract.js +1 -1
  46. package/dist/esm/onchain/market/zapper/ZapperContract.js +1 -1
  47. package/dist/esm/onchain/utils/viem/simulateWithPriceUpdates.js +1 -1
  48. package/dist/esm/preview/simulate/simulatePoolOperation.js +1 -1
  49. package/dist/esm/preview/trace/extractTransfers.js +1 -1
  50. package/dist/esm/rewards/errors.js +26 -0
  51. package/dist/esm/rewards/index.js +4 -5
  52. package/dist/esm/rewards/merkl-api.js +42 -0
  53. package/dist/esm/rewards/multichain.js +39 -0
  54. package/dist/esm/rewards/{rewards/api.js → toMerklRewards.js} +26 -28
  55. package/dist/esm/sdk/analytics/AnalyticsNamespace.js +6 -0
  56. package/dist/types/dev/mode-parity/compareOpportunities.d.ts +3 -7
  57. package/dist/types/dev/mode-parity/comparePositions.d.ts +4 -8
  58. package/dist/types/dev/mode-parity/fieldDiff.d.ts +9 -8
  59. package/dist/types/dev/mode-parity/scriptUtils.d.ts +26 -1
  60. package/dist/types/model/analytics.d.ts +22 -1
  61. package/dist/types/model/analytics.schema.d.ts +65 -1
  62. package/dist/types/model/charts.d.ts +20 -2
  63. package/dist/types/model/charts.schema.d.ts +14 -2
  64. package/dist/types/model/index.d.ts +5 -5
  65. package/dist/types/offchain/AbstractOffchainNamespace.d.ts +1 -1
  66. package/dist/types/offchain/analytics/OffchainAnalytics.d.ts +14 -2
  67. package/dist/types/offchain/analytics/types.d.ts +11 -0
  68. package/dist/types/offchain/opportunities/OffchainOpportunities.d.ts +1 -1
  69. package/dist/types/offchain/opportunities/types.d.ts +1 -1
  70. package/dist/types/offchain/positions/OffchainPositions.d.ts +1 -1
  71. package/dist/types/offchain/positions/types.d.ts +1 -1
  72. package/dist/types/rewards/errors.d.ts +18 -0
  73. package/dist/types/rewards/index.d.ts +4 -7
  74. package/dist/types/rewards/merkl-api.d.ts +64 -0
  75. package/dist/types/rewards/multichain.d.ts +33 -0
  76. package/dist/types/rewards/toMerklRewards.d.ts +42 -0
  77. package/dist/types/sdk/analytics/AnalyticsNamespace.d.ts +6 -0
  78. package/dist/types/sdk/analytics/types.d.ts +16 -0
  79. package/dist/types/sdk/opportunities/OpportunitiesNamespace.d.ts +1 -1
  80. package/dist/types/sdk/opportunities/types.d.ts +1 -1
  81. package/dist/types/sdk/positions/PositionsNamespace.d.ts +1 -1
  82. package/dist/types/sdk/positions/types.d.ts +1 -1
  83. package/package.json +1 -3
  84. package/dist/cjs/_virtual/_rolldown/runtime.js +0 -23
  85. package/dist/cjs/rewards/apy/index.js +0 -3
  86. package/dist/cjs/rewards/apy/output-details.js +0 -1
  87. package/dist/cjs/rewards/apy/output.js +0 -1
  88. package/dist/cjs/rewards/rewards/common.js +0 -1
  89. package/dist/cjs/rewards/rewards/extra-apy.js +0 -71
  90. package/dist/cjs/rewards/rewards/index.js +0 -6
  91. package/dist/cjs/rewards/rewards/merkl-api.js +0 -22
  92. package/dist/esm/rewards/apy/index.js +0 -3
  93. package/dist/esm/rewards/apy/output-details.js +0 -1
  94. package/dist/esm/rewards/apy/output.js +0 -1
  95. package/dist/esm/rewards/rewards/common.js +0 -1
  96. package/dist/esm/rewards/rewards/extra-apy.js +0 -67
  97. package/dist/esm/rewards/rewards/index.js +0 -3
  98. package/dist/esm/rewards/rewards/merkl-api.js +0 -19
  99. package/dist/types/rewards/apy/index.d.ts +0 -3
  100. package/dist/types/rewards/apy/output-details.d.ts +0 -99
  101. package/dist/types/rewards/apy/output.d.ts +0 -25
  102. package/dist/types/rewards/rewards/api.d.ts +0 -60
  103. package/dist/types/rewards/rewards/common.d.ts +0 -9
  104. package/dist/types/rewards/rewards/extra-apy.d.ts +0 -37
  105. package/dist/types/rewards/rewards/index.d.ts +0 -3
  106. package/dist/types/rewards/rewards/merkl-api.d.ts +0 -54
@@ -1,28 +1,17 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_onchain_utils_AddressMap = require("../../onchain/utils/AddressMap.js");
3
- const require_onchain_utils_bigint_math = require("../../onchain/utils/bigint-math.js");
4
- const require_onchain_utils_formatter = require("../../onchain/utils/formatter.js");
5
- require("../../onchain/index.js");
6
- const require_rewards_rewards_merkl_api = require("./merkl-api.js");
2
+ const require_onchain_utils_AddressMap = require("../onchain/utils/AddressMap.js");
3
+ const require_onchain_utils_bigint_math = require("../onchain/utils/bigint-math.js");
4
+ const require_onchain_utils_formatter = require("../onchain/utils/formatter.js");
5
+ require("../onchain/index.js");
7
6
  let viem = require("viem");
8
- //#region src/rewards/rewards/api.ts
7
+ //#region src/rewards/toMerklRewards.ts
9
8
  /**
10
- * The wallet's claimable Merkl rewards on one chain.
11
- *
12
- * Never rejects on a transport failure: the fetch is settled rather than
13
- * awaited, and a failure goes to `reportError` and yields an empty list. A
14
- * caller that must tell "this chain is down" from "this chain has no rewards"
15
- * has to watch that callback.
9
+ * Merkl's answer for one chain, turned into rows of the read model.
16
10
  */
17
- async function getMerklRewards({ sdk, account, reportError, apiKey }) {
18
- const [merkleXYZLMResponse] = await Promise.allSettled([require_rewards_rewards_merkl_api.MerkleXYZApi.fetchWithFallback(require_rewards_rewards_merkl_api.MerkleXYZApi.getUserRewardsUrl({ params: {
19
- chainId: sdk.chainId,
20
- user: (0, viem.getAddress)(account)
21
- } }), apiKey)]);
22
- const merkleXYZLm = extractFulfilled(merkleXYZLMResponse, reportError, "merkleXYZLm")?.data;
11
+ function toMerklRewards(sdk, response) {
23
12
  const poolByItsToken = require_onchain_utils_AddressMap.AddressMap.fromMappedArray(sdk.marketRegister.pools.map(({ pool }) => pool.address), (address) => address);
24
13
  const claimable = /* @__PURE__ */ new Map();
25
- for (const chainRewards of merkleXYZLm || []) for (const reward of chainRewards.rewards) {
14
+ for (const chainRewards of response) for (const reward of chainRewards.rewards) {
26
15
  if (!(0, viem.isAddress)(reward.token.address, { strict: false })) continue;
27
16
  const rewardTokenAddress = (0, viem.getAddress)(reward.token.address);
28
17
  for (const reason of reward.breakdowns) {
@@ -30,9 +19,9 @@ async function getMerklRewards({ sdk, account, reportError, apiKey }) {
30
19
  if (!(0, viem.isAddress)(poolTokenAddress, { strict: false })) continue;
31
20
  const pool = poolByItsToken.get(poolTokenAddress);
32
21
  if (!pool) continue;
33
- const total = require_onchain_utils_formatter.toBigInt(reason.amount || 0);
34
- const claimed = require_onchain_utils_formatter.toBigInt(reason.claimed || 0);
35
- const amount = require_onchain_utils_bigint_math.BigIntMath.max(total - claimed, 0n);
22
+ const amounts = toAmounts(reason);
23
+ if (!amounts) continue;
24
+ const amount = require_onchain_utils_bigint_math.BigIntMath.max(amounts.total - amounts.claimed, 0n);
36
25
  if (amount === 0n) continue;
37
26
  const key = `${pool}_${rewardTokenAddress}`;
38
27
  const seen = claimable.get(key);
@@ -54,6 +43,20 @@ async function getMerklRewards({ sdk, account, reportError, apiKey }) {
54
43
  }
55
44
  return [...claimable.values()].map(toReward);
56
45
  }
46
+ /**
47
+ * `toBigInt` throws on anything `BigInt()` cannot parse, and Merkl's amounts
48
+ * are free-form strings.
49
+ */
50
+ function toAmounts(reason) {
51
+ try {
52
+ return {
53
+ total: require_onchain_utils_formatter.toBigInt(reason.amount || 0),
54
+ claimed: require_onchain_utils_formatter.toBigInt(reason.claimed || 0)
55
+ };
56
+ } catch {
57
+ return;
58
+ }
59
+ }
57
60
  function toReward({ price, token, value, ...rest }) {
58
61
  return {
59
62
  ...rest,
@@ -78,10 +81,5 @@ function toRewardToken(sdk, address, merkl) {
78
81
  decimals: merkl.decimals || 18
79
82
  };
80
83
  }
81
- function extractFulfilled(r, reportError, description) {
82
- if (r.status === "fulfilled") return r.value;
83
- if (reportError) reportError(r.reason, description);
84
- else console.error(r.reason);
85
- }
86
84
  //#endregion
87
- exports.getMerklRewards = getMerklRewards;
85
+ exports.toMerklRewards = toMerklRewards;
@@ -3,9 +3,15 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  /** Backend-only protocol analytics exposed by {@link GearboxSDK}. */
4
4
  var AnalyticsNamespace = class {
5
5
  positions;
6
+ #backend;
6
7
  constructor(backend) {
8
+ this.#backend = backend;
7
9
  this.positions = backend.analytics.positions;
8
10
  }
11
+ /** {@inheritDoc IAnalytics.charts} */
12
+ async charts(metrics, range, filter) {
13
+ return this.#backend.analytics.getCharts(metrics, range, filter);
14
+ }
9
15
  };
10
16
  //#endregion
11
17
  exports.AnalyticsNamespace = AnalyticsNamespace;
@@ -1,5 +1,5 @@
1
- import { ierc20Abi } from "../abi/iERC20.js";
2
1
  import { iCreditFacadeV310Abi } from "../abi/310/generated.js";
2
+ import { ierc20Abi } from "../abi/iERC20.js";
3
3
  import { AddressMap } from "../onchain/utils/AddressMap.js";
4
4
  import { AddressSet } from "../onchain/utils/AddressSet.js";
5
5
  import { AssetsMap } from "../onchain/utils/AssetsMap.js";
@@ -14,8 +14,8 @@ const tagDiff = makeTagDiff({
14
14
  *
15
15
  * Nothing is filtered out. A field only the backend can fill, or a USD value
16
16
  * that drifted within snapshot-lag noise, is still reported — tagged
17
- * {@link FieldDiff.expected} so that {@link CompareCounts.clean} can ignore it
18
- * while {@link CompareCounts.identical} stays strict.
17
+ * {@link FieldDiff.expected} so that {@link CompareCounts.similar} can ignore
18
+ * it.
19
19
  **/
20
20
  function compareOpportunities(input) {
21
21
  const onchainRows = indexById(input.onchain.data);
@@ -36,8 +36,7 @@ function compareOpportunities(input) {
36
36
  chainId: row.chainId,
37
37
  onchainName: row.name,
38
38
  offchainName: counterpart.name,
39
- identical: diffs.length === 0,
40
- clean: diffs.every((diff) => diff.expected),
39
+ similar: diffs.every((diff) => diff.expected),
41
40
  diffs
42
41
  });
43
42
  }
@@ -17,8 +17,8 @@ const tagDiff = makeTagDiff({
17
17
  * Nothing is filtered out. A field only one mode can fill, a strategy field
18
18
  * both-mode merge overlays from the backend, or a USD value that drifted
19
19
  * within snapshot-lag noise, is still reported — tagged
20
- * {@link FieldDiff.expected} so that {@link CompareCounts.clean} can ignore it
21
- * while {@link CompareCounts.identical} stays strict.
20
+ * {@link FieldDiff.expected} so that {@link CompareCounts.similar} can ignore
21
+ * it.
22
22
  **/
23
23
  function comparePositions(input) {
24
24
  const failures = input.failures ?? [];
@@ -65,8 +65,7 @@ function compareWallet(input) {
65
65
  chainId: row.chainId,
66
66
  onchainName: row.name,
67
67
  offchainName: counterpart.name,
68
- identical: diffs.length === 0,
69
- clean: diffs.every((diff) => diff.expected),
68
+ similar: diffs.every((diff) => diff.expected),
70
69
  diffs
71
70
  });
72
71
  }
@@ -129,11 +128,11 @@ function summarize(inputs, wallets, failed) {
129
128
  ...wallet.error ? { error: wallet.error } : {},
130
129
  ...toCompareCounts(wallet.matched.length + wallet.onlyOnchain.length, wallet.matched.length + wallet.onlyOffchain.length, wallet.onlyOnchain.length, wallet.onlyOffchain.length, wallet.matched)
131
130
  }));
132
- const walletsClean = compared.filter((wallet) => wallet.onlyOnchain.length === 0 && wallet.onlyOffchain.length === 0 && wallet.matched.every((match) => match.clean)).length;
131
+ const walletsSimilar = compared.filter((wallet) => wallet.onlyOnchain.length === 0 && wallet.onlyOffchain.length === 0 && wallet.matched.every((match) => match.similar)).length;
133
132
  return {
134
133
  ...toCompareCounts(allOnchain.length, allOffchain.length, onlyOnchain.length, onlyOffchain.length, matched),
135
134
  wallets: wallets.length,
136
- walletsClean,
135
+ walletsSimilar,
137
136
  walletsFailed: failed,
138
137
  byChain,
139
138
  byWallet,
@@ -53,7 +53,7 @@ function diffObjects(onchain, offchain, options) {
53
53
  return diffs;
54
54
  }
55
55
  /**
56
- * Mark a diff expected, so a later `clean` count can ignore it.
56
+ * Mark a diff expected, so a later `similar` count can ignore it.
57
57
  **/
58
58
  function withExpected(diff, reason) {
59
59
  return {
@@ -117,15 +117,13 @@ function collapseArrayKeys(path) {
117
117
  * Membership and match totals of one comparison, from already-built lists.
118
118
  **/
119
119
  function toCompareCounts(onchainRows, offchainRows, onlyOnchain, onlyOffchain, matched) {
120
- const identical = matched.filter((match) => match.identical).length;
121
- const clean = matched.filter((match) => match.clean).length;
120
+ const similar = matched.filter((match) => match.similar).length;
122
121
  return {
123
122
  onchainRows,
124
123
  offchainRows,
125
124
  matched: matched.length,
126
- identical,
127
- clean,
128
- differing: matched.length - identical,
125
+ similar,
126
+ different: matched.length - similar,
129
127
  onlyOnchain,
130
128
  onlyOffchain
131
129
  };
@@ -1,4 +1,5 @@
1
1
  import { getAlchemyUrl } from "../providers.js";
2
+ import { appendFileSync } from "node:fs";
2
3
  import { pino } from "pino";
3
4
  //#region src/dev/mode-parity/scriptUtils.ts
4
5
  const NETWORKS = [
@@ -76,6 +77,40 @@ function worstColumns(worst) {
76
77
  };
77
78
  }
78
79
  /**
80
+ * Reasons a compare run should fail CI: unexpected membership or field diffs,
81
+ * both sources empty, a chain that could not be read, or wallets that failed
82
+ * to list. Expected diffs (mode-scoped, backend-preferred, tolerance) do not
83
+ * fail the run.
84
+ **/
85
+ function evaluateCompareFailure(report) {
86
+ const { summary } = report;
87
+ const reasons = [];
88
+ if (summary.onchainRows === 0 && summary.offchainRows === 0) reasons.push("both sources produced no data");
89
+ if (summary.different > 0) reasons.push(`${summary.different} matched rows are different`);
90
+ if (summary.onlyOnchain > 0) reasons.push(`${summary.onlyOnchain} rows only onchain`);
91
+ if (summary.onlyOffchain > 0) reasons.push(`${summary.onlyOffchain} rows only offchain`);
92
+ if ((summary.walletsFailed ?? 0) > 0) reasons.push(`${summary.walletsFailed} wallets failed to list`);
93
+ for (const chain of [...report.onchainChains, ...report.offchainChains]) if (chain.status === "error") reasons.push(`chain ${chain.chainId} failed on ${chain.source ?? "unknown"}: ${errorMessage(chain.error)}`);
94
+ return reasons;
95
+ }
96
+ function splitDiffs(summary) {
97
+ return {
98
+ unexpected: summary.diffsByPath.filter((entry) => entry.unexpected > 0),
99
+ expected: summary.diffsByPath.filter((entry) => entry.unexpected === 0 && entry.expected > 0)
100
+ };
101
+ }
102
+ function markdownCell(value) {
103
+ return String(value).replaceAll("|", "\\|").replaceAll("\n", " ");
104
+ }
105
+ function markdownTable(headers, rows) {
106
+ const line = (cells) => `| ${cells.map(markdownCell).join(" | ")} |`;
107
+ return [
108
+ line(headers),
109
+ line(headers.map(() => "---")),
110
+ ...rows.map(line)
111
+ ].join("\n");
112
+ }
113
+ /**
79
114
  * Prints the shared membership table, the fields that differed most often,
80
115
  * and any chain that failed to answer.
81
116
  **/
@@ -87,15 +122,13 @@ function printCompareSummary(noun, report, extraLines = []) {
87
122
  onchain: chain.onchainRows,
88
123
  offchain: chain.offchainRows,
89
124
  matched: chain.matched,
90
- identical: chain.identical,
91
- clean: chain.clean,
92
- differing: chain.differing,
125
+ similar: chain.similar,
126
+ different: chain.different,
93
127
  "only onchain": chain.onlyOnchain,
94
128
  "only offchain": chain.onlyOffchain
95
129
  })));
96
130
  for (const line of extraLines) console.log(line);
97
- const unexpected = summary.diffsByPath.filter((entry) => entry.unexpected > 0);
98
- const expected = summary.diffsByPath.filter((entry) => entry.unexpected === 0 && entry.expected > 0);
131
+ const { unexpected, expected } = splitDiffs(summary);
99
132
  if (unexpected.length) {
100
133
  console.log("\nunexpected fields that differed most often:");
101
134
  console.table(unexpected.slice(0, 25).map((entry) => ({
@@ -117,5 +150,108 @@ function printCompareSummary(noun, report, extraLines = []) {
117
150
  }
118
151
  for (const chain of [...report.onchainChains, ...report.offchainChains]) if (chain.status === "error") console.log(`chain ${chain.chainId} failed on ${chain.source}:`, chain.error);
119
152
  }
153
+ /**
154
+ * Markdown of the same summary printed to the console, for GitHub job summaries.
155
+ **/
156
+ function formatCompareMarkdown(noun, report, extraLines = [], reasons = []) {
157
+ const { summary } = report;
158
+ const { unexpected, expected } = splitDiffs(summary);
159
+ const parts = [
160
+ `# ${noun} compare`,
161
+ "",
162
+ reasons.length ? "**Failed**" : "**Passed**",
163
+ "",
164
+ `${noun} from \`${report.backendUrl}\` vs the chain`,
165
+ ""
166
+ ];
167
+ if (reasons.length) {
168
+ parts.push("## Failures", "");
169
+ for (const reason of reasons) parts.push(`- ${reason}`);
170
+ parts.push("");
171
+ }
172
+ if (extraLines.length) {
173
+ for (const line of extraLines) parts.push(line);
174
+ parts.push("");
175
+ }
176
+ if (summary.byChain.length) parts.push(markdownTable([
177
+ "chain",
178
+ "onchain",
179
+ "offchain",
180
+ "matched",
181
+ "similar",
182
+ "different",
183
+ "only onchain",
184
+ "only offchain"
185
+ ], summary.byChain.map((chain) => [
186
+ chain.chainId,
187
+ chain.onchainRows,
188
+ chain.offchainRows,
189
+ chain.matched,
190
+ chain.similar,
191
+ chain.different,
192
+ chain.onlyOnchain,
193
+ chain.onlyOffchain
194
+ ])), "");
195
+ if (unexpected.length) parts.push("## Unexpected fields that differed most often", "", markdownTable([
196
+ "field",
197
+ "unexpected",
198
+ "expected",
199
+ "kinds",
200
+ "max diff",
201
+ "worst entity"
202
+ ], unexpected.slice(0, 25).map((entry) => {
203
+ const worst = worstColumns(entry.worstUnexpected);
204
+ return [
205
+ entry.path,
206
+ entry.unexpected,
207
+ entry.expected,
208
+ entry.kinds.join(", "),
209
+ worst["max diff"],
210
+ worst["worst entity"]
211
+ ];
212
+ })), "");
213
+ if (expected.length) parts.push("## Expected fields (mode-scoped, backend-preferred, or within tolerance)", "", markdownTable([
214
+ "field",
215
+ "rows",
216
+ "kinds",
217
+ "max diff",
218
+ "worst entity"
219
+ ], expected.slice(0, 25).map((entry) => {
220
+ const worst = worstColumns(entry.worstExpected);
221
+ return [
222
+ entry.path,
223
+ entry.expected,
224
+ entry.kinds.join(", "),
225
+ worst["max diff"],
226
+ worst["worst entity"]
227
+ ];
228
+ })), "");
229
+ const failedChains = [...report.onchainChains, ...report.offchainChains].filter((chain) => chain.status === "error");
230
+ if (failedChains.length) {
231
+ parts.push("## Chain errors", "");
232
+ for (const chain of failedChains) parts.push(`- chain ${chain.chainId} failed on ${chain.source ?? "unknown"}: ${errorMessage(chain.error)}`);
233
+ parts.push("");
234
+ }
235
+ return parts.join("\n");
236
+ }
237
+ /**
238
+ * Appends {@link formatCompareMarkdown} to `GITHUB_STEP_SUMMARY` when running
239
+ * in GitHub Actions. No-op locally.
240
+ **/
241
+ function writeGithubJobSummary(noun, report, extraLines = [], reasons = []) {
242
+ const path = process.env.GITHUB_STEP_SUMMARY;
243
+ if (!path) return;
244
+ appendFileSync(path, `${formatCompareMarkdown(noun, report, extraLines, reasons)}\n`);
245
+ }
246
+ /**
247
+ * Console + job-summary output for a compare run. Returns the failure reasons
248
+ * so the caller can exit 1 when the report is not similar.
249
+ **/
250
+ function reportCompare(noun, report, extraLines = []) {
251
+ printCompareSummary(noun, report, extraLines);
252
+ const reasons = evaluateCompareFailure(report);
253
+ writeGithubJobSummary(noun, report, extraLines, reasons);
254
+ return reasons;
255
+ }
120
256
  //#endregion
121
- export { BACKEND_URL, NETWORKS, TIMEOUT, createLogger, errorMessage, formatBpsAsPercent, mapPool, printCompareSummary, requireEnv, rpcUrls };
257
+ export { BACKEND_URL, NETWORKS, TIMEOUT, createLogger, errorMessage, evaluateCompareFailure, formatBpsAsPercent, formatCompareMarkdown, mapPool, printCompareSummary, reportCompare, requireEnv, rpcUrls, writeGithubJobSummary };
@@ -1,6 +1,6 @@
1
- import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
2
1
  import { getNetworkType } from "../onchain/chain/chains.js";
3
2
  import { getWithdrawalCompressorAddress } from "../onchain/accounts/withdrawal-compressor/addresses.js";
3
+ import { iWithdrawalCompressorV313Abi } from "../abi/IWithdrawalCompressorV313.js";
4
4
  import "../onchain/index.js";
5
5
  import { iMidasDataFeedAbi, iMidasRedemptionVaultAbi, midasGatewayAbi, midasRedeemerAbi, midasRedemptionVaultPhantomTokenAbi, securitizeRedeemerAbi, securitizeRedemptionGatewayAbi, securitizeRedemptionPhantomTokenAbi } from "./withdrawalAbi.js";
6
6
  import { erc20Abi, hexToString, parseAbi, parseEther } from "viem";
@@ -1,7 +1,8 @@
1
1
  import { ZodAddress } from "../onchain/utils/zod.js";
2
+ import { assetTypeSchema, chainIdSchema } from "./primitives.schema.js";
3
+ import { chartRangeSchema, protocolChartMetricSchema } from "./charts.schema.js";
2
4
  import { isFilterSet } from "./filters.js";
3
5
  import { encodeFlag, filterable } from "./filters.schema.js";
4
- import { assetTypeSchema, chainIdSchema } from "./primitives.schema.js";
5
6
  import { liquidationPositionSchema } from "./liquidations.schema.js";
6
7
  import { poolPositionSchema, positionKindSchema, strategyPositionSchema } from "./positions.schema.js";
7
8
  import { isAddress } from "viem";
@@ -104,5 +105,44 @@ const analyticsPositionPageSchema = z.object({
104
105
  offset: z.number().int().nonnegative(),
105
106
  limit: z.number().int().positive().max(100)
106
107
  });
108
+ /**
109
+ * {@link AnalyticsChartQuery}
110
+ *
111
+ * The metric list is narrowed to {@link ProtocolChartMetric} here rather than
112
+ * on the route, so asking the protocol chart for an opportunity metric is
113
+ * rejected by the one codec both sides share instead of by a check only the
114
+ * backend runs.
115
+ **/
116
+ const analyticsChartQueryOptionsSchema = z.object({
117
+ metrics: z.array(protocolChartMetricSchema).readonly().refine((metrics) => metrics.length > 0, { error: "a chart read needs at least one metric" }).refine((metrics) => new Set(metrics).size === metrics.length, { error: "a chart read needs distinct metrics" }),
118
+ range: chartRangeSchema,
119
+ chainIds: z.array(chainIdSchema).optional()
120
+ });
121
+ /**
122
+ * {@link AnalyticsChartQuery} as URL query parameters: the metrics comma-joined
123
+ * like every other chart read, and the chains comma-joined like every other
124
+ * analytics read.
125
+ **/
126
+ const analyticsChartQueryParamsSchema = z.object({
127
+ metrics: z.string().regex(/^\w+(,\w+)*$/),
128
+ range: chartRangeSchema,
129
+ chainIds: z.string().regex(/^$|^\d+(,\d+)*$/).optional()
130
+ });
131
+ /**
132
+ * Codec for a protocol-wide chart query. It is shared by the SDK client and
133
+ * backend controller so both sides interpret every parameter identically.
134
+ **/
135
+ const analyticsChartQuerySchema = z.codec(analyticsChartQueryParamsSchema, analyticsChartQueryOptionsSchema, {
136
+ decode: (params) => ({
137
+ metrics: params.metrics.split(","),
138
+ range: params.range,
139
+ ...params.chainIds === void 0 ? {} : { chainIds: params.chainIds === "" ? [] : params.chainIds.split(",").map(Number) }
140
+ }),
141
+ encode: (query) => ({
142
+ metrics: query.metrics.join(","),
143
+ range: query.range,
144
+ chainIds: query.chainIds?.join(",")
145
+ })
146
+ });
107
147
  //#endregion
108
- export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema };
148
+ export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, analyticsChartQueryOptionsSchema, analyticsChartQueryParamsSchema, analyticsChartQuerySchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema };
@@ -84,6 +84,18 @@ const STRATEGY_POSITION_CHART_METRICS = [
84
84
  "netApy7d"
85
85
  ];
86
86
  /**
87
+ * Every metric the protocol as a whole can chart.
88
+ *
89
+ * Protocol-wide rather than per subject: the series describes Gearbox itself
90
+ * over every chain the read covers, so it has no address to hang off and is
91
+ * read from the analytics namespace rather than from an opportunity.
92
+ *
93
+ * `tvlUsd` is deliberately not spelled `tvl`: that key is already the credit
94
+ * manager's TVL in whole underlying tokens, and one metric has exactly one
95
+ * unit in {@link CHART_METRIC_UNITS}.
96
+ **/
97
+ const PROTOCOL_CHART_METRICS = ["tvlUsd"];
98
+ /**
87
99
  * Unit of every metric, the one place either side decides it.
88
100
  *
89
101
  * A metric added to a union above fails to compile here until its unit is
@@ -113,7 +125,8 @@ const CHART_METRIC_UNITS = {
113
125
  totalValueUnderlying: "token",
114
126
  debt: "token",
115
127
  healthFactor: "bps",
116
- netApy7d: "bps"
128
+ netApy7d: "bps",
129
+ tvlUsd: "usd"
117
130
  };
118
131
  /**
119
132
  * Reason a series could not be produced at all, which is not the same as a
@@ -127,4 +140,4 @@ const CHART_UNAVAILABLE_CODES = [
127
140
  "internal"
128
141
  ];
129
142
  //#endregion
130
- export { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS };
143
+ export { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS };
@@ -1,5 +1,5 @@
1
+ import { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS } from "./charts.js";
1
2
  import { timestampSchema, tokenSchema } from "./primitives.schema.js";
2
- import { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS } from "./charts.js";
3
3
  import { z } from "zod/v4";
4
4
  //#region src/model/charts.schema.ts
5
5
  /**
@@ -32,13 +32,18 @@ const poolPositionChartMetricSchema = z.enum(POOL_POSITION_CHART_METRICS);
32
32
  **/
33
33
  const strategyPositionChartMetricSchema = z.enum(STRATEGY_POSITION_CHART_METRICS);
34
34
  /**
35
- * {@link ChartMetric}, every metric either kind of subject can chart.
35
+ * {@link ProtocolChartMetric}
36
+ **/
37
+ const protocolChartMetricSchema = z.enum(PROTOCOL_CHART_METRICS);
38
+ /**
39
+ * {@link ChartMetric}, every metric any subject can chart.
36
40
  **/
37
41
  const chartMetricSchema = z.union([
38
42
  poolOpportunityChartMetricSchema,
39
43
  strategyOpportunityChartMetricSchema,
40
44
  poolPositionChartMetricSchema,
41
- strategyPositionChartMetricSchema
45
+ strategyPositionChartMetricSchema,
46
+ protocolChartMetricSchema
42
47
  ]);
43
48
  /**
44
49
  * {@link ChartQuery}
@@ -223,4 +228,4 @@ function chartBundleSchemaFor(metrics, range) {
223
228
  return chartBundleSchemaWith(z.union(literals), range);
224
229
  }
225
230
  //#endregion
226
- export { chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, poolOpportunityChartMetricSchema, poolPositionChartMetricSchema, strategyOpportunityChartMetricSchema, strategyPositionChartMetricSchema };
231
+ export { chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, poolOpportunityChartMetricSchema, poolPositionChartMetricSchema, protocolChartMetricSchema, strategyOpportunityChartMetricSchema, strategyPositionChartMetricSchema };
@@ -1,15 +1,15 @@
1
1
  import "./analytics.js";
2
+ import { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS } from "./charts.js";
3
+ import { backendPreferred, compareTagOf, offchainOnly, onchainOnly, tolerance } from "./compare.schema.js";
4
+ import { amountSchema, assetTypeSchema, bpsSchema, chainIdSchema, leverageSchema, timestampSchema, tokenAmountSchema, tokenSchema, txCallSchema, underlyingTokenSchema } from "./primitives.schema.js";
5
+ import { chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, poolOpportunityChartMetricSchema, poolPositionChartMetricSchema, protocolChartMetricSchema, strategyOpportunityChartMetricSchema, strategyPositionChartMetricSchema } from "./charts.schema.js";
2
6
  import { FILTER_ALL, isFilterSet } from "./filters.js";
3
7
  import { booleanParamSchema, encodeFlag, filterAllSchema, filterable } from "./filters.schema.js";
4
- import { backendPreferred, compareTagOf, offchainOnly, onchainOnly, tolerance } from "./compare.schema.js";
5
8
  import { curatorNameSchema, curatorSchema } from "./curators.schema.js";
6
- import { amountSchema, assetTypeSchema, bpsSchema, chainIdSchema, leverageSchema, timestampSchema, tokenAmountSchema, tokenSchema, txCallSchema, underlyingTokenSchema } from "./primitives.schema.js";
7
9
  import { delayedReceivedAssetSchema, instantReceivedAssetSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionSchema, receivedAssetSchema } from "./liquidations.schema.js";
8
10
  import { apyBreakdownSchema, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pointRewardsSchema, pointsProgramSchema, poolOpportunityDetailSchema, poolOpportunityKeySchema, poolOpportunitySchema, priceFeedDataSchema, priceFeedSummarySchema, quotaAssetSchema, rateCurvePointSchema, rateCurveSchema, rewardsSchema, strategyOpportunityDetailSchema, strategyOpportunityKeySchema, strategyOpportunitySchema, tokenRewardsSchema } from "./opportunities.schema.js";
9
11
  import { borrowRateBreakdownSchema, pnlBreakdownSchema, pointsProgramPnLSchema, pointsRewardsPnLSchema, poolPositionKeySchema, poolPositionSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionKeySchema, positionKindSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionsTotalsSchema, rewardsPnLSchema, strategyPositionKeySchema, strategyPositionSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema } from "./positions.schema.js";
10
- import { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema } from "./analytics.schema.js";
11
- import { CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS } from "./charts.js";
12
- import { chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, poolOpportunityChartMetricSchema, poolPositionChartMetricSchema, strategyOpportunityChartMetricSchema, strategyPositionChartMetricSchema } from "./charts.schema.js";
12
+ import { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, analyticsChartQueryOptionsSchema, analyticsChartQueryParamsSchema, analyticsChartQuerySchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema } from "./analytics.schema.js";
13
13
  import "./curators.js";
14
14
  import "./delayed-intents.js";
15
15
  import "./errors.js";
@@ -25,4 +25,4 @@ import { chainFailedSchema, chainMetadataSchema, chainSucceededSchema, dataSourc
25
25
  import { isSDKError, safeValue, sdkErr, sdkOk } from "./result.js";
26
26
  import "./withdrawals.js";
27
27
  import { positionClaimableWithdrawalSchema, positionPendingWithdrawalSchema, positionWithdrawalsSchema, withdrawalOutputAmountSchema } from "./withdrawals.schema.js";
28
- export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, amountSchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, curatorNameSchema, curatorSchema, dataSourceSchema, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, instantReceivedAssetSchema, isFilterSet, isSDKError, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, quotaAssetSchema, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, safeValue, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, withdrawalOutputAmountSchema };
28
+ export { ANALYTICS_POSITIONS_DEFAULT_LIMIT, ANALYTICS_POSITIONS_MAX_LIMIT, CHART_METRIC_UNITS, CHART_RANGES, CHART_UNAVAILABLE_CODES, FILTER_ALL, POOL_OPPORTUNITY_CHART_METRICS, POOL_POSITION_CHART_METRICS, PROTOCOL_CHART_METRICS, STRATEGY_OPPORTUNITY_CHART_METRICS, STRATEGY_POSITION_CHART_METRICS, STRATEGY_POSITION_COLLATERAL_ERROR, amountSchema, analyticsChartQueryOptionsSchema, analyticsChartQueryParamsSchema, analyticsChartQuerySchema, analyticsPositionListOptionsSchema, analyticsPositionListQueryParamsSchema, analyticsPositionListQuerySchema, analyticsPositionPageSchema, analyticsPositionSchema, analyticsPositionSortFieldSchema, analyticsSortDirectionSchema, apyBreakdownSchema, asEstimated, assetTypeSchema, backendPreferred, booleanParamSchema, borrowRateBreakdownSchema, bpsSchema, chainFailedSchema, chainIdSchema, chainMetadataSchema, chainSucceededSchema, chartBundleSchemaFor, chartDenominationSchema, chartMetricSchema, chartQueryCodec, chartQueryParamsSchema, chartQuerySchema, chartRangeSchema, chartSeriesSchema, chartValueSchema, chartWindowSchema, compareTagOf, curatorNameSchema, curatorSchema, dataSourceSchema, delayedReceivedAssetSchema, encodeFlag, filterAllSchema, filterable, instantReceivedAssetSchema, isFilterSet, isSDKError, leverageSchema, liquidatableAccountFilterSchema, liquidatableAccountSchema, liquidationApprovalSchema, liquidationDetailsSchema, liquidationPositionId, liquidationPositionSchema, matchesLiquidatableAccountFilter, matchesOpportunityFilter, matchesPositionFilter, noticeKindSchema, noticeSchema, offchainOnly, onchainOnly, opportunityBaseSchema, opportunityDetailSchema, opportunityFilterQueryParamsSchema, opportunityFilterQuerySchema, opportunityFilterSchema, opportunityId, opportunityKeySchema, opportunityKindSchema, opportunitySchema, opportunityTotalsSchema, pnlBreakdownSchema, pointRewardsSchema, pointsProgramPnLSchema, pointsProgramSchema, pointsRewardsPnLSchema, poolOpportunityChartMetricSchema, poolOpportunityDetailSchema, poolOpportunityId, poolOpportunityKeySchema, poolOpportunitySchema, poolPositionChartMetricSchema, poolPositionId, poolPositionKeySchema, poolPositionSchema, positionClaimableWithdrawalSchema, positionCollateralSchema, positionFilterQueryParamsSchema, positionFilterQuerySchema, positionFilterSchema, positionId, positionKeySchema, positionKindSchema, positionPendingWithdrawalSchema, positionSchema, positionTransactionKindSchema, positionTransactionSchema, positionWithdrawalsSchema, positionsTotalsSchema, priceFeedDataSchema, priceFeedSummarySchema, protocolChartMetricSchema, quotaAssetSchema, rateCurvePointSchema, rateCurveSchema, receivedAssetSchema, responseMetadataSchema, responseSchema, rewardsPnLSchema, rewardsSchema, safeValue, sdkErr, sdkOk, strategyOpportunityChartMetricSchema, strategyOpportunityDetailSchema, strategyOpportunityId, strategyOpportunityKeySchema, strategyOpportunitySchema, strategyPositionChartMetricSchema, strategyPositionId, strategyPositionKeySchema, strategyPositionSchema, timestampSchema, tokenAmountSchema, tokenQuotaRateSchema, tokenRewardsPnLSchema, tokenRewardsSchema, tokenSchema, tolerance, txCallSchema, underlyingTokenSchema, withdrawalOutputAmountSchema };
@@ -1,7 +1,7 @@
1
1
  import { ZodAddress } from "../onchain/utils/zod.js";
2
+ import { assetTypeSchema, bpsSchema, chainIdSchema, timestampSchema, tokenAmountSchema, tokenSchema, txCallSchema, underlyingTokenSchema } from "./primitives.schema.js";
2
3
  import { filterable } from "./filters.schema.js";
3
4
  import { curatorSchema } from "./curators.schema.js";
4
- import { assetTypeSchema, bpsSchema, chainIdSchema, timestampSchema, tokenAmountSchema, tokenSchema, txCallSchema, underlyingTokenSchema } from "./primitives.schema.js";
5
5
  import { z } from "zod/v4";
6
6
  //#region src/model/liquidations.schema.ts
7
7
  /**
@@ -1,9 +1,9 @@
1
1
  import { ZodAddress } from "../onchain/utils/zod.js";
2
+ import { offchainOnly, tolerance } from "./compare.schema.js";
3
+ import { amountSchema, assetTypeSchema, bpsSchema, chainIdSchema, leverageSchema, timestampSchema, tokenSchema, underlyingTokenSchema } from "./primitives.schema.js";
2
4
  import { isFilterSet } from "./filters.js";
3
5
  import { booleanParamSchema, encodeFlag, filterable } from "./filters.schema.js";
4
- import { offchainOnly, tolerance } from "./compare.schema.js";
5
6
  import { curatorSchema } from "./curators.schema.js";
6
- import { amountSchema, assetTypeSchema, bpsSchema, chainIdSchema, leverageSchema, timestampSchema, tokenSchema, underlyingTokenSchema } from "./primitives.schema.js";
7
7
  import { z } from "zod/v4";
8
8
  //#region src/model/opportunities.schema.ts
9
9
  /**
@@ -1,8 +1,8 @@
1
1
  import { ZodAddress, ZodBigInt, ZodHex } from "../onchain/utils/zod.js";
2
- import { isFilterSet } from "./filters.js";
3
- import { booleanParamSchema, encodeFlag, filterable } from "./filters.schema.js";
4
2
  import { backendPreferred, offchainOnly, onchainOnly, tolerance } from "./compare.schema.js";
5
3
  import { assetTypeSchema, bpsSchema, chainIdSchema, leverageSchema, timestampSchema, tokenAmountSchema, tokenSchema, underlyingTokenSchema } from "./primitives.schema.js";
4
+ import { isFilterSet } from "./filters.js";
5
+ import { booleanParamSchema, encodeFlag, filterable } from "./filters.schema.js";
6
6
  import { delayedReceivedAssetSchema, liquidationPositionSchema } from "./liquidations.schema.js";
7
7
  import { apyBreakdownSchema, pointsProgramSchema } from "./opportunities.schema.js";
8
8
  import { z } from "zod/v4";
@@ -1,11 +1,34 @@
1
+ import { chartBundleSchemaFor } from "../../model/charts.schema.js";
2
+ import { analyticsChartQuerySchema } from "../../model/analytics.schema.js";
3
+ import { AbstractOffchainNamespace } from "../AbstractOffchainNamespace.js";
1
4
  import { OffchainAnalyticsPositions } from "./OffchainAnalyticsPositions.js";
5
+ import { z } from "zod/v4";
2
6
  //#region src/offchain/analytics/OffchainAnalytics.ts
3
- /** Backend-only protocol analytics, grouped by subject. */
4
- var OffchainAnalytics = class {
7
+ /**
8
+ * Backend-only protocol analytics, grouped by subject.
9
+ *
10
+ * It owns the protocol-wide charts itself rather than through a sub-namespace:
11
+ * their subject is Gearbox as a whole, so there is nothing narrower for them to
12
+ * hang off.
13
+ **/
14
+ var OffchainAnalytics = class extends AbstractOffchainNamespace {
5
15
  positions;
6
16
  constructor(options) {
17
+ super("OffchainAnalytics", options);
7
18
  this.positions = new OffchainAnalyticsPositions(options);
8
19
  }
20
+ /** {@inheritDoc IOffchainAnalytics.getCharts} */
21
+ async getCharts(metrics, range, filter) {
22
+ return this.get({
23
+ path: "/v2/analytics/charts",
24
+ query: z.encode(analyticsChartQuerySchema, {
25
+ metrics,
26
+ range,
27
+ chainIds: this.scopedChainIds(filter)
28
+ }),
29
+ schema: chartBundleSchemaFor(metrics, range)
30
+ });
31
+ }
9
32
  };
10
33
  //#endregion
11
34
  export { OffchainAnalytics };
@@ -1,5 +1,3 @@
1
- import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
2
- import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
3
1
  import { AP_REWARDS_COMPRESSOR } from "../constants/address-provider.js";
4
2
  import { ADDRESS_0X0 } from "../constants/addresses.js";
5
3
  import { MAX_UINT256 } from "../constants/math.js";
@@ -10,6 +8,8 @@ import "../base/index.js";
10
8
  import { AccountBotsService } from "./bots/AccountBotsService.js";
11
9
  import "./bots/index.js";
12
10
  import { rewardsCompressorAbi } from "../../abi/compressors/rewardsCompressor.js";
11
+ import { iBaseRewardPoolAbi } from "../../abi/iBaseRewardPool.js";
12
+ import { ierc4626AdapterAbi } from "../../abi/ierc4626Adapter.js";
13
13
  import { expectedBalanceDeltas } from "../market/credit/expectedBalanceDeltas.js";
14
14
  import "../market/index.js";
15
15
  import { CreditAccountCompressor } from "./credit-account-compressor/CreditAccountCompressor.js";
@@ -1,4 +1,3 @@
1
- import { iLiquidationCompressorV313Abi } from "../../../abi/ILiquidationCompressorV313.js";
2
1
  import { AddressSet } from "../../utils/AddressSet.js";
3
2
  import { bytes32ToString } from "../../utils/bytes32ToString.js";
4
3
  import { ADDRESS_0X0 } from "../../constants/addresses.js";
@@ -20,6 +19,7 @@ import { SecuritizeLiquidatorContract } from "../../market/rwa/securitize/Securi
20
19
  import "../../market/rwa/securitize/index.js";
21
20
  import "../../market/index.js";
22
21
  import { LIQUIDATION_APPROVAL_BUFFER, LIQUIDATION_COMPRESSOR_V313_ADDRESS } from "./constants.js";
22
+ import { iLiquidationCompressorV313Abi } from "../../../abi/ILiquidationCompressorV313.js";
23
23
  import { skipLiquidatableAccount } from "./skipLiquidatableAccount.js";
24
24
  //#region src/onchain/accounts/liquidations/LiquidationsService.ts
25
25
  /**