@moonwell-fi/moonwell-sdk 0.23.0 → 0.25.0

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 (199) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/_cjs/actions/axiosWithRetry.js +10 -11
  3. package/_cjs/actions/axiosWithRetry.js.map +1 -1
  4. package/_cjs/actions/core/getUserBalances.js +63 -32
  5. package/_cjs/actions/core/getUserBalances.js.map +1 -1
  6. package/_cjs/actions/core/markets/common.js +31 -42
  7. package/_cjs/actions/core/markets/common.js.map +1 -1
  8. package/_cjs/actions/core/markets/getMarkets.js +7 -3
  9. package/_cjs/actions/core/markets/getMarkets.js.map +1 -1
  10. package/_cjs/actions/core/user-positions/common.js +56 -60
  11. package/_cjs/actions/core/user-positions/common.js.map +1 -1
  12. package/_cjs/actions/core/user-positions/getUserPositions.js +9 -6
  13. package/_cjs/actions/core/user-positions/getUserPositions.js.map +1 -1
  14. package/_cjs/actions/governance/getStakingInfo.js +1 -7
  15. package/_cjs/actions/governance/getStakingInfo.js.map +1 -1
  16. package/_cjs/actions/governance/getUserStakingInfo.js +1 -7
  17. package/_cjs/actions/governance/getUserStakingInfo.js.map +1 -1
  18. package/_cjs/actions/governance/getWellPrice.js +51 -1
  19. package/_cjs/actions/governance/getWellPrice.js.map +1 -1
  20. package/_cjs/actions/governance/proposals/common.js +34 -15
  21. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  22. package/_cjs/actions/governance/proposals/getProposals.js +5 -4
  23. package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
  24. package/_cjs/actions/index.js +3 -1
  25. package/_cjs/actions/index.js.map +1 -1
  26. package/_cjs/actions/morpho/markets/common.js +155 -26
  27. package/_cjs/actions/morpho/markets/common.js.map +1 -1
  28. package/_cjs/actions/morpho/markets/getMorphoMarket.js +1 -0
  29. package/_cjs/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  30. package/_cjs/actions/morpho/markets/getMorphoMarkets.js +1 -0
  31. package/_cjs/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  32. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +46 -0
  33. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  34. package/_cjs/actions/morpho/user-positions/common.js +26 -24
  35. package/_cjs/actions/morpho/user-positions/common.js.map +1 -1
  36. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js +7 -8
  37. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  38. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js +7 -8
  39. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  40. package/_cjs/actions/morpho/user-rewards/common.js +1 -7
  41. package/_cjs/actions/morpho/user-rewards/common.js.map +1 -1
  42. package/_cjs/actions/morpho/vaults/common.js +104 -87
  43. package/_cjs/actions/morpho/vaults/common.js.map +1 -1
  44. package/_cjs/actions/morpho/vaults/lunarIndexerTransform.js +31 -3
  45. package/_cjs/actions/morpho/vaults/lunarIndexerTransform.js.map +1 -1
  46. package/_cjs/actions/retry.js +43 -13
  47. package/_cjs/actions/retry.js.map +1 -1
  48. package/_cjs/client/createActions.js +2 -0
  49. package/_cjs/client/createActions.js.map +1 -1
  50. package/_cjs/common/error.js +37 -1
  51. package/_cjs/common/error.js.map +1 -1
  52. package/_cjs/common/index.js +2 -1
  53. package/_cjs/common/index.js.map +1 -1
  54. package/_cjs/common/readAcrossEnvironments.js +17 -0
  55. package/_cjs/common/readAcrossEnvironments.js.map +1 -0
  56. package/_cjs/environments/types/config.js.map +1 -1
  57. package/_cjs/errors/version.js +1 -1
  58. package/_cjs/index.js +3 -1
  59. package/_cjs/index.js.map +1 -1
  60. package/_esm/actions/axiosWithRetry.js +11 -13
  61. package/_esm/actions/axiosWithRetry.js.map +1 -1
  62. package/_esm/actions/core/getUserBalances.js +72 -35
  63. package/_esm/actions/core/getUserBalances.js.map +1 -1
  64. package/_esm/actions/core/markets/common.js +36 -43
  65. package/_esm/actions/core/markets/common.js.map +1 -1
  66. package/_esm/actions/core/markets/getMarkets.js +7 -3
  67. package/_esm/actions/core/markets/getMarkets.js.map +1 -1
  68. package/_esm/actions/core/user-positions/common.js +65 -63
  69. package/_esm/actions/core/user-positions/common.js.map +1 -1
  70. package/_esm/actions/core/user-positions/getUserPositions.js +14 -6
  71. package/_esm/actions/core/user-positions/getUserPositions.js.map +1 -1
  72. package/_esm/actions/governance/getStakingInfo.js +2 -8
  73. package/_esm/actions/governance/getStakingInfo.js.map +1 -1
  74. package/_esm/actions/governance/getUserStakingInfo.js +2 -8
  75. package/_esm/actions/governance/getUserStakingInfo.js.map +1 -1
  76. package/_esm/actions/governance/getWellPrice.js +67 -7
  77. package/_esm/actions/governance/getWellPrice.js.map +1 -1
  78. package/_esm/actions/governance/proposals/common.js +37 -12
  79. package/_esm/actions/governance/proposals/common.js.map +1 -1
  80. package/_esm/actions/governance/proposals/getProposals.js +7 -5
  81. package/_esm/actions/governance/proposals/getProposals.js.map +1 -1
  82. package/_esm/actions/index.js +1 -0
  83. package/_esm/actions/index.js.map +1 -1
  84. package/_esm/actions/morpho/markets/common.js +168 -27
  85. package/_esm/actions/morpho/markets/common.js.map +1 -1
  86. package/_esm/actions/morpho/markets/getMorphoMarket.js +1 -0
  87. package/_esm/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  88. package/_esm/actions/morpho/markets/getMorphoMarkets.js +1 -0
  89. package/_esm/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  90. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +48 -0
  91. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  92. package/_esm/actions/morpho/user-positions/common.js +31 -24
  93. package/_esm/actions/morpho/user-positions/common.js.map +1 -1
  94. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js +12 -8
  95. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  96. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js +12 -8
  97. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  98. package/_esm/actions/morpho/user-rewards/common.js +2 -8
  99. package/_esm/actions/morpho/user-rewards/common.js.map +1 -1
  100. package/_esm/actions/morpho/vaults/common.js +110 -91
  101. package/_esm/actions/morpho/vaults/common.js.map +1 -1
  102. package/_esm/actions/morpho/vaults/lunarIndexerTransform.js +36 -4
  103. package/_esm/actions/morpho/vaults/lunarIndexerTransform.js.map +1 -1
  104. package/_esm/actions/retry.js +45 -15
  105. package/_esm/actions/retry.js.map +1 -1
  106. package/_esm/client/createActions.js +2 -0
  107. package/_esm/client/createActions.js.map +1 -1
  108. package/_esm/common/error.js +49 -0
  109. package/_esm/common/error.js.map +1 -1
  110. package/_esm/common/index.js +1 -1
  111. package/_esm/common/index.js.map +1 -1
  112. package/_esm/common/readAcrossEnvironments.js +30 -0
  113. package/_esm/common/readAcrossEnvironments.js.map +1 -0
  114. package/_esm/environments/types/config.js.map +1 -1
  115. package/_esm/errors/version.js +1 -1
  116. package/_esm/index.js +1 -0
  117. package/_esm/index.js.map +1 -1
  118. package/_types/actions/axiosWithRetry.d.ts +1 -0
  119. package/_types/actions/axiosWithRetry.d.ts.map +1 -1
  120. package/_types/actions/core/getUserBalances.d.ts.map +1 -1
  121. package/_types/actions/core/markets/common.d.ts.map +1 -1
  122. package/_types/actions/core/markets/getMarkets.d.ts.map +1 -1
  123. package/_types/actions/core/user-positions/common.d.ts.map +1 -1
  124. package/_types/actions/core/user-positions/getUserPositions.d.ts +5 -0
  125. package/_types/actions/core/user-positions/getUserPositions.d.ts.map +1 -1
  126. package/_types/actions/governance/getStakingInfo.d.ts.map +1 -1
  127. package/_types/actions/governance/getUserStakingInfo.d.ts.map +1 -1
  128. package/_types/actions/governance/getWellPrice.d.ts +9 -1
  129. package/_types/actions/governance/getWellPrice.d.ts.map +1 -1
  130. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  131. package/_types/actions/governance/proposals/getProposals.d.ts +10 -1
  132. package/_types/actions/governance/proposals/getProposals.d.ts.map +1 -1
  133. package/_types/actions/index.d.ts +1 -0
  134. package/_types/actions/index.d.ts.map +1 -1
  135. package/_types/actions/morpho/markets/common.d.ts +7 -10
  136. package/_types/actions/morpho/markets/common.d.ts.map +1 -1
  137. package/_types/actions/morpho/markets/getMorphoMarket.d.ts +2 -0
  138. package/_types/actions/morpho/markets/getMorphoMarket.d.ts.map +1 -1
  139. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts +2 -0
  140. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts.map +1 -1
  141. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts +17 -0
  142. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts.map +1 -0
  143. package/_types/actions/morpho/user-positions/common.d.ts.map +1 -1
  144. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts +5 -0
  145. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts.map +1 -1
  146. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts +5 -0
  147. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts.map +1 -1
  148. package/_types/actions/morpho/user-rewards/common.d.ts.map +1 -1
  149. package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
  150. package/_types/actions/morpho/vaults/lunarIndexerTransform.d.ts.map +1 -1
  151. package/_types/actions/retry.d.ts +5 -4
  152. package/_types/actions/retry.d.ts.map +1 -1
  153. package/_types/client/createActions.d.ts +2 -0
  154. package/_types/client/createActions.d.ts.map +1 -1
  155. package/_types/common/error.d.ts +31 -0
  156. package/_types/common/error.d.ts.map +1 -1
  157. package/_types/common/index.d.ts +2 -2
  158. package/_types/common/index.d.ts.map +1 -1
  159. package/_types/common/readAcrossEnvironments.d.ts +23 -0
  160. package/_types/common/readAcrossEnvironments.d.ts.map +1 -0
  161. package/_types/environments/types/config.d.ts +11 -1
  162. package/_types/environments/types/config.d.ts.map +1 -1
  163. package/_types/errors/version.d.ts +1 -1
  164. package/_types/index.d.ts +3 -1
  165. package/_types/index.d.ts.map +1 -1
  166. package/_types/types/morphoMarket.d.ts +9 -0
  167. package/_types/types/morphoMarket.d.ts.map +1 -1
  168. package/actions/axiosWithRetry.ts +19 -13
  169. package/actions/core/getUserBalances.ts +98 -51
  170. package/actions/core/markets/common.ts +49 -51
  171. package/actions/core/markets/getMarkets.ts +9 -5
  172. package/actions/core/user-positions/common.ts +107 -111
  173. package/actions/core/user-positions/getUserPositions.ts +11 -10
  174. package/actions/governance/getStakingInfo.ts +2 -9
  175. package/actions/governance/getUserStakingInfo.ts +2 -8
  176. package/actions/governance/getWellPrice.ts +99 -7
  177. package/actions/governance/proposals/common.ts +44 -19
  178. package/actions/governance/proposals/getProposals.ts +22 -5
  179. package/actions/index.ts +5 -0
  180. package/actions/morpho/markets/common.ts +324 -125
  181. package/actions/morpho/markets/getMorphoMarket.ts +3 -0
  182. package/actions/morpho/markets/getMorphoMarkets.ts +3 -0
  183. package/actions/morpho/markets/getMorphoMarketsSharedLiquidity.ts +93 -0
  184. package/actions/morpho/user-positions/common.ts +48 -42
  185. package/actions/morpho/user-positions/getMorphoMarketUserPositions.ts +14 -15
  186. package/actions/morpho/user-positions/getMorphoVaultUserPositions.ts +14 -15
  187. package/actions/morpho/user-rewards/common.ts +2 -8
  188. package/actions/morpho/vaults/common.ts +161 -127
  189. package/actions/morpho/vaults/lunarIndexerTransform.ts +41 -6
  190. package/actions/retry.ts +53 -18
  191. package/client/createActions.ts +13 -0
  192. package/common/error.ts +45 -0
  193. package/common/index.ts +2 -2
  194. package/common/readAcrossEnvironments.ts +45 -0
  195. package/environments/types/config.ts +11 -1
  196. package/errors/version.ts +1 -1
  197. package/index.ts +3 -0
  198. package/package.json +1 -1
  199. package/types/morphoMarket.ts +10 -0
@@ -6,7 +6,7 @@ import type { OptionalNetworkParameterType } from "../../common/types.js";
6
6
  import type { Environment } from "../../environments/index.js";
7
7
  import type { UserStakingInfo } from "../../types/staking.js";
8
8
  import { getMerklCampaignIds, getMerklRewardsData } from "./common.js";
9
- import { getGovernanceTokenPriceFor } from "./getWellPrice.js";
9
+ import { getGovernanceTokenPriceOrZero } from "./getWellPrice.js";
10
10
 
11
11
  export type GetUserStakingInfoParameters<
12
12
  environments,
@@ -150,7 +150,7 @@ export async function getUserStakingInfo<
150
150
  environment.contracts.views?.read.getUserStakingInfo([userAddress]),
151
151
  environment.contracts.governanceToken?.read.balanceOf([userAddress]),
152
152
  environment.contracts.views?.read.getStakingInfo(),
153
- getGovernanceTokenPriceFor(environment, baseEnvironment),
153
+ getGovernanceTokenPriceOrZero(environment, baseEnvironment),
154
154
  ]);
155
155
 
156
156
  const [userStakingR, balanceR, stakingScheduleR, priceR] = settled;
@@ -175,12 +175,6 @@ export async function getUserStakingInfo<
175
175
  : 0n;
176
176
 
177
177
  const price = priceR.status === "fulfilled" ? priceR.value : 0n;
178
- if (priceR.status === "rejected") {
179
- environment.onError?.(priceR.reason, {
180
- source: "governance-token-price",
181
- chainId: environment.chainId,
182
- });
183
- }
184
178
 
185
179
  return { userStaking, schedule, tokenBalance, price };
186
180
  }),
@@ -41,6 +41,71 @@ export async function getWellPriceFromBaseOracle(
41
41
  return await oracle.read.getUnderlyingPrice([mWELL]);
42
42
  }
43
43
 
44
+ async function readGovernanceTokenPrice(
45
+ environment: Environment,
46
+ baseEnvironment?: Environment,
47
+ ): Promise<bigint> {
48
+ if (environment.custom?.governance?.token === "WELL") {
49
+ return getWellPriceFromBaseOracle(baseEnvironment);
50
+ }
51
+ // Non-WELL (e.g. Moonriver / MFAM): the env itself is the governance "home".
52
+ const views = environment.contracts.views;
53
+ if (!views) return 0n;
54
+ return (await views.read.getGovernanceTokenPrice()) ?? 0n;
55
+ }
56
+
57
+ const GOVERNANCE_TOKEN_PRICE_TTL_MS = 10_000;
58
+
59
+ type OnErrorCallback = NonNullable<Environment["onError"]>;
60
+
61
+ type GovernanceTokenPriceEntry = {
62
+ promise: Promise<bigint>;
63
+ expiresAt: number;
64
+ requestingChainIds: Set<number>;
65
+ /** Callbacks already told about this read's failure. */
66
+ reportedTo: Set<OnErrorCallback>;
67
+ };
68
+
69
+ // Keyed by the environment the price is read through (the Base env for every
70
+ // WELL chain), so markets, vaults, rewards and staking reads issued together
71
+ // share one request, while clients with their own RPCs never share results.
72
+ const governanceTokenPriceCache = new WeakMap<
73
+ Environment,
74
+ GovernanceTokenPriceEntry
75
+ >();
76
+
77
+ function getSharedGovernanceTokenPrice(
78
+ environment: Environment,
79
+ baseEnvironment?: Environment,
80
+ ): { sourceChainId: number; entry: GovernanceTokenPriceEntry } {
81
+ const sourceEnvironment: Environment =
82
+ environment.custom?.governance?.token === "WELL"
83
+ ? (baseEnvironment ?? publicEnvironments.base)
84
+ : environment;
85
+ const sourceChainId = sourceEnvironment.chainId;
86
+
87
+ const cached = governanceTokenPriceCache.get(sourceEnvironment);
88
+ if (cached && Date.now() < cached.expiresAt) {
89
+ cached.requestingChainIds.add(environment.chainId);
90
+ return { sourceChainId, entry: cached };
91
+ }
92
+
93
+ const entry: GovernanceTokenPriceEntry = {
94
+ promise: readGovernanceTokenPrice(environment, baseEnvironment),
95
+ expiresAt: Date.now() + GOVERNANCE_TOKEN_PRICE_TTL_MS,
96
+ requestingChainIds: new Set([environment.chainId]),
97
+ reportedTo: new Set(),
98
+ };
99
+ governanceTokenPriceCache.set(sourceEnvironment, entry);
100
+ // Failures are never cached: evict so the next call reads again.
101
+ entry.promise.catch(() => {
102
+ if (governanceTokenPriceCache.get(sourceEnvironment) === entry) {
103
+ governanceTokenPriceCache.delete(sourceEnvironment);
104
+ }
105
+ });
106
+ return { sourceChainId, entry };
107
+ }
108
+
44
109
  /**
45
110
  * Returns the governance-token-in-USD price for an environment.
46
111
  *
@@ -50,17 +115,44 @@ export async function getWellPriceFromBaseOracle(
50
115
  * env's own views.getGovernanceTokenPrice() — Moonriver has its own MFAM
51
116
  * oracle and isn't priced from Base.
52
117
  *
53
- * Returns 0n if the lookup fails.
118
+ * Concurrent calls for the same price source share one in-flight read, and a
119
+ * successful price is reused for a few seconds. Rejects if the read fails.
54
120
  */
55
121
  export async function getGovernanceTokenPriceFor(
56
122
  environment: Environment,
57
123
  baseEnvironment?: Environment,
58
124
  ): Promise<bigint> {
59
- if (environment.custom?.governance?.token === "WELL") {
60
- return getWellPriceFromBaseOracle(baseEnvironment);
125
+ return getSharedGovernanceTokenPrice(environment, baseEnvironment).entry
126
+ .promise;
127
+ }
128
+
129
+ /**
130
+ * Same shared read as `getGovernanceTokenPriceFor`, but resolves to 0n on
131
+ * failure. A failed shared read is reported once per `onError` callback,
132
+ * however many callers using that callback were waiting on it; `items` lists
133
+ * the requesting chainIds.
134
+ */
135
+ export async function getGovernanceTokenPriceOrZero(
136
+ environment: Environment,
137
+ baseEnvironment?: Environment,
138
+ ): Promise<bigint> {
139
+ const { sourceChainId, entry } = getSharedGovernanceTokenPrice(
140
+ environment,
141
+ baseEnvironment,
142
+ );
143
+ try {
144
+ return await entry.promise;
145
+ } catch (error) {
146
+ const onError = environment.onError;
147
+ if (onError && !entry.reportedTo.has(onError)) {
148
+ entry.reportedTo.add(onError);
149
+ environment.onError?.(error, {
150
+ source: "governance-token-price",
151
+ chainId: sourceChainId,
152
+ operation: "governance-token-price-read",
153
+ items: [...entry.requestingChainIds].map(String),
154
+ });
155
+ }
156
+ return 0n;
61
157
  }
62
- // Non-WELL (e.g. Moonriver / MFAM): the env itself is the governance "home".
63
- const views = environment.contracts.views;
64
- if (!views) return 0n;
65
- return (await views.read.getGovernanceTokenPrice()) ?? 0n;
66
158
  }
@@ -1,4 +1,3 @@
1
- import axios from "axios";
2
1
  import { mainnet } from "viem/chains";
3
2
  import { Amount } from "../../../common/index.js";
4
3
  import type { Environment } from "../../../environments/index.js";
@@ -23,8 +22,6 @@ const MULTICHAIN_WORMHOLE_BRIDGES: ReadonlySet<string> = new Set([
23
22
  "0x98f3c9e6e3face36baad05fe09d375ef1464288b", // Ethereum
24
23
  ]);
25
24
 
26
- axios.defaults.timeout = 5_000;
27
-
28
25
  /**
29
26
  * Extract proposal subtitle from description
30
27
  */
@@ -450,6 +447,29 @@ export const getProposalsOnChainData = async (
450
447
  ? governanceEnvironment
451
448
  : getEnvironmentByChainId(chainId);
452
449
 
450
+ // viem batches these reads into one multicall, so a single failed request
451
+ // rejects every read in it. Collect failures per chain and report them once
452
+ // after the batch instead of once per read (Sentry MOONWELL-FRONTEND-1AX).
453
+ const readFailures = new Map<
454
+ number,
455
+ { error: unknown; failed: number; total: number; proposalIds: Set<string> }
456
+ >();
457
+ const recordRead = (chainId: number, proposalId: number, error?: unknown) => {
458
+ const entry = readFailures.get(chainId) ?? {
459
+ error: undefined,
460
+ failed: 0,
461
+ total: 0,
462
+ proposalIds: new Set<string>(),
463
+ };
464
+ entry.total++;
465
+ if (error !== undefined) {
466
+ entry.error ??= error;
467
+ entry.failed++;
468
+ entry.proposalIds.add(String(proposalId));
469
+ }
470
+ readFailures.set(chainId, entry);
471
+ };
472
+
453
473
  const onChainDataList = await Promise.all(
454
474
  apiProposals.map(async (p) => {
455
475
  const isLocal = p.chainId === governanceEnvironment.chainId;
@@ -504,29 +524,17 @@ export const getProposalsOnChainData = async (
504
524
  ]);
505
525
  if (stateResult.status === "fulfilled") {
506
526
  state = Number(stateResult.value);
527
+ recordRead(p.chainId, p.proposalId);
507
528
  } else {
508
529
  stateReadFailed = true;
509
- console.warn(
510
- `Failed to fetch state for proposal ${p.proposalId} (chainId=${p.chainId}):`,
511
- stateResult.reason,
512
- );
513
- governanceEnvironment.onError?.(stateResult.reason, {
514
- source: "governance-proposals",
515
- chainId: p.chainId,
516
- });
530
+ recordRead(p.chainId, p.proposalId, stateResult.reason);
517
531
  }
518
532
  if (proposalsResult.status === "fulfilled") {
519
533
  proposalData = proposalsResult.value ?? null;
534
+ recordRead(p.chainId, p.proposalId);
520
535
  } else {
521
536
  proposalsReadFailed = true;
522
- console.warn(
523
- `Failed to fetch proposalData for proposal ${p.proposalId} (chainId=${p.chainId}):`,
524
- proposalsResult.reason,
525
- );
526
- governanceEnvironment.onError?.(proposalsResult.reason, {
527
- source: "governance-proposals",
528
- chainId: p.chainId,
529
- });
537
+ recordRead(p.chainId, p.proposalId, proposalsResult.reason);
530
538
  }
531
539
  }
532
540
 
@@ -612,6 +620,23 @@ export const getProposalsOnChainData = async (
612
620
  }),
613
621
  );
614
622
 
623
+ for (const [chainId, entry] of readFailures) {
624
+ if (entry.failed === 0) continue;
625
+ const proposalIds = [...entry.proposalIds];
626
+ console.warn(
627
+ `Failed ${entry.failed}/${entry.total} governor reads (chainId=${chainId}, proposals ${proposalIds.join(", ")}):`,
628
+ entry.error,
629
+ );
630
+ governanceEnvironment.onError?.(entry.error, {
631
+ source: "governance-proposals",
632
+ chainId,
633
+ operation: "proposal-onchain-read",
634
+ failedCount: entry.failed,
635
+ totalCount: entry.total,
636
+ items: proposalIds,
637
+ });
638
+ }
639
+
615
640
  return onChainDataList;
616
641
  };
617
642
 
@@ -20,7 +20,16 @@ import {
20
20
  export type GetProposalsParameters<
21
21
  environments,
22
22
  network extends Chain | undefined,
23
- > = OptionalNetworkParameterType<environments, network>;
23
+ > = OptionalNetworkParameterType<environments, network> & {
24
+ /**
25
+ * Governance chains to fetch proposals from: 1 (Ethereum, active),
26
+ * 1284 (Moonbeam archive) and/or 1285 (Moonriver archive). Defaults to all
27
+ * of them. The archives hold almost all of the payload (~6.6MB of ~7MB), so
28
+ * views that only show recent proposals can pass `[1]` and load the archives
29
+ * separately when needed. Unsupported chainIds are ignored.
30
+ */
31
+ proposalChainIds?: readonly number[];
32
+ };
24
33
 
25
34
  export type GetProposalsReturnType = Promise<Proposal[]>;
26
35
 
@@ -42,7 +51,10 @@ export async function getProposals<
42
51
  return [];
43
52
  }
44
53
 
45
- const proposals = await fetchGovernorProposals(governanceEnvironment);
54
+ const proposals = await fetchGovernorProposals(
55
+ governanceEnvironment,
56
+ args?.proposalChainIds,
57
+ );
46
58
  // Newer multigov-ethereum proposals (chainId=1) and historical Moonbeam
47
59
  // proposals (chainId=1284) restart their proposalId counters from 1, so IDs
48
60
  // may collide across chains. Sort by proposalId desc with chainId as a
@@ -58,7 +70,8 @@ export async function getProposals<
58
70
  }
59
71
 
60
72
  /**
61
- * Fetch every proposal the Governor API serves, across all governance chains.
73
+ * Fetch every proposal the Governor API serves, across all governance chains
74
+ * (or only `proposalChainIds`, when given).
62
75
  *
63
76
  * One indexer DO serves them all:
64
77
  * - chainId=1 (Ethereum) — the active multigov contract
@@ -76,16 +89,20 @@ export async function getProposals<
76
89
  */
77
90
  async function fetchGovernorProposals(
78
91
  governanceEnvironment: Environment,
92
+ proposalChainIds?: readonly number[],
79
93
  ): Promise<Proposal[]> {
94
+ const chainIds = SUPPORTED_GOVERNOR_CHAIN_IDS.filter(
95
+ (chainId) => !proposalChainIds || proposalChainIds.includes(chainId),
96
+ );
80
97
  const results = await Promise.allSettled(
81
- SUPPORTED_GOVERNOR_CHAIN_IDS.map((chainId) =>
98
+ chainIds.map((chainId) =>
82
99
  fetchAllProposals(governanceEnvironment, { chainId }),
83
100
  ),
84
101
  );
85
102
 
86
103
  const apiProposals: ApiProposal[] = [];
87
104
  results.forEach((result, index) => {
88
- const chainId = SUPPORTED_GOVERNOR_CHAIN_IDS[index];
105
+ const chainId = chainIds[index];
89
106
  if (result.status === "fulfilled") {
90
107
  apiProposals.push(...result.value);
91
108
  } else if (chainId !== undefined) {
package/actions/index.ts CHANGED
@@ -116,6 +116,11 @@ export {
116
116
  type GetMorphoMarketsParameters,
117
117
  type GetMorphoMarketsReturnType,
118
118
  } from "./morpho/markets/getMorphoMarkets.js";
119
+ export {
120
+ getMorphoMarketsSharedLiquidity,
121
+ type GetMorphoMarketsSharedLiquidityParameters,
122
+ type GetMorphoMarketsSharedLiquidityReturnType,
123
+ } from "./morpho/markets/getMorphoMarketsSharedLiquidity.js";
119
124
  export {
120
125
  getMarketSnapshots as getMorphoMarketSnapshots,
121
126
  type GetMarketSnapshotsParameters as GetMorphoMarketSnapshotsParameters,