@moonwell-fi/moonwell-sdk 0.11.0 → 0.12.1

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 (242) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/_cjs/actions/axiosWithRetry.js +25 -0
  3. package/_cjs/actions/axiosWithRetry.js.map +1 -0
  4. package/_cjs/actions/beam/getBeamTokenLimits.js +2 -5
  5. package/_cjs/actions/beam/getBeamTokenLimits.js.map +1 -1
  6. package/_cjs/actions/beam/getBeamTokenRoutes.js +3 -6
  7. package/_cjs/actions/beam/getBeamTokenRoutes.js.map +1 -1
  8. package/_cjs/actions/core/markets/common.js +26 -12
  9. package/_cjs/actions/core/markets/common.js.map +1 -1
  10. package/_cjs/actions/core/markets/getMarketSnapshots.js +175 -326
  11. package/_cjs/actions/core/markets/getMarketSnapshots.js.map +1 -1
  12. package/_cjs/actions/core/user-positions/getUserPositionSnapshots.js +33 -31
  13. package/_cjs/actions/core/user-positions/getUserPositionSnapshots.js.map +1 -1
  14. package/_cjs/actions/governance/getCirculatingSupplySnapshots.js +38 -35
  15. package/_cjs/actions/governance/getCirculatingSupplySnapshots.js.map +1 -1
  16. package/_cjs/actions/governance/getDelegates.js +2 -5
  17. package/_cjs/actions/governance/getDelegates.js.map +1 -1
  18. package/_cjs/actions/governance/getDiscussions.js +3 -3
  19. package/_cjs/actions/governance/getDiscussions.js.map +1 -1
  20. package/_cjs/actions/governance/getStakingSnapshots.js +18 -17
  21. package/_cjs/actions/governance/getStakingSnapshots.js.map +1 -1
  22. package/_cjs/actions/governance/getUserVotingPowers.js +12 -4
  23. package/_cjs/actions/governance/getUserVotingPowers.js.map +1 -1
  24. package/_cjs/actions/governance/governor-api-client.js +10 -13
  25. package/_cjs/actions/governance/governor-api-client.js.map +1 -1
  26. package/_cjs/actions/governance/proposals/common.js +248 -211
  27. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  28. package/_cjs/actions/governance/snapshot/common.js +2 -5
  29. package/_cjs/actions/governance/snapshot/common.js.map +1 -1
  30. package/_cjs/actions/lunar-indexer-client.js +4 -0
  31. package/_cjs/actions/lunar-indexer-client.js.map +1 -1
  32. package/_cjs/actions/morpho/markets/common.js +28 -34
  33. package/_cjs/actions/morpho/markets/common.js.map +1 -1
  34. package/_cjs/actions/morpho/markets/lunarIndexerTransform.js +5 -8
  35. package/_cjs/actions/morpho/markets/lunarIndexerTransform.js.map +1 -1
  36. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js +12 -69
  37. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js.map +1 -1
  38. package/_cjs/actions/morpho/vaults/common.js +7 -4
  39. package/_cjs/actions/morpho/vaults/common.js.map +1 -1
  40. package/_cjs/actions/morpho/vaults/getMorphoVaultSnapshots.js +21 -78
  41. package/_cjs/actions/morpho/vaults/getMorphoVaultSnapshots.js.map +1 -1
  42. package/_cjs/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js +13 -66
  43. package/_cjs/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js.map +1 -1
  44. package/_cjs/actions/retry.js +63 -0
  45. package/_cjs/actions/retry.js.map +1 -0
  46. package/_cjs/client/createMoonwellClient.js +9 -3
  47. package/_cjs/client/createMoonwellClient.js.map +1 -1
  48. package/_cjs/common/getBlockNumberAtTimestamp.js +42 -0
  49. package/_cjs/common/getBlockNumberAtTimestamp.js.map +1 -0
  50. package/_cjs/common/index.js +3 -1
  51. package/_cjs/common/index.js.map +1 -1
  52. package/_cjs/environments/definitions/arbitrum/environment.js +1 -2
  53. package/_cjs/environments/definitions/arbitrum/environment.js.map +1 -1
  54. package/_cjs/environments/definitions/avalanche/environment.js +1 -2
  55. package/_cjs/environments/definitions/avalanche/environment.js.map +1 -1
  56. package/_cjs/environments/definitions/base/custom.js +0 -1
  57. package/_cjs/environments/definitions/base/custom.js.map +1 -1
  58. package/_cjs/environments/definitions/base/environment.js +1 -2
  59. package/_cjs/environments/definitions/base/environment.js.map +1 -1
  60. package/_cjs/environments/definitions/ethereum/environment.js +1 -2
  61. package/_cjs/environments/definitions/ethereum/environment.js.map +1 -1
  62. package/_cjs/environments/definitions/moonbeam/environment.js +1 -2
  63. package/_cjs/environments/definitions/moonbeam/environment.js.map +1 -1
  64. package/_cjs/environments/definitions/optimism/custom.js +0 -1
  65. package/_cjs/environments/definitions/optimism/custom.js.map +1 -1
  66. package/_cjs/environments/definitions/optimism/environment.js +1 -2
  67. package/_cjs/environments/definitions/optimism/environment.js.map +1 -1
  68. package/_cjs/environments/definitions/polygon/environment.js +1 -2
  69. package/_cjs/environments/definitions/polygon/environment.js.map +1 -1
  70. package/_cjs/environments/index.js +8 -8
  71. package/_cjs/environments/index.js.map +1 -1
  72. package/_cjs/environments/types/config.js +1 -0
  73. package/_cjs/environments/types/config.js.map +1 -1
  74. package/_cjs/errors/version.js +1 -1
  75. package/_esm/actions/axiosWithRetry.js +32 -0
  76. package/_esm/actions/axiosWithRetry.js.map +1 -0
  77. package/_esm/actions/beam/getBeamTokenLimits.js +2 -2
  78. package/_esm/actions/beam/getBeamTokenLimits.js.map +1 -1
  79. package/_esm/actions/beam/getBeamTokenRoutes.js +3 -3
  80. package/_esm/actions/beam/getBeamTokenRoutes.js.map +1 -1
  81. package/_esm/actions/core/markets/common.js +26 -13
  82. package/_esm/actions/core/markets/common.js.map +1 -1
  83. package/_esm/actions/core/markets/getMarketSnapshots.js +196 -348
  84. package/_esm/actions/core/markets/getMarketSnapshots.js.map +1 -1
  85. package/_esm/actions/core/user-positions/getUserPositionSnapshots.js +34 -31
  86. package/_esm/actions/core/user-positions/getUserPositionSnapshots.js.map +1 -1
  87. package/_esm/actions/governance/getCirculatingSupplySnapshots.js +38 -33
  88. package/_esm/actions/governance/getCirculatingSupplySnapshots.js.map +1 -1
  89. package/_esm/actions/governance/getDelegates.js +2 -2
  90. package/_esm/actions/governance/getDelegates.js.map +1 -1
  91. package/_esm/actions/governance/getDiscussions.js +3 -3
  92. package/_esm/actions/governance/getDiscussions.js.map +1 -1
  93. package/_esm/actions/governance/getStakingSnapshots.js +19 -15
  94. package/_esm/actions/governance/getStakingSnapshots.js.map +1 -1
  95. package/_esm/actions/governance/getUserVotingPowers.js +13 -5
  96. package/_esm/actions/governance/getUserVotingPowers.js.map +1 -1
  97. package/_esm/actions/governance/governor-api-client.js +10 -10
  98. package/_esm/actions/governance/governor-api-client.js.map +1 -1
  99. package/_esm/actions/governance/proposals/common.js +247 -216
  100. package/_esm/actions/governance/proposals/common.js.map +1 -1
  101. package/_esm/actions/governance/snapshot/common.js +2 -2
  102. package/_esm/actions/governance/snapshot/common.js.map +1 -1
  103. package/_esm/actions/lunar-indexer-client.js +6 -0
  104. package/_esm/actions/lunar-indexer-client.js.map +1 -1
  105. package/_esm/actions/morpho/markets/common.js +29 -36
  106. package/_esm/actions/morpho/markets/common.js.map +1 -1
  107. package/_esm/actions/morpho/markets/lunarIndexerTransform.js +5 -5
  108. package/_esm/actions/morpho/markets/lunarIndexerTransform.js.map +1 -1
  109. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js +14 -68
  110. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.js.map +1 -1
  111. package/_esm/actions/morpho/vaults/common.js +7 -4
  112. package/_esm/actions/morpho/vaults/common.js.map +1 -1
  113. package/_esm/actions/morpho/vaults/getMorphoVaultSnapshots.js +24 -78
  114. package/_esm/actions/morpho/vaults/getMorphoVaultSnapshots.js.map +1 -1
  115. package/_esm/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js +15 -65
  116. package/_esm/actions/morpho/vaults/getMorphoVaultStakingSnapshots.js.map +1 -1
  117. package/_esm/actions/retry.js +90 -0
  118. package/_esm/actions/retry.js.map +1 -0
  119. package/_esm/client/createMoonwellClient.js +9 -3
  120. package/_esm/client/createMoonwellClient.js.map +1 -1
  121. package/_esm/common/getBlockNumberAtTimestamp.js +56 -0
  122. package/_esm/common/getBlockNumberAtTimestamp.js.map +1 -0
  123. package/_esm/common/index.js +1 -0
  124. package/_esm/common/index.js.map +1 -1
  125. package/_esm/environments/definitions/arbitrum/environment.js +1 -2
  126. package/_esm/environments/definitions/arbitrum/environment.js.map +1 -1
  127. package/_esm/environments/definitions/avalanche/environment.js +1 -2
  128. package/_esm/environments/definitions/avalanche/environment.js.map +1 -1
  129. package/_esm/environments/definitions/base/custom.js +0 -1
  130. package/_esm/environments/definitions/base/custom.js.map +1 -1
  131. package/_esm/environments/definitions/base/environment.js +1 -2
  132. package/_esm/environments/definitions/base/environment.js.map +1 -1
  133. package/_esm/environments/definitions/ethereum/environment.js +1 -2
  134. package/_esm/environments/definitions/ethereum/environment.js.map +1 -1
  135. package/_esm/environments/definitions/moonbeam/environment.js +1 -2
  136. package/_esm/environments/definitions/moonbeam/environment.js.map +1 -1
  137. package/_esm/environments/definitions/optimism/custom.js +0 -1
  138. package/_esm/environments/definitions/optimism/custom.js.map +1 -1
  139. package/_esm/environments/definitions/optimism/environment.js +1 -2
  140. package/_esm/environments/definitions/optimism/environment.js.map +1 -1
  141. package/_esm/environments/definitions/polygon/environment.js +1 -2
  142. package/_esm/environments/definitions/polygon/environment.js.map +1 -1
  143. package/_esm/environments/index.js +8 -8
  144. package/_esm/environments/index.js.map +1 -1
  145. package/_esm/environments/types/config.js +1 -0
  146. package/_esm/environments/types/config.js.map +1 -1
  147. package/_esm/errors/version.js +1 -1
  148. package/_types/actions/axiosWithRetry.d.ts +16 -0
  149. package/_types/actions/axiosWithRetry.d.ts.map +1 -0
  150. package/_types/actions/beam/getBeamTokenLimits.d.ts.map +1 -1
  151. package/_types/actions/beam/getBeamTokenRoutes.d.ts.map +1 -1
  152. package/_types/actions/core/markets/common.d.ts.map +1 -1
  153. package/_types/actions/core/markets/getMarketSnapshots.d.ts.map +1 -1
  154. package/_types/actions/core/user-positions/getUserPositionSnapshots.d.ts +0 -1
  155. package/_types/actions/core/user-positions/getUserPositionSnapshots.d.ts.map +1 -1
  156. package/_types/actions/governance/getCirculatingSupplySnapshots.d.ts.map +1 -1
  157. package/_types/actions/governance/getDelegates.d.ts.map +1 -1
  158. package/_types/actions/governance/getDiscussions.d.ts.map +1 -1
  159. package/_types/actions/governance/getStakingSnapshots.d.ts.map +1 -1
  160. package/_types/actions/governance/getUserVotingPowers.d.ts +13 -1
  161. package/_types/actions/governance/getUserVotingPowers.d.ts.map +1 -1
  162. package/_types/actions/governance/governor-api-client.d.ts.map +1 -1
  163. package/_types/actions/governance/proposals/common.d.ts +2 -8
  164. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  165. package/_types/actions/governance/snapshot/common.d.ts.map +1 -1
  166. package/_types/actions/lunar-indexer-client.d.ts.map +1 -1
  167. package/_types/actions/morpho/markets/common.d.ts.map +1 -1
  168. package/_types/actions/morpho/markets/lunarIndexerTransform.d.ts.map +1 -1
  169. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.d.ts.map +1 -1
  170. package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
  171. package/_types/actions/morpho/vaults/getMorphoVaultSnapshots.d.ts.map +1 -1
  172. package/_types/actions/morpho/vaults/getMorphoVaultStakingSnapshots.d.ts.map +1 -1
  173. package/_types/actions/retry.d.ts +45 -0
  174. package/_types/actions/retry.d.ts.map +1 -0
  175. package/_types/client/createMoonwellClient.d.ts +6 -6
  176. package/_types/client/createMoonwellClient.d.ts.map +1 -1
  177. package/_types/common/getBlockNumberAtTimestamp.d.ts +15 -0
  178. package/_types/common/getBlockNumberAtTimestamp.d.ts.map +1 -0
  179. package/_types/common/index.d.ts +1 -0
  180. package/_types/common/index.d.ts.map +1 -1
  181. package/_types/environments/definitions/arbitrum/environment.d.ts +1 -1
  182. package/_types/environments/definitions/arbitrum/environment.d.ts.map +1 -1
  183. package/_types/environments/definitions/avalanche/environment.d.ts +1 -1
  184. package/_types/environments/definitions/avalanche/environment.d.ts.map +1 -1
  185. package/_types/environments/definitions/base/custom.d.ts +0 -1
  186. package/_types/environments/definitions/base/custom.d.ts.map +1 -1
  187. package/_types/environments/definitions/base/environment.d.ts +22 -4
  188. package/_types/environments/definitions/base/environment.d.ts.map +1 -1
  189. package/_types/environments/definitions/ethereum/environment.d.ts +1 -1
  190. package/_types/environments/definitions/ethereum/environment.d.ts.map +1 -1
  191. package/_types/environments/definitions/moonbeam/custom.d.ts +1 -1
  192. package/_types/environments/definitions/moonbeam/environment.d.ts +2 -2
  193. package/_types/environments/definitions/moonbeam/environment.d.ts.map +1 -1
  194. package/_types/environments/definitions/optimism/custom.d.ts +0 -1
  195. package/_types/environments/definitions/optimism/custom.d.ts.map +1 -1
  196. package/_types/environments/definitions/optimism/environment.d.ts +1 -2
  197. package/_types/environments/definitions/optimism/environment.d.ts.map +1 -1
  198. package/_types/environments/definitions/polygon/environment.d.ts +1 -1
  199. package/_types/environments/definitions/polygon/environment.d.ts.map +1 -1
  200. package/_types/environments/index.d.ts +119 -23
  201. package/_types/environments/index.d.ts.map +1 -1
  202. package/_types/environments/types/config.d.ts +37 -44
  203. package/_types/environments/types/config.d.ts.map +1 -1
  204. package/_types/errors/version.d.ts +1 -1
  205. package/actions/axiosWithRetry.ts +42 -0
  206. package/actions/beam/getBeamTokenLimits.ts +2 -2
  207. package/actions/beam/getBeamTokenRoutes.ts +3 -3
  208. package/actions/core/markets/common.ts +33 -18
  209. package/actions/core/markets/getMarketSnapshots.ts +263 -513
  210. package/actions/core/user-positions/getUserPositionSnapshots.ts +46 -48
  211. package/actions/governance/getCirculatingSupplySnapshots.ts +46 -38
  212. package/actions/governance/getDelegates.ts +2 -2
  213. package/actions/governance/getDiscussions.ts +6 -5
  214. package/actions/governance/getStakingSnapshots.ts +34 -31
  215. package/actions/governance/getUserVotingPowers.ts +43 -8
  216. package/actions/governance/governor-api-client.ts +12 -10
  217. package/actions/governance/proposals/common.ts +370 -330
  218. package/actions/governance/snapshot/common.ts +2 -2
  219. package/actions/lunar-indexer-client.ts +8 -0
  220. package/actions/morpho/markets/common.ts +34 -45
  221. package/actions/morpho/markets/lunarIndexerTransform.ts +6 -5
  222. package/actions/morpho/user-positions/getMorphoVaultUserPositionSnapshots.ts +20 -109
  223. package/actions/morpho/vaults/common.ts +7 -6
  224. package/actions/morpho/vaults/getMorphoVaultSnapshots.ts +36 -120
  225. package/actions/morpho/vaults/getMorphoVaultStakingSnapshots.ts +24 -111
  226. package/actions/retry.ts +121 -0
  227. package/client/createMoonwellClient.ts +17 -5
  228. package/common/getBlockNumberAtTimestamp.ts +59 -0
  229. package/common/index.ts +1 -0
  230. package/environments/definitions/arbitrum/environment.ts +0 -2
  231. package/environments/definitions/avalanche/environment.ts +0 -2
  232. package/environments/definitions/base/custom.ts +0 -1
  233. package/environments/definitions/base/environment.ts +0 -2
  234. package/environments/definitions/ethereum/environment.ts +0 -2
  235. package/environments/definitions/moonbeam/environment.ts +0 -2
  236. package/environments/definitions/optimism/custom.ts +0 -1
  237. package/environments/definitions/optimism/environment.ts +0 -2
  238. package/environments/definitions/polygon/environment.ts +0 -2
  239. package/environments/index.ts +6 -27
  240. package/environments/types/config.ts +45 -210
  241. package/errors/version.ts +1 -1
  242. package/package.json +2 -2
@@ -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
- }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Retry helpers for SDK API calls.
3
+ *
4
+ * Two consumers:
5
+ * 1. `attachRetryInterceptor` — axios response interceptor used inside
6
+ * LunarIndexerClient. One install per axios instance covers every method.
7
+ * 2. `retry` — generic wrapper for ad-hoc `axios.post(...)` callsites in
8
+ * actions that don't go through a shared axios instance.
9
+ *
10
+ * Policy:
11
+ * - 3 attempts (initial + 2 retries) by default
12
+ * - Exponential backoff: 250ms → 500ms (capped at 5s)
13
+ * - Retry only network errors / timeouts / 5xx; never retry 4xx (incl. 404 —
14
+ * retrying a deterministic "not found" wastes time and amplifies log noise)
15
+ * - After retries exhaust, the last error propagates to the caller's try/catch
16
+ * where the existing `environment.onError(...)` wiring picks it up
17
+ */
18
+ import axios, {
19
+ type AxiosError,
20
+ type AxiosInstance,
21
+ type InternalAxiosRequestConfig,
22
+ } from "axios";
23
+
24
+ export interface RetryOptions {
25
+ maxAttempts?: number;
26
+ initialDelay?: number;
27
+ maxDelay?: number;
28
+ }
29
+
30
+ const DEFAULT_MAX_ATTEMPTS = 3;
31
+ const DEFAULT_INITIAL_DELAY_MS = 250;
32
+ const DEFAULT_MAX_DELAY_MS = 5_000;
33
+
34
+ async function sleep(ms: number): Promise<void> {
35
+ return new Promise((resolve) => setTimeout(resolve, ms));
36
+ }
37
+
38
+ function backoffDelay(
39
+ attemptIndex: number,
40
+ initialDelay: number,
41
+ maxDelay: number,
42
+ ): number {
43
+ return Math.min(initialDelay * 2 ** attemptIndex, maxDelay);
44
+ }
45
+
46
+ /**
47
+ * Decide whether an error represents a transient failure worth retrying.
48
+ * - Axios network errors (no `response`) → retry (server unreachable, timeout)
49
+ * - 5xx responses → retry (server hiccup)
50
+ * - 4xx responses (incl. 404) → do NOT retry (deterministic, won't change)
51
+ * - Non-axios errors (parse errors, code bugs) → do NOT retry
52
+ */
53
+ export function isRetriableError(error: unknown): boolean {
54
+ if (!axios.isAxiosError(error)) return false;
55
+ if (!error.response) return true;
56
+ return error.response.status >= 500;
57
+ }
58
+
59
+ /**
60
+ * Attach a retry-on-failure interceptor to an axios instance. Every request
61
+ * made through this instance is retried up to `maxAttempts` times when the
62
+ * failure is retriable. Per-config state is tracked on a WeakMap so we don't
63
+ * pollute the public axios config shape.
64
+ */
65
+ export function attachRetryInterceptor(
66
+ instance: AxiosInstance,
67
+ options: RetryOptions = {},
68
+ ): void {
69
+ const {
70
+ maxAttempts = DEFAULT_MAX_ATTEMPTS,
71
+ initialDelay = DEFAULT_INITIAL_DELAY_MS,
72
+ maxDelay = DEFAULT_MAX_DELAY_MS,
73
+ } = options;
74
+ const attemptsByConfig = new WeakMap<InternalAxiosRequestConfig, number>();
75
+
76
+ instance.interceptors.response.use(
77
+ (response) => response,
78
+ async (error: AxiosError) => {
79
+ const config = error.config;
80
+ if (!config) throw error;
81
+ if (!isRetriableError(error)) throw error;
82
+
83
+ const previousAttempts = attemptsByConfig.get(config) ?? 0;
84
+ if (previousAttempts >= maxAttempts - 1) throw error;
85
+
86
+ attemptsByConfig.set(config, previousAttempts + 1);
87
+ await sleep(backoffDelay(previousAttempts, initialDelay, maxDelay));
88
+ return instance.request(config);
89
+ },
90
+ );
91
+ }
92
+
93
+ /**
94
+ * Generic wrapper for individual axios calls (e.g. raw `axios.post(...)` in
95
+ * action files that don't share a configured instance). Mirrors the
96
+ * interceptor's policy: retry transient failures, fail fast on 4xx.
97
+ */
98
+ export async function retry<T>(
99
+ fn: () => Promise<T>,
100
+ options: RetryOptions = {},
101
+ ): Promise<T> {
102
+ const {
103
+ maxAttempts = DEFAULT_MAX_ATTEMPTS,
104
+ initialDelay = DEFAULT_INITIAL_DELAY_MS,
105
+ maxDelay = DEFAULT_MAX_DELAY_MS,
106
+ } = options;
107
+ let attempt = 0;
108
+ let lastError: unknown;
109
+ while (attempt < maxAttempts) {
110
+ try {
111
+ return await fn();
112
+ } catch (error) {
113
+ lastError = error;
114
+ attempt++;
115
+ if (!isRetriableError(error)) throw error;
116
+ if (attempt >= maxAttempts) break;
117
+ await sleep(backoffDelay(attempt - 1, initialDelay, maxDelay));
118
+ }
119
+ }
120
+ throw lastError;
121
+ }
@@ -77,12 +77,15 @@ export type NetworksConfig<networks> = {} extends networks
77
77
 
78
78
  export const createMoonwellClient = <const networks>(config: {
79
79
  networks: NetworksConfig<Narrow<networks>>;
80
+ onError?: (
81
+ error: unknown,
82
+ context: { source: string; chainId: number },
83
+ ) => void;
80
84
  }) => {
81
- const environments = Object.keys(config.networks).reduce((prev, curr) => {
82
- const key = curr as SupportedChains;
83
- const networkConfig = (config.networks as NetworksConfig<SupportedChains>)[
84
- key
85
- ]!;
85
+ const environments = Object.entries(
86
+ config.networks as NetworksConfig<SupportedChains>,
87
+ ).reduce((prev, [curr, networkConfig]) => {
88
+ if (!networkConfig) return prev;
86
89
  return {
87
90
  ...prev,
88
91
  [curr]: createEnvironment({
@@ -143,6 +146,15 @@ export const createMoonwellClient = <const networks>(config: {
143
146
  }
144
147
  >;
145
148
 
149
+ if (config.onError) {
150
+ const onError = config.onError;
151
+ for (const env of Object.values(
152
+ environments as Record<string, Environment>,
153
+ )) {
154
+ env.onError = onError;
155
+ }
156
+ }
157
+
146
158
  const client = {
147
159
  environments,
148
160
  };
@@ -0,0 +1,59 @@
1
+ import type { PublicClient } from "viem";
2
+
3
+ /**
4
+ * Safety cap on interpolation iterations. With near-linear `ts(block)` the search
5
+ * converges in ~3–5 reads; 8 leaves headroom for chains with variable block times
6
+ * (e.g. Moonbeam) without unbounded RPC fan-out on pathological inputs.
7
+ */
8
+ const MAX_ITERATIONS = 8;
9
+
10
+ /**
11
+ * Find the block number on a chain whose timestamp is the latest one ≤ the target unix timestamp.
12
+ *
13
+ * Uses interpolation search anchored on the latest block and block 1: each iteration
14
+ * narrows the range by reading one block and projecting the target via the slope of the
15
+ * remaining range. Converges in ~3–5 RPC calls even on chains with variable block times.
16
+ *
17
+ * Assumes block 1 exists on the chain — true for every EVM chain Moonwell supports.
18
+ *
19
+ * Returns the latest block if `targetTimestamp` is at or after the head, and block 1
20
+ * if it is before block 1's timestamp. On a chain with only block 0, returns block 0.
21
+ */
22
+ export async function getBlockNumberAtTimestamp(
23
+ publicClient: PublicClient,
24
+ targetTimestamp: bigint,
25
+ ): Promise<bigint> {
26
+ const latest = await publicClient.getBlock({ blockTag: "latest" });
27
+ if (targetTimestamp >= latest.timestamp) return latest.number;
28
+ if (latest.number === 0n) return latest.number;
29
+
30
+ const first = await publicClient.getBlock({ blockNumber: 1n });
31
+ if (targetTimestamp <= first.timestamp) return first.number;
32
+
33
+ let lo = first.number;
34
+ let loTs = first.timestamp;
35
+ let hi = latest.number;
36
+ let hiTs = latest.timestamp;
37
+
38
+ for (let i = 0; i < MAX_ITERATIONS; i += 1) {
39
+ if (hi - lo <= 1n) break;
40
+ const tsRange = hiTs - loTs;
41
+ if (tsRange <= 0n) break;
42
+
43
+ const offset = ((targetTimestamp - loTs) * (hi - lo)) / tsRange;
44
+ let mid = lo + offset;
45
+ if (mid <= lo) mid = lo + 1n;
46
+ if (mid >= hi) mid = hi - 1n;
47
+
48
+ const block = await publicClient.getBlock({ blockNumber: mid });
49
+ if (block.timestamp <= targetTimestamp) {
50
+ lo = mid;
51
+ loTs = block.timestamp;
52
+ } else {
53
+ hi = mid;
54
+ hiTs = block.timestamp;
55
+ }
56
+ }
57
+
58
+ return lo;
59
+ }
package/common/index.ts CHANGED
@@ -7,6 +7,7 @@ dayjs.extend(utc);
7
7
  export { Amount } from "./amount.js";
8
8
  export { BaseError, HttpRequestError } from "./error.js";
9
9
  export type { HttpRequestErrorType } from "./error.js";
10
+ export { getBlockNumberAtTimestamp } from "./getBlockNumberAtTimestamp.js";
10
11
  export type { MultichainReturnType } from "./types.js";
11
12
 
12
13
  export const SECONDS_PER_DAY = 86400;
@@ -8,7 +8,6 @@ import { tokens } from "./tokens.js";
8
8
 
9
9
  const createEnvironment = (
10
10
  rpcUrls?: string[],
11
- indexerUrl?: string,
12
11
  governanceIndexerUrl?: string,
13
12
  ): Environment<typeof tokens, {}, {}, {}, {}> =>
14
13
  createEnvironmentConfig({
@@ -25,7 +24,6 @@ const createEnvironment = (
25
24
  transport: rpcUrls
26
25
  ? fallback(rpcUrls.map((url) => http(url)))
27
26
  : http("https://rpc.moonwell.fi/main/evm/42161"),
28
- indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
29
27
  governanceIndexerUrl:
30
28
  governanceIndexerUrl ||
31
29
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -8,7 +8,6 @@ import { tokens } from "./tokens.js";
8
8
 
9
9
  const createEnvironment = (
10
10
  rpcUrls?: string[],
11
- indexerUrl?: string,
12
11
  governanceIndexerUrl?: string,
13
12
  ): Environment<typeof tokens, {}, {}, {}, {}> =>
14
13
  createEnvironmentConfig({
@@ -25,7 +24,6 @@ const createEnvironment = (
25
24
  transport: rpcUrls
26
25
  ? fallback(rpcUrls.map((url) => http(url)))
27
26
  : http("https://rpc.moonwell.fi/main/evm/43114"),
28
- indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
29
27
  governanceIndexerUrl:
30
28
  governanceIndexerUrl ||
31
29
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -5,7 +5,6 @@ export const custom = createCustomConfig({
5
5
  minimalDeployment: false,
6
6
  apiUrl: "https://api.morpho.org/graphql",
7
7
  rewardsApiUrl: "https://rewards.morpho.org",
8
- lunarIndexerUrl: "https://lunar-services-worker.moonwell.workers.dev",
9
8
  },
10
9
  governance: {
11
10
  token: "WELL",
@@ -15,7 +15,6 @@ const base = defineChain({ ...baseChain, testnet: false });
15
15
 
16
16
  const createEnvironment = (
17
17
  rpcUrls?: string[],
18
- indexerUrl?: string,
19
18
  governanceIndexerUrl?: string,
20
19
  lunarIndexerUrl?: string,
21
20
  ): Environment<
@@ -37,7 +36,6 @@ const createEnvironment = (
37
36
  transport: rpcUrls
38
37
  ? fallback(rpcUrls.map((url) => http(url)))
39
38
  : http("https://rpc.moonwell.fi/main/evm/8453"),
40
- indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
41
39
  governanceIndexerUrl:
42
40
  governanceIndexerUrl ||
43
41
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -8,7 +8,6 @@ import { tokens } from "./tokens.js";
8
8
 
9
9
  const createEnvironment = (
10
10
  rpcUrls?: string[],
11
- indexerUrl?: string,
12
11
  governanceIndexerUrl?: string,
13
12
  ): Environment<typeof tokens, {}, {}, {}, {}> =>
14
13
  createEnvironmentConfig({
@@ -23,7 +22,6 @@ const createEnvironment = (
23
22
  transport: rpcUrls
24
23
  ? fallback(rpcUrls.map((url) => http(url)))
25
24
  : http("https://rpc.moonwell.fi/main/evm/1"),
26
- indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
27
25
  governanceIndexerUrl:
28
26
  governanceIndexerUrl ||
29
27
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -8,7 +8,6 @@ import { tokens } from "./tokens.js";
8
8
 
9
9
  const createEnvironment = (
10
10
  rpcUrls?: string[],
11
- indexerUrl?: string,
12
11
  governanceIndexerUrl?: string,
13
12
  lunarIndexerUrl?: string,
14
13
  ) =>
@@ -24,7 +23,6 @@ const createEnvironment = (
24
23
  transport: rpcUrls
25
24
  ? fallback(rpcUrls.map((url) => http(url)))
26
25
  : http("https://rpc.moonwell.fi/main/evm/1284"),
27
- indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
28
26
  lunarIndexerUrl:
29
27
  lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
30
28
  governanceIndexerUrl:
@@ -5,7 +5,6 @@ export const custom = createCustomConfig({
5
5
  minimalDeployment: true,
6
6
  apiUrl: "https://api.morpho.org/graphql",
7
7
  rewardsApiUrl: "https://rewards.morpho.org",
8
- lunarIndexerUrl: "https://lunar-services-worker.moonwell.workers.dev",
9
8
  },
10
9
  governance: {
11
10
  token: "WELL",
@@ -11,7 +11,6 @@ const optimism = defineChain({ ...optimismChain, testnet: false });
11
11
 
12
12
  const createEnvironment = (
13
13
  rpcUrls?: string[],
14
- indexerUrl?: string,
15
14
  governanceIndexerUrl?: string,
16
15
  lunarIndexerUrl?: string,
17
16
  ) =>
@@ -27,7 +26,6 @@ const createEnvironment = (
27
26
  transport: rpcUrls
28
27
  ? fallback(rpcUrls.map((url) => http(url)))
29
28
  : http("https://rpc.moonwell.fi/main/evm/10"),
30
- indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
31
29
  lunarIndexerUrl:
32
30
  lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
33
31
  governanceIndexerUrl:
@@ -8,7 +8,6 @@ import { tokens } from "./tokens.js";
8
8
 
9
9
  const createEnvironment = (
10
10
  rpcUrls?: string[],
11
- indexerUrl?: string,
12
11
  governanceIndexerUrl?: string,
13
12
  ): Environment<typeof tokens, {}, {}, {}, {}> =>
14
13
  createEnvironmentConfig({
@@ -23,7 +22,6 @@ const createEnvironment = (
23
22
  transport: rpcUrls
24
23
  ? fallback(rpcUrls.map((url) => http(url)))
25
24
  : http("https://rpc.moonwell.fi/main/evm/137"),
26
- indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
27
25
  governanceIndexerUrl:
28
26
  governanceIndexerUrl ||
29
27
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -147,49 +147,28 @@ export type GetEnvironment<chain> = chain extends typeof base
147
147
  export const createEnvironment = <const chain extends Chain>(config: {
148
148
  chain: chain;
149
149
  rpcUrls?: string[] | undefined;
150
- indexerUrl?: string;
151
150
  }): GetEnvironment<chain> => {
152
151
  switch (config.chain.id) {
153
152
  case base.id:
154
- return createBaseEnvironment(
155
- config.rpcUrls,
156
- config.indexerUrl,
157
- ) as GetEnvironment<chain>;
153
+ return createBaseEnvironment(config.rpcUrls) as GetEnvironment<chain>;
158
154
  case moonbeam.id:
159
- return createMoonbeamEnvironment(
160
- config.rpcUrls,
161
- config.indexerUrl,
162
- ) as GetEnvironment<chain>;
155
+ return createMoonbeamEnvironment(config.rpcUrls) as GetEnvironment<chain>;
163
156
  case moonriver.id:
164
157
  return createMoonriverEnvironment(
165
158
  config.rpcUrls,
166
- config.indexerUrl,
167
159
  ) as GetEnvironment<chain>;
168
160
  case optimism.id:
169
- return createOptimismEnvironment(
170
- config.rpcUrls,
171
- config.indexerUrl,
172
- ) as GetEnvironment<chain>;
161
+ return createOptimismEnvironment(config.rpcUrls) as GetEnvironment<chain>;
173
162
  case ethereum.id:
174
- return createEthereumEnvironment(
175
- config.rpcUrls,
176
- config.indexerUrl,
177
- ) as GetEnvironment<chain>;
163
+ return createEthereumEnvironment(config.rpcUrls) as GetEnvironment<chain>;
178
164
  case avalanche.id:
179
165
  return createAvalancheEnvironment(
180
166
  config.rpcUrls,
181
- config.indexerUrl,
182
167
  ) as GetEnvironment<chain>;
183
168
  case arbitrum.id:
184
- return createArbitrumEnvironment(
185
- config.rpcUrls,
186
- config.indexerUrl,
187
- ) as GetEnvironment<chain>;
169
+ return createArbitrumEnvironment(config.rpcUrls) as GetEnvironment<chain>;
188
170
  case polygon.id:
189
- return createPolygonEnvironment(
190
- config.rpcUrls,
191
- config.indexerUrl,
192
- ) as GetEnvironment<chain>;
171
+ return createPolygonEnvironment(config.rpcUrls) as GetEnvironment<chain>;
193
172
  default:
194
173
  throw new Error("Unsupported chainId");
195
174
  }