@moonwell-fi/moonwell-sdk 0.11.0 → 0.12.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 (158) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/_cjs/actions/core/markets/common.js +26 -12
  3. package/_cjs/actions/core/markets/common.js.map +1 -1
  4. package/_cjs/actions/core/markets/getMarketSnapshots.js +173 -321
  5. package/_cjs/actions/core/markets/getMarketSnapshots.js.map +1 -1
  6. package/_cjs/actions/core/user-positions/getUserPositionSnapshots.js +31 -26
  7. package/_cjs/actions/core/user-positions/getUserPositionSnapshots.js.map +1 -1
  8. package/_cjs/actions/governance/getCirculatingSupplySnapshots.js +35 -29
  9. package/_cjs/actions/governance/getCirculatingSupplySnapshots.js.map +1 -1
  10. package/_cjs/actions/governance/getStakingSnapshots.js +16 -12
  11. package/_cjs/actions/governance/getStakingSnapshots.js.map +1 -1
  12. package/_cjs/actions/governance/proposals/common.js +247 -211
  13. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  14. package/_cjs/actions/morpho/markets/common.js +26 -29
  15. package/_cjs/actions/morpho/markets/common.js.map +1 -1
  16. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js +12 -69
  17. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js.map +1 -1
  18. package/_cjs/actions/morpho/vaults/common.js +7 -4
  19. package/_cjs/actions/morpho/vaults/common.js.map +1 -1
  20. package/_cjs/actions/morpho/vaults/getMorphoVaultSnapshots.js +21 -78
  21. package/_cjs/actions/morpho/vaults/getMorphoVaultSnapshots.js.map +1 -1
  22. package/_cjs/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js +13 -66
  23. package/_cjs/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js.map +1 -1
  24. package/_cjs/client/createMoonwellClient.js +9 -3
  25. package/_cjs/client/createMoonwellClient.js.map +1 -1
  26. package/_cjs/environments/definitions/arbitrum/environment.js +1 -2
  27. package/_cjs/environments/definitions/arbitrum/environment.js.map +1 -1
  28. package/_cjs/environments/definitions/avalanche/environment.js +1 -2
  29. package/_cjs/environments/definitions/avalanche/environment.js.map +1 -1
  30. package/_cjs/environments/definitions/base/custom.js +0 -1
  31. package/_cjs/environments/definitions/base/custom.js.map +1 -1
  32. package/_cjs/environments/definitions/base/environment.js +1 -2
  33. package/_cjs/environments/definitions/base/environment.js.map +1 -1
  34. package/_cjs/environments/definitions/ethereum/environment.js +1 -2
  35. package/_cjs/environments/definitions/ethereum/environment.js.map +1 -1
  36. package/_cjs/environments/definitions/moonbeam/environment.js +1 -2
  37. package/_cjs/environments/definitions/moonbeam/environment.js.map +1 -1
  38. package/_cjs/environments/definitions/optimism/custom.js +0 -1
  39. package/_cjs/environments/definitions/optimism/custom.js.map +1 -1
  40. package/_cjs/environments/definitions/optimism/environment.js +1 -2
  41. package/_cjs/environments/definitions/optimism/environment.js.map +1 -1
  42. package/_cjs/environments/definitions/polygon/environment.js +1 -2
  43. package/_cjs/environments/definitions/polygon/environment.js.map +1 -1
  44. package/_cjs/environments/index.js +8 -8
  45. package/_cjs/environments/index.js.map +1 -1
  46. package/_cjs/environments/types/config.js +1 -0
  47. package/_cjs/environments/types/config.js.map +1 -1
  48. package/_cjs/errors/version.js +1 -1
  49. package/_esm/actions/core/markets/common.js +26 -13
  50. package/_esm/actions/core/markets/common.js.map +1 -1
  51. package/_esm/actions/core/markets/getMarketSnapshots.js +194 -346
  52. package/_esm/actions/core/markets/getMarketSnapshots.js.map +1 -1
  53. package/_esm/actions/core/user-positions/getUserPositionSnapshots.js +32 -29
  54. package/_esm/actions/core/user-positions/getUserPositionSnapshots.js.map +1 -1
  55. package/_esm/actions/governance/getCirculatingSupplySnapshots.js +35 -30
  56. package/_esm/actions/governance/getCirculatingSupplySnapshots.js.map +1 -1
  57. package/_esm/actions/governance/getStakingSnapshots.js +17 -13
  58. package/_esm/actions/governance/getStakingSnapshots.js.map +1 -1
  59. package/_esm/actions/governance/proposals/common.js +246 -216
  60. package/_esm/actions/governance/proposals/common.js.map +1 -1
  61. package/_esm/actions/morpho/markets/common.js +27 -34
  62. package/_esm/actions/morpho/markets/common.js.map +1 -1
  63. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js +14 -68
  64. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js.map +1 -1
  65. package/_esm/actions/morpho/vaults/common.js +7 -4
  66. package/_esm/actions/morpho/vaults/common.js.map +1 -1
  67. package/_esm/actions/morpho/vaults/getMorphoVaultSnapshots.js +24 -78
  68. package/_esm/actions/morpho/vaults/getMorphoVaultSnapshots.js.map +1 -1
  69. package/_esm/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js +15 -65
  70. package/_esm/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js.map +1 -1
  71. package/_esm/client/createMoonwellClient.js +9 -3
  72. package/_esm/client/createMoonwellClient.js.map +1 -1
  73. package/_esm/environments/definitions/arbitrum/environment.js +1 -2
  74. package/_esm/environments/definitions/arbitrum/environment.js.map +1 -1
  75. package/_esm/environments/definitions/avalanche/environment.js +1 -2
  76. package/_esm/environments/definitions/avalanche/environment.js.map +1 -1
  77. package/_esm/environments/definitions/base/custom.js +0 -1
  78. package/_esm/environments/definitions/base/custom.js.map +1 -1
  79. package/_esm/environments/definitions/base/environment.js +1 -2
  80. package/_esm/environments/definitions/base/environment.js.map +1 -1
  81. package/_esm/environments/definitions/ethereum/environment.js +1 -2
  82. package/_esm/environments/definitions/ethereum/environment.js.map +1 -1
  83. package/_esm/environments/definitions/moonbeam/environment.js +1 -2
  84. package/_esm/environments/definitions/moonbeam/environment.js.map +1 -1
  85. package/_esm/environments/definitions/optimism/custom.js +0 -1
  86. package/_esm/environments/definitions/optimism/custom.js.map +1 -1
  87. package/_esm/environments/definitions/optimism/environment.js +1 -2
  88. package/_esm/environments/definitions/optimism/environment.js.map +1 -1
  89. package/_esm/environments/definitions/polygon/environment.js +1 -2
  90. package/_esm/environments/definitions/polygon/environment.js.map +1 -1
  91. package/_esm/environments/index.js +8 -8
  92. package/_esm/environments/index.js.map +1 -1
  93. package/_esm/environments/types/config.js +1 -0
  94. package/_esm/environments/types/config.js.map +1 -1
  95. package/_esm/errors/version.js +1 -1
  96. package/_types/actions/core/markets/common.d.ts.map +1 -1
  97. package/_types/actions/core/markets/getMarketSnapshots.d.ts.map +1 -1
  98. package/_types/actions/core/user-positions/getUserPositionSnapshots.d.ts +0 -1
  99. package/_types/actions/core/user-positions/getUserPositionSnapshots.d.ts.map +1 -1
  100. package/_types/actions/governance/getCirculatingSupplySnapshots.d.ts.map +1 -1
  101. package/_types/actions/governance/getStakingSnapshots.d.ts.map +1 -1
  102. package/_types/actions/governance/proposals/common.d.ts +2 -8
  103. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  104. package/_types/actions/morpho/markets/common.d.ts.map +1 -1
  105. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.d.ts.map +1 -1
  106. package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
  107. package/_types/actions/morpho/vaults/getMorphoVaultSnapshots.d.ts.map +1 -1
  108. package/_types/actions/morpho/vaults/getMorphoVaultStakingSnapshots.d.ts.map +1 -1
  109. package/_types/client/createMoonwellClient.d.ts +4 -4
  110. package/_types/client/createMoonwellClient.d.ts.map +1 -1
  111. package/_types/environments/definitions/arbitrum/environment.d.ts +1 -1
  112. package/_types/environments/definitions/arbitrum/environment.d.ts.map +1 -1
  113. package/_types/environments/definitions/avalanche/environment.d.ts +1 -1
  114. package/_types/environments/definitions/avalanche/environment.d.ts.map +1 -1
  115. package/_types/environments/definitions/base/custom.d.ts +0 -1
  116. package/_types/environments/definitions/base/custom.d.ts.map +1 -1
  117. package/_types/environments/definitions/base/environment.d.ts +1 -1
  118. package/_types/environments/definitions/base/environment.d.ts.map +1 -1
  119. package/_types/environments/definitions/ethereum/environment.d.ts +1 -1
  120. package/_types/environments/definitions/ethereum/environment.d.ts.map +1 -1
  121. package/_types/environments/definitions/moonbeam/environment.d.ts +1 -1
  122. package/_types/environments/definitions/moonbeam/environment.d.ts.map +1 -1
  123. package/_types/environments/definitions/optimism/custom.d.ts +0 -1
  124. package/_types/environments/definitions/optimism/custom.d.ts.map +1 -1
  125. package/_types/environments/definitions/optimism/environment.d.ts +1 -2
  126. package/_types/environments/definitions/optimism/environment.d.ts.map +1 -1
  127. package/_types/environments/definitions/polygon/environment.d.ts +1 -1
  128. package/_types/environments/definitions/polygon/environment.d.ts.map +1 -1
  129. package/_types/environments/index.d.ts +0 -3
  130. package/_types/environments/index.d.ts.map +1 -1
  131. package/_types/environments/types/config.d.ts +10 -3
  132. package/_types/environments/types/config.d.ts.map +1 -1
  133. package/_types/errors/version.d.ts +1 -1
  134. package/actions/core/markets/common.ts +33 -18
  135. package/actions/core/markets/getMarketSnapshots.ts +261 -511
  136. package/actions/core/user-positions/getUserPositionSnapshots.ts +44 -46
  137. package/actions/governance/getCirculatingSupplySnapshots.ts +43 -35
  138. package/actions/governance/getStakingSnapshots.ts +32 -29
  139. package/actions/governance/proposals/common.ts +369 -330
  140. package/actions/morpho/markets/common.ts +32 -43
  141. package/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.ts +20 -109
  142. package/actions/morpho/vaults/common.ts +7 -6
  143. package/actions/morpho/vaults/getMorphoVaultSnapshots.ts +36 -120
  144. package/actions/morpho/vaults/getMorphoVaultStakingSnapshots.ts +24 -111
  145. package/client/createMoonwellClient.ts +17 -5
  146. package/environments/definitions/arbitrum/environment.ts +0 -2
  147. package/environments/definitions/avalanche/environment.ts +0 -2
  148. package/environments/definitions/base/custom.ts +0 -1
  149. package/environments/definitions/base/environment.ts +0 -2
  150. package/environments/definitions/ethereum/environment.ts +0 -2
  151. package/environments/definitions/moonbeam/environment.ts +0 -2
  152. package/environments/definitions/optimism/custom.ts +0 -1
  153. package/environments/definitions/optimism/environment.ts +0 -2
  154. package/environments/definitions/polygon/environment.ts +0 -2
  155. package/environments/index.ts +6 -27
  156. package/environments/types/config.ts +11 -3
  157. package/errors/version.ts +1 -1
  158. package/package.json +1 -1
@@ -8,7 +8,6 @@ import type {
8
8
  PublicAllocatorSharedLiquidityType,
9
9
  } from "../../../types/morphoMarket.js";
10
10
  import type { MorphoReward } from "../../../types/morphoReward.js";
11
- import { shouldFallback } from "../../lunar-indexer-client.js";
12
11
  import { getGraphQL } from "../utils/graphql.js";
13
12
  import {
14
13
  type GetMorphoMarketsRewardsReturnType as LunarIndexerRewardsType,
@@ -829,7 +828,10 @@ async function getMorphoMarketsDataFromIndexer(params: {
829
828
  `Failed to fetch markets from Lunar Indexer for chain ${environment.chainId}, falling back to on-chain:`,
830
829
  error,
831
830
  );
832
- // Return rejection so we can fall back to on-chain for this environment
831
+ environment.onError?.(error, {
832
+ source: "morpho-markets",
833
+ chainId: environment.chainId,
834
+ });
833
835
  return Promise.reject({ environment, error });
834
836
  }
835
837
  }),
@@ -841,9 +843,9 @@ async function getMorphoMarketsDataFromIndexer(params: {
841
843
 
842
844
  // Collect environments that failed to fetch from indexer for fallback
843
845
  const failedEnvironments = marketsSettlements
844
- .filter((s) => s.status === "rejected")
845
- .map((s: any) => s.reason?.environment)
846
- .filter((env) => env !== undefined);
846
+ .filter((s): s is PromiseRejectedResult => s.status === "rejected")
847
+ .map((s) => (s.reason as { environment?: Environment }).environment)
848
+ .filter((env): env is Environment => env !== undefined);
847
849
 
848
850
  // Fall back to on-chain for environments where indexer failed
849
851
  let fallbackMarkets: MorphoMarket[] = [];
@@ -851,16 +853,27 @@ async function getMorphoMarketsDataFromIndexer(params: {
851
853
  console.warn(
852
854
  `Falling back to on-chain for ${failedEnvironments.length} environment(s)`,
853
855
  );
854
- fallbackMarkets = await getMorphoMarketsDataFromOnChain({
855
- environments: failedEnvironments,
856
- markets: params.markets,
857
- includeRewards: params.includeRewards,
858
- });
856
+ try {
857
+ fallbackMarkets = await getMorphoMarketsDataFromOnChain({
858
+ environments: failedEnvironments,
859
+ markets: params.markets,
860
+ includeRewards: params.includeRewards,
861
+ });
862
+ } catch (rpcError) {
863
+ console.warn(
864
+ `RPC fallback also failed for ${failedEnvironments.length} environment(s):`,
865
+ rpcError,
866
+ );
867
+ for (const env of failedEnvironments) {
868
+ env.onError?.(rpcError, {
869
+ source: "morpho-markets-rpc-fallback",
870
+ chainId: env.chainId,
871
+ });
872
+ }
873
+ }
859
874
  }
860
875
 
861
- // Fetch shared liquidity from lunar-indexer, tracking which environments
862
- // fell back so we can fill them from api.morpho.org after.
863
- const fallbackChainIds = new Set<number>();
876
+ // Fetch shared liquidity from lunar-indexer.
864
877
  const sharedLiquiditySettlements = await Promise.allSettled(
865
878
  fulfilledMarkets.map(async ({ environment, markets }) => {
866
879
  const lunarIndexerUrl = environment.lunarIndexerUrl;
@@ -903,12 +916,14 @@ async function getMorphoMarketsDataFromIndexer(params: {
903
916
  );
904
917
  return { environment, data };
905
918
  } catch (error) {
906
- if (!shouldFallback(error)) throw error;
907
- console.debug(
908
- "[Lunar fallback] Falling back to Morpho API for shared liquidity:",
919
+ console.warn(
920
+ `[getMorphoMarketsData] Lunar shared liquidity failed for chain ${environment.chainId}:`,
909
921
  error,
910
922
  );
911
- fallbackChainIds.add(environment.chainId);
923
+ environment.onError?.(error, {
924
+ source: "morpho-shared-liquidity",
925
+ chainId: environment.chainId,
926
+ });
912
927
  return {
913
928
  environment,
914
929
  data: [] as GetMorphoMarketsPublicAllocatorSharedLiquidityReturnType[],
@@ -963,32 +978,6 @@ async function getMorphoMarketsDataFromIndexer(params: {
963
978
  });
964
979
  });
965
980
 
966
- // Fallback: if the lunar shared-liquidity endpoint failed for some environments,
967
- // fetch publicAllocatorSharedLiquidity from the Morpho API for those environments only.
968
- if (fallbackChainIds.size > 0) {
969
- const fallbackMarketIds = fulfilledMarkets
970
- .filter(({ environment }) => fallbackChainIds.has(environment.chainId))
971
- .flatMap(({ environment, markets }) =>
972
- markets.map((m) => ({
973
- marketId: m.marketId,
974
- chainId: environment.chainId,
975
- })),
976
- );
977
- const rewardEnvironment =
978
- params.environments.find((env) => env.custom?.morpho?.apiUrl) ??
979
- params.environments[0];
980
- const morphoApiData = await getMorphoMarketRewards(
981
- rewardEnvironment,
982
- fallbackMarketIds,
983
- );
984
- morphoApiData.forEach((item) => {
985
- const key = `${item.chainId}-${item.marketId.toLowerCase()}`;
986
- if (!sharedLiquidityMap.has(key)) {
987
- sharedLiquidityMap.set(key, item.publicAllocatorSharedLiquidity);
988
- }
989
- });
990
- }
991
-
992
981
  // Overlay rewards from the indexer when requested
993
982
  if (params.includeRewards) {
994
983
  fulfilledMarkets.forEach(({ environment, markets }) => {
@@ -1,9 +1,6 @@
1
- import axios from "axios";
2
- import dayjs from "dayjs";
3
- import utc from "dayjs/plugin/utc.js";
4
1
  import type { Address } from "viem";
5
2
  import type { MoonwellClient } from "../../../client/createMoonwellClient.js";
6
- import { getEnvironmentFromArgs, isStartOfDay } from "../../../common/index.js";
3
+ import { getEnvironmentFromArgs } from "../../../common/index.js";
7
4
  import type { NetworkParameterType } from "../../../common/types.js";
8
5
  import type {
9
6
  Chain,
@@ -15,11 +12,8 @@ import type { MorphoVaultUserPositionSnapshot } from "../../../types/morphoUserP
15
12
  import {
16
13
  DEFAULT_LUNAR_TIMEOUT_MS,
17
14
  createLunarIndexerClient,
18
- shouldFallback,
19
15
  } from "../../lunar-indexer-client.js";
20
16
 
21
- dayjs.extend(utc);
22
-
23
17
  export type GetMorphoVaultUserPositionSnapshotsParameters<
24
18
  environments,
25
19
  network extends Chain | undefined,
@@ -61,36 +55,30 @@ export async function getMorphoVaultUserPositionSnapshots<
61
55
  const vaultAddress: Address | undefined =
62
56
  rawVaultAddress ?? (vault ? environment.vaults[vault].address : undefined);
63
57
 
64
- const lunarIndexerUrl = environment.custom?.morpho?.lunarIndexerUrl;
58
+ const lunarIndexerUrl = environment.lunarIndexerUrl;
65
59
 
66
- if (lunarIndexerUrl) {
67
- try {
68
- return await fetchUserPositionSnapshotsFromLunar(
69
- args.userAddress,
70
- vaultAddress,
71
- lunarIndexerUrl,
72
- environment,
73
- );
74
- } catch (error) {
75
- if (!shouldFallback(error)) {
76
- throw error;
77
- }
78
- console.debug(
79
- "[Lunar fallback] Falling back to Ponder for vault user position snapshots:",
80
- error,
81
- );
82
- }
60
+ if (!lunarIndexerUrl) {
61
+ return [];
83
62
  }
84
63
 
85
- if (!vaultAddress) {
64
+ try {
65
+ return await fetchUserPositionSnapshotsFromLunar(
66
+ args.userAddress,
67
+ vaultAddress,
68
+ lunarIndexerUrl,
69
+ environment,
70
+ );
71
+ } catch (error) {
72
+ console.warn(
73
+ `[getMorphoVaultUserPositionSnapshots] Lunar Indexer failed for chain ${environment.chainId}:`,
74
+ error,
75
+ );
76
+ environment.onError?.(error, {
77
+ source: "morpho-vault-user-position-snapshots",
78
+ chainId: environment.chainId,
79
+ });
86
80
  return [];
87
81
  }
88
-
89
- return fetchUserPositionSnapshots(
90
- args.userAddress,
91
- vaultAddress,
92
- environment,
93
- );
94
82
  }
95
83
 
96
84
  async function fetchUserPositionSnapshotsFromLunar(
@@ -131,80 +119,3 @@ async function fetchUserPositionSnapshotsFromLunar(
131
119
 
132
120
  return snapshots;
133
121
  }
134
-
135
- async function fetchUserPositionSnapshots(
136
- userAddress: Address,
137
- vaultAddress: Address,
138
- environment: Environment,
139
- ): Promise<MorphoVaultUserPositionSnapshot[]> {
140
- const dailyData: MorphoVaultUserDailyData[] = [];
141
- let hasNextPage = true;
142
- let endCursor: string | undefined;
143
-
144
- interface MorphoVaultUserDailyData {
145
- totalSuppliesUSD: string;
146
- timestamp: number;
147
- }
148
-
149
- while (hasNextPage) {
150
- const result = await axios.post<{
151
- data: {
152
- accountVaultDailySnapshots: {
153
- items: MorphoVaultUserDailyData[];
154
- pageInfo: {
155
- hasNextPage: boolean;
156
- endCursor: string;
157
- };
158
- };
159
- };
160
- }>(environment.indexerUrl, {
161
- query: `
162
- query {
163
- accountVaultDailySnapshots(
164
- limit: 365,
165
- orderDirection: "desc",
166
- orderBy: "timestamp",
167
- where: { vaultAddress: "${vaultAddress.toLowerCase()}", accountAddress: "${userAddress.toLowerCase()}", chainId: ${environment.chainId} }
168
- ${endCursor ? `after: "${endCursor}"` : ""}
169
- ) {
170
- items {
171
- totalSuppliesUSD
172
- timestamp
173
- }
174
- pageInfo {
175
- hasNextPage
176
- endCursor
177
- }
178
- }
179
- }
180
- `,
181
- });
182
-
183
- dailyData.push(
184
- ...result.data.data.accountVaultDailySnapshots.items.filter(
185
- (f: { timestamp: number }) => isStartOfDay(f.timestamp),
186
- ),
187
- );
188
- hasNextPage =
189
- result.data.data.accountVaultDailySnapshots.pageInfo.hasNextPage;
190
- endCursor = result.data.data.accountVaultDailySnapshots.pageInfo.endCursor;
191
- }
192
-
193
- if (dailyData.length > 0) {
194
- return dailyData.map((point: MorphoVaultUserDailyData) => {
195
- const suppliedUsd = Number(point.totalSuppliesUSD);
196
-
197
- const result: MorphoVaultUserPositionSnapshot = {
198
- chainId: environment.chainId,
199
- timestamp: point.timestamp * 1000,
200
- suppliedUsd: suppliedUsd,
201
- account: userAddress,
202
- vaultAddress: vaultAddress,
203
- };
204
-
205
- return result;
206
- });
207
- } else {
208
- return [];
209
- }
210
- }
@@ -153,14 +153,13 @@ async function getMorphoVaultsDataFromIndexer(params: {
153
153
  // Filter environments that have vaults and Lunar Indexer URL configured
154
154
  const environmentsWithVaults = environments.filter(
155
155
  (environment) =>
156
- Object.keys(environment.vaults).length > 0 &&
157
- environment.custom?.morpho?.lunarIndexerUrl,
156
+ Object.keys(environment.vaults).length > 0 && environment.lunarIndexerUrl,
158
157
  );
159
158
 
160
159
  // Fetch vaults from Lunar Indexer for each environment
161
160
  const environmentsVaultsSettlements = await Promise.allSettled(
162
161
  environmentsWithVaults.map(async (environment) => {
163
- const lunarIndexerUrl = environment.custom.morpho!.lunarIndexerUrl!;
162
+ const lunarIndexerUrl = environment.lunarIndexerUrl!;
164
163
 
165
164
  try {
166
165
  // Fetch tokens and vaults in parallel
@@ -228,6 +227,10 @@ async function getMorphoVaultsDataFromIndexer(params: {
228
227
  `Failed to fetch vaults from Lunar Indexer for chain ${environment.chainId}, falling back to on-chain:`,
229
228
  error,
230
229
  );
230
+ environment.onError?.(error, {
231
+ source: "vaults",
232
+ chainId: environment.chainId,
233
+ });
231
234
  throw { environment, error };
232
235
  }
233
236
  }),
@@ -442,9 +445,7 @@ export async function getMorphoVaultsData(params: {
442
445
  const { environments } = params;
443
446
 
444
447
  // Check if any environment has Lunar Indexer URL configured
445
- const hasLunarIndexer = environments.some(
446
- (env) => env.custom?.morpho?.lunarIndexerUrl,
447
- );
448
+ const hasLunarIndexer = environments.some((env) => env.lunarIndexerUrl);
448
449
 
449
450
  // Use Lunar Indexer implementation if available
450
451
  if (hasLunarIndexer) {
@@ -1,17 +1,15 @@
1
- import axios from "axios";
2
1
  import type { MoonwellClient } from "../../../client/createMoonwellClient.js";
3
2
  import {
4
3
  applyGranularity,
5
4
  calculateTimeRange,
6
5
  getEnvironmentFromArgs,
7
- isStartOfDay,
8
6
  toApiGranularity,
9
7
  } from "../../../common/index.js";
10
8
  import type {
11
9
  MorphoVaultParameterType,
12
10
  NetworkParameterType,
13
11
  } from "../../../common/types.js";
14
- import type { Chain, Environment } from "../../../environments/index.js";
12
+ import type { Chain } from "../../../environments/index.js";
15
13
  import type { MorphoVaultSnapshot } from "../../../types/morphoVault.js";
16
14
  import {
17
15
  fetchVaultSnapshotsFromIndexer,
@@ -76,29 +74,43 @@ export async function getMorphoVaultSnapshots<
76
74
  }
77
75
  }
78
76
 
79
- const lunarIndexerUrl = environment.custom?.morpho?.lunarIndexerUrl;
80
-
81
- const snapshots = lunarIndexerUrl
82
- ? await fetchVaultSnapshotsFromLunarIndexer(
83
- fetchAddress,
84
- environment.chainId,
85
- lunarIndexerUrl,
86
- period,
87
- customStartTime,
88
- customEndTime,
89
- )
90
- : await fetchVaultSnapshotsFromPonder(fetchAddress, environment);
91
-
92
- // Restore the originally-requested vault address on every snapshot so
93
- // callers keying by address see the V2 address they asked for.
94
- if (fetchAddress.toLowerCase() !== requestedVaultAddress.toLowerCase()) {
95
- return snapshots.map((s) => ({
96
- ...s,
97
- vaultAddress: requestedVaultAddress.toLowerCase(),
98
- }));
77
+ const lunarIndexerUrl = environment.lunarIndexerUrl;
78
+
79
+ if (!lunarIndexerUrl) {
80
+ return [];
99
81
  }
100
82
 
101
- return snapshots;
83
+ try {
84
+ const snapshots = await fetchVaultSnapshotsFromLunarIndexer(
85
+ fetchAddress,
86
+ environment.chainId,
87
+ lunarIndexerUrl,
88
+ period,
89
+ customStartTime,
90
+ customEndTime,
91
+ );
92
+
93
+ // Restore the originally-requested vault address on every snapshot so
94
+ // callers keying by address see the V2 address they asked for.
95
+ if (fetchAddress.toLowerCase() !== requestedVaultAddress.toLowerCase()) {
96
+ return snapshots.map((s) => ({
97
+ ...s,
98
+ vaultAddress: requestedVaultAddress.toLowerCase(),
99
+ }));
100
+ }
101
+
102
+ return snapshots;
103
+ } catch (error) {
104
+ console.warn(
105
+ `[getMorphoVaultSnapshots] Lunar Indexer failed for chain ${environment.chainId}:`,
106
+ error,
107
+ );
108
+ environment.onError?.(error, {
109
+ source: "morpho-vault-snapshots",
110
+ chainId: environment.chainId,
111
+ });
112
+ return [];
113
+ }
102
114
  }
103
115
 
104
116
  async function fetchVaultSnapshotsFromLunarIndexer(
@@ -147,99 +159,3 @@ async function fetchVaultSnapshotsFromLunarIndexer(
147
159
  allSnapshots.sort((a, b) => a.timestamp - b.timestamp);
148
160
  return applyGranularity(allSnapshots, granularity);
149
161
  }
150
-
151
- async function fetchVaultSnapshotsFromPonder(
152
- vaultAddress: string,
153
- environment: Environment,
154
- ): Promise<MorphoVaultSnapshot[]> {
155
- const dailyData: VaultDailyData[] = [];
156
- let hasNextPage = true;
157
- let endCursor: string | undefined;
158
-
159
- interface VaultDailyData {
160
- totalBorrows: number;
161
- totalBorrowsUSD: number;
162
- totalSupplies: number;
163
- totalSuppliesUSD: number;
164
- totalLiquidity: number;
165
- totalLiquidityUSD: number;
166
- timestamp: number;
167
- }
168
-
169
- while (hasNextPage) {
170
- const result = await axios.post<{
171
- data: {
172
- vaultDailySnapshots: {
173
- items: VaultDailyData[];
174
- pageInfo: {
175
- hasNextPage: boolean;
176
- endCursor: string;
177
- };
178
- };
179
- };
180
- }>(environment.indexerUrl, {
181
- query: `
182
- query {
183
- vaultDailySnapshots (
184
- limit: 365,
185
- orderBy: "timestamp"
186
- orderDirection: "desc"
187
- where: {vaultAddress: "${vaultAddress.toLowerCase()}", chainId: ${environment.chainId}}
188
- ${endCursor ? `after: "${endCursor}"` : ""}
189
- ) {
190
- items {
191
- totalBorrows
192
- totalBorrowsUSD
193
- totalSupplies
194
- totalSuppliesUSD
195
- totalLiquidity
196
- totalLiquidityUSD
197
- timestamp
198
- }
199
- pageInfo {
200
- hasNextPage
201
- endCursor
202
- }
203
- }
204
- }
205
- `,
206
- });
207
-
208
- if (result.data.data.vaultDailySnapshots) {
209
- dailyData.push(
210
- ...result.data.data.vaultDailySnapshots.items.filter(
211
- (f: { timestamp: number }) => isStartOfDay(f.timestamp),
212
- ),
213
- );
214
- hasNextPage = result.data.data.vaultDailySnapshots.pageInfo.hasNextPage;
215
- endCursor = result.data.data.vaultDailySnapshots.pageInfo.endCursor;
216
- }
217
- }
218
-
219
- if (dailyData.length > 0) {
220
- return dailyData.map((point: VaultDailyData) => {
221
- const supplied = Number(point.totalSupplies);
222
- const borrow = Number(point.totalBorrows);
223
- const borrowUsd = Number(point.totalBorrowsUSD);
224
- const suppliedUsd = Number(point.totalSuppliesUSD);
225
- const liquidity = Number(point.totalLiquidity);
226
- const liquidityUsd = Number(point.totalLiquidityUSD);
227
-
228
- const result: MorphoVaultSnapshot = {
229
- vaultAddress: vaultAddress.toLowerCase(),
230
- chainId: environment.chainId,
231
- timestamp: point.timestamp * 1000,
232
- totalSupply: supplied,
233
- totalSupplyUsd: suppliedUsd,
234
- totalBorrows: borrow,
235
- totalBorrowsUsd: borrowUsd,
236
- totalLiquidity: liquidity,
237
- totalLiquidityUsd: liquidityUsd,
238
- };
239
-
240
- return result;
241
- });
242
- } else {
243
- return [];
244
- }
245
- }
@@ -1,23 +1,20 @@
1
- import axios from "axios";
2
1
  import type { MoonwellClient } from "../../../client/createMoonwellClient.js";
3
2
  import {
4
3
  type SnapshotPeriod,
5
4
  applyGranularity,
6
5
  calculateTimeRange,
7
6
  getEnvironmentFromArgs,
8
- isStartOfDay,
9
7
  toApiGranularity,
10
8
  } from "../../../common/index.js";
11
9
  import type {
12
10
  MorphoVaultParameterType,
13
11
  NetworkParameterType,
14
12
  } from "../../../common/types.js";
15
- import type { Chain, Environment } from "../../../environments/index.js";
13
+ import type { Chain } from "../../../environments/index.js";
16
14
  import type { MorphoVaultStakingSnapshot } from "../../../types/morphoVault.js";
17
15
  import {
18
16
  DEFAULT_LUNAR_TIMEOUT_MS,
19
17
  createLunarIndexerClient,
20
- shouldFallback,
21
18
  } from "../../lunar-indexer-client.js";
22
19
  import { transformVaultStakingSnapshots } from "../../lunar-indexer-transformers.js";
23
20
 
@@ -56,37 +53,31 @@ export async function getMorphoVaultStakingSnapshots<
56
53
  } = args as GetMorphoVaultStakingSnapshotsParameters<environments, undefined>;
57
54
 
58
55
  const { lunarIndexerUrl } = environment;
59
- if (lunarIndexerUrl) {
60
- try {
61
- return await fetchVaultStakingSnapshotsFromLunar(
62
- vaultAddress,
63
- lunarIndexerUrl,
64
- environment.chainId,
65
- period,
66
- customStartTime,
67
- customEndTime,
68
- );
69
- } catch (error) {
70
- if (!shouldFallback(error)) {
71
- throw error;
72
- }
73
- console.debug(
74
- "[Lunar fallback] Falling back to Ponder for vault staking snapshots:",
75
- error,
76
- );
77
- }
56
+
57
+ if (!lunarIndexerUrl) {
58
+ return [];
78
59
  }
79
60
 
80
- const { startTime } = calculateTimeRange(
81
- period,
82
- customStartTime,
83
- customEndTime,
84
- );
85
- return fetchVaultStakingSnapshotsFromPonder(
86
- vaultAddress,
87
- environment,
88
- startTime,
89
- );
61
+ try {
62
+ return await fetchVaultStakingSnapshotsFromLunar(
63
+ vaultAddress,
64
+ lunarIndexerUrl,
65
+ environment.chainId,
66
+ period,
67
+ customStartTime,
68
+ customEndTime,
69
+ );
70
+ } catch (error) {
71
+ console.warn(
72
+ `[getMorphoVaultStakingSnapshots] Lunar Indexer failed for chain ${environment.chainId}:`,
73
+ error,
74
+ );
75
+ environment.onError?.(error, {
76
+ source: "morpho-vault-staking-snapshots",
77
+ chainId: environment.chainId,
78
+ });
79
+ return [];
80
+ }
90
81
  }
91
82
 
92
83
  async function fetchVaultStakingSnapshotsFromLunar(
@@ -131,81 +122,3 @@ async function fetchVaultStakingSnapshotsFromLunar(
131
122
  allSnapshots.sort((a, b) => a.timestamp - b.timestamp);
132
123
  return applyGranularity(allSnapshots, granularity);
133
124
  }
134
-
135
- interface VaultStakingData {
136
- totalStaked: number;
137
- totalStakedUSD: number;
138
- timestamp: number;
139
- }
140
-
141
- async function fetchVaultStakingSnapshotsFromPonder(
142
- vaultAddress: string,
143
- environment: Environment,
144
- startTime?: number,
145
- ): Promise<MorphoVaultStakingSnapshot[]> {
146
- const dailyData: VaultStakingData[] = [];
147
- let hasNextPage = true;
148
- let endCursor: string | undefined;
149
-
150
- while (hasNextPage) {
151
- const result = await axios.post<{
152
- data: {
153
- vaultStakingDailySnapshots: {
154
- items: VaultStakingData[];
155
- pageInfo: {
156
- hasNextPage: boolean;
157
- endCursor: string;
158
- };
159
- };
160
- };
161
- }>(environment.indexerUrl, {
162
- query: `
163
- query {
164
- vaultStakingDailySnapshots (
165
- limit: 365,
166
- orderBy: "timestamp"
167
- orderDirection: "desc"
168
- where: {vaultAddress: "${vaultAddress.toLowerCase()}", chainId: ${environment.chainId}}
169
- ${endCursor ? `after: "${endCursor}"` : ""}
170
- ) {
171
- items {
172
- totalStaked
173
- totalStakedUSD
174
- timestamp
175
- }
176
- pageInfo {
177
- hasNextPage
178
- endCursor
179
- }
180
- }
181
- }
182
- `,
183
- });
184
-
185
- if (result.data.data.vaultStakingDailySnapshots) {
186
- dailyData.push(
187
- ...result.data.data.vaultStakingDailySnapshots.items.filter(
188
- (f: { timestamp: number }) =>
189
- isStartOfDay(f.timestamp) &&
190
- (startTime === undefined || f.timestamp >= startTime),
191
- ),
192
- );
193
- hasNextPage =
194
- result.data.data.vaultStakingDailySnapshots.pageInfo.hasNextPage;
195
- endCursor =
196
- result.data.data.vaultStakingDailySnapshots.pageInfo.endCursor;
197
- }
198
- }
199
-
200
- if (dailyData.length > 0) {
201
- return dailyData.map((point: VaultStakingData) => ({
202
- vaultAddress: vaultAddress.toLowerCase(),
203
- chainId: environment.chainId,
204
- timestamp: point.timestamp * 1000,
205
- totalStaked: Number(point.totalStaked),
206
- totalStakedUsd: Number(point.totalStakedUSD),
207
- }));
208
- } else {
209
- return [];
210
- }
211
- }