@moonwell-fi/moonwell-sdk 0.9.26 → 0.9.28

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 (81) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/_cjs/actions/core/markets/common.js +291 -5
  3. package/_cjs/actions/core/markets/common.js.map +1 -1
  4. package/_cjs/actions/core/markets/getMarketSnapshots.js +83 -3
  5. package/_cjs/actions/core/markets/getMarketSnapshots.js.map +1 -1
  6. package/_cjs/actions/core/user-positions/common.js +61 -1
  7. package/_cjs/actions/core/user-positions/common.js.map +1 -1
  8. package/_cjs/actions/core/user-positions/getUserPositionSnapshots.js +70 -2
  9. package/_cjs/actions/core/user-positions/getUserPositionSnapshots.js.map +1 -1
  10. package/_cjs/actions/lunar-indexer-client.js +164 -0
  11. package/_cjs/actions/lunar-indexer-client.js.map +1 -0
  12. package/_cjs/actions/lunar-indexer-transformers.js +47 -0
  13. package/_cjs/actions/lunar-indexer-transformers.js.map +1 -0
  14. package/_cjs/environments/definitions/base/environment.js +2 -1
  15. package/_cjs/environments/definitions/base/environment.js.map +1 -1
  16. package/_cjs/environments/definitions/moonbeam/environment.js +2 -1
  17. package/_cjs/environments/definitions/moonbeam/environment.js.map +1 -1
  18. package/_cjs/environments/definitions/optimism/environment.js +2 -1
  19. package/_cjs/environments/definitions/optimism/environment.js.map +1 -1
  20. package/_cjs/environments/types/config.js +1 -0
  21. package/_cjs/environments/types/config.js.map +1 -1
  22. package/_cjs/errors/version.js +1 -1
  23. package/_cjs/utils/lunar-indexer-helpers.js +27 -0
  24. package/_cjs/utils/lunar-indexer-helpers.js.map +1 -0
  25. package/_esm/actions/core/markets/common.js +302 -5
  26. package/_esm/actions/core/markets/common.js.map +1 -1
  27. package/_esm/actions/core/markets/getMarketSnapshots.js +87 -3
  28. package/_esm/actions/core/markets/getMarketSnapshots.js.map +1 -1
  29. package/_esm/actions/core/user-positions/common.js +74 -1
  30. package/_esm/actions/core/user-positions/common.js.map +1 -1
  31. package/_esm/actions/core/user-positions/getUserPositionSnapshots.js +100 -2
  32. package/_esm/actions/core/user-positions/getUserPositionSnapshots.js.map +1 -1
  33. package/_esm/actions/lunar-indexer-client.js +201 -0
  34. package/_esm/actions/lunar-indexer-client.js.map +1 -0
  35. package/_esm/actions/lunar-indexer-transformers.js +80 -0
  36. package/_esm/actions/lunar-indexer-transformers.js.map +1 -0
  37. package/_esm/environments/definitions/base/environment.js +2 -1
  38. package/_esm/environments/definitions/base/environment.js.map +1 -1
  39. package/_esm/environments/definitions/moonbeam/environment.js +2 -1
  40. package/_esm/environments/definitions/moonbeam/environment.js.map +1 -1
  41. package/_esm/environments/definitions/optimism/environment.js +2 -1
  42. package/_esm/environments/definitions/optimism/environment.js.map +1 -1
  43. package/_esm/environments/types/config.js +1 -0
  44. package/_esm/environments/types/config.js.map +1 -1
  45. package/_esm/errors/version.js +1 -1
  46. package/_esm/utils/lunar-indexer-helpers.js +48 -0
  47. package/_esm/utils/lunar-indexer-helpers.js.map +1 -0
  48. package/_types/actions/core/markets/common.d.ts.map +1 -1
  49. package/_types/actions/core/markets/getMarketSnapshots.d.ts +4 -0
  50. package/_types/actions/core/markets/getMarketSnapshots.d.ts.map +1 -1
  51. package/_types/actions/core/user-positions/common.d.ts.map +1 -1
  52. package/_types/actions/core/user-positions/getUserPositionSnapshots.d.ts +28 -0
  53. package/_types/actions/core/user-positions/getUserPositionSnapshots.d.ts.map +1 -1
  54. package/_types/actions/lunar-indexer-client.d.ts +197 -0
  55. package/_types/actions/lunar-indexer-client.d.ts.map +1 -0
  56. package/_types/actions/lunar-indexer-transformers.d.ts +40 -0
  57. package/_types/actions/lunar-indexer-transformers.d.ts.map +1 -0
  58. package/_types/environments/definitions/base/environment.d.ts +1 -1
  59. package/_types/environments/definitions/base/environment.d.ts.map +1 -1
  60. package/_types/environments/definitions/moonbeam/environment.d.ts +1 -1
  61. package/_types/environments/definitions/moonbeam/environment.d.ts.map +1 -1
  62. package/_types/environments/definitions/optimism/environment.d.ts +1 -1
  63. package/_types/environments/definitions/optimism/environment.d.ts.map +1 -1
  64. package/_types/environments/types/config.d.ts +2 -0
  65. package/_types/environments/types/config.d.ts.map +1 -1
  66. package/_types/errors/version.d.ts +1 -1
  67. package/_types/utils/lunar-indexer-helpers.d.ts +38 -0
  68. package/_types/utils/lunar-indexer-helpers.d.ts.map +1 -0
  69. package/actions/core/markets/common.ts +500 -5
  70. package/actions/core/markets/getMarketSnapshots.ts +153 -2
  71. package/actions/core/user-positions/common.ts +139 -6
  72. package/actions/core/user-positions/getUserPositionSnapshots.ts +175 -1
  73. package/actions/lunar-indexer-client.ts +409 -0
  74. package/actions/lunar-indexer-transformers.ts +113 -0
  75. package/environments/definitions/base/environment.ts +3 -0
  76. package/environments/definitions/moonbeam/environment.ts +3 -0
  77. package/environments/definitions/optimism/environment.ts +3 -0
  78. package/environments/types/config.ts +3 -0
  79. package/errors/version.ts +1 -1
  80. package/package.json +1 -1
  81. package/utils/lunar-indexer-helpers.ts +57 -0
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Lunar Indexer API Client
3
+ *
4
+ * Client for interacting with the Lunar Indexer REST API endpoints.
5
+ * Provides functions for fetching comptroller, market, token, and portfolio data.
6
+ */
7
+
8
+ import axios, { type AxiosInstance, type AxiosError } from "axios";
9
+
10
+ // ============================================================================
11
+ // Type Definitions
12
+ // ============================================================================
13
+
14
+ export interface LunarIndexerConfig {
15
+ baseUrl: string;
16
+ timeout?: number;
17
+ }
18
+
19
+ export interface LunarPaginatedResponse<T> {
20
+ results: T[];
21
+ nextCursor: string | null;
22
+ }
23
+
24
+ export interface LunarSnapshotOptions {
25
+ limit?: number;
26
+ cursor?: string;
27
+ granularity?: "15m" | "1h" | "6h" | "1d";
28
+ startTime?: number;
29
+ endTime?: number;
30
+ }
31
+
32
+ export interface LunarPortfolioOptions {
33
+ startTime: number;
34
+ endTime: number;
35
+ granularity?: "1h" | "6h" | "1d";
36
+ chainId?: number;
37
+ market?: string;
38
+ }
39
+
40
+ export interface LunarComptroller {
41
+ id: string;
42
+ chainId: number;
43
+ address: string;
44
+ priceOracleAddress: string;
45
+ }
46
+
47
+ export interface LunarMarket {
48
+ id: string;
49
+ chainId: number;
50
+ address: string;
51
+ underlyingTokenAddress: string;
52
+ collateralFactor: number;
53
+ interestRateModelAddress: string;
54
+ priceFeedAddress: string;
55
+ reserveFactor: string;
56
+ blockNumber: string;
57
+ timestamp: number;
58
+ }
59
+
60
+ /**
61
+ * Full market data with all real-time fields from Lunar Indexer
62
+ * Based on actual API responses from /markets/:chainId and /market/:marketId
63
+ */
64
+ export interface LunarMarketFull {
65
+ id: string;
66
+ chainId: number;
67
+ address: string;
68
+ underlyingTokenAddress: string;
69
+ comptrollerAddress: string;
70
+
71
+ totalBorrows: number;
72
+ totalBorrowsUsd: number;
73
+ totalSupply: number;
74
+ totalSupplyUsd: number;
75
+ totalReserves: number;
76
+ totalReservesUsd: number;
77
+ cash: number;
78
+ cashUsd: number;
79
+ badDebt: number;
80
+ badDebtUsd: number;
81
+
82
+ exchangeRate: number;
83
+ priceUsd: number;
84
+ baseSupplyApy: number;
85
+ baseBorrowApy: number;
86
+
87
+ mintPaused: boolean;
88
+ borrowPaused: boolean;
89
+ seizePaused: boolean;
90
+ transferPaused: boolean;
91
+
92
+ borrowCap: number;
93
+ supplyCap: number;
94
+
95
+ collateralFactor: number;
96
+ reserveFactor: string;
97
+
98
+ incentives: Array<{
99
+ token: string;
100
+ supplyIncentivesPerSec: string | number;
101
+ borrowIncentivesPerSec: string | number;
102
+ priceUsd: number | null;
103
+ supplyApr: number | null;
104
+ borrowApr: number | null;
105
+ }>;
106
+
107
+ underlyingToken: {
108
+ id: string;
109
+ chainId: number;
110
+ address: string;
111
+ name: string;
112
+ symbol: string;
113
+ decimals: number;
114
+ };
115
+
116
+ blockNumber: string;
117
+ timestamp: number;
118
+ }
119
+
120
+ export interface LunarMarketWithToken extends LunarMarket {
121
+ underlyingToken: LunarToken;
122
+ }
123
+
124
+ export interface LunarToken {
125
+ id: string;
126
+ chainId: number;
127
+ address: string;
128
+ name: string;
129
+ symbol: string;
130
+ decimals: number;
131
+ }
132
+
133
+ export interface LunarMarketSnapshot {
134
+ id: string;
135
+ chainId: number;
136
+ marketAddress: string;
137
+ timestamp: number;
138
+ blockNumber: string;
139
+ totalBorrows: number;
140
+ totalBorrowsUSD: number;
141
+ totalSupplies: number;
142
+ totalSuppliesUSD: number;
143
+ totalLiquidity: number;
144
+ totalLiquidityUSD: number;
145
+ totalReserves: number;
146
+ totalReservesUSD: number;
147
+ baseSupplyApy: number;
148
+ baseBorrowApy: number;
149
+ timeInterval: number;
150
+ }
151
+
152
+ export interface LunarPortfolio {
153
+ account: string;
154
+ positions: Array<{
155
+ timestamp: number;
156
+ markets: Array<{
157
+ chainId: number;
158
+ marketAddress: string;
159
+ supplyBalance: string;
160
+ supplyBalanceUsd: string;
161
+ borrowBalance: string;
162
+ borrowBalanceUsd: string;
163
+ }>;
164
+ }>;
165
+ }
166
+
167
+ // ============================================================================
168
+ // Error Handling
169
+ // ============================================================================
170
+
171
+ export class LunarIndexerError extends Error {
172
+ constructor(
173
+ message: string,
174
+ public readonly statusCode?: number,
175
+ public readonly endpoint?: string,
176
+ public readonly originalError?: Error,
177
+ ) {
178
+ super(message);
179
+ this.name = "LunarIndexerError";
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Determine if an error should trigger fallback to Ponder/on-chain
185
+ */
186
+ export function shouldFallback(error: unknown): boolean {
187
+ if (axios.isAxiosError(error)) {
188
+ const axiosError = error as AxiosError;
189
+
190
+ const isNetworkError = !axiosError.response;
191
+ const is5xxError =
192
+ !!axiosError.response && axiosError.response.status >= 500;
193
+ const is404Error =
194
+ !!axiosError.response && axiosError.response.status === 404;
195
+
196
+ if (isNetworkError || is5xxError || is404Error) {
197
+ return true;
198
+ }
199
+
200
+ // 4xx errors (except 404) should NOT fallback - fail fast
201
+ return false;
202
+ }
203
+
204
+ // Unknown errors should fallback
205
+ return true;
206
+ }
207
+
208
+ export const DEFAULT_LUNAR_TIMEOUT_MS = 10_000;
209
+
210
+ // ============================================================================
211
+ // Lunar Indexer Client Class
212
+ // ============================================================================
213
+
214
+ export class LunarIndexerClient {
215
+ private client: AxiosInstance;
216
+
217
+ constructor(config: LunarIndexerConfig) {
218
+ this.client = axios.create({
219
+ baseURL: `${config.baseUrl}/api/v1/core`,
220
+ timeout: config.timeout || DEFAULT_LUNAR_TIMEOUT_MS,
221
+ headers: {
222
+ "Content-Type": "application/json",
223
+ },
224
+ });
225
+ }
226
+
227
+ /**
228
+ * Get comptroller data for a specific chain
229
+ */
230
+ async getComptroller(chainId: number): Promise<LunarComptroller> {
231
+ try {
232
+ const response = await this.client.get<LunarComptroller>(
233
+ `/comptroller/${chainId}`,
234
+ );
235
+ return response.data;
236
+ } catch (error) {
237
+ throw new LunarIndexerError(
238
+ `Failed to fetch comptroller for chain ${chainId}`,
239
+ axios.isAxiosError(error) ? error.response?.status : undefined,
240
+ `/comptroller/${chainId}`,
241
+ error as Error,
242
+ );
243
+ }
244
+ }
245
+
246
+ /**
247
+ * List all markets for a specific chain with pagination
248
+ * Returns full market data with real-time values, APYs, and incentives
249
+ */
250
+ async listMarkets(
251
+ chainId: number,
252
+ options?: { limit?: number; cursor?: string },
253
+ ): Promise<LunarPaginatedResponse<LunarMarketFull>> {
254
+ try {
255
+ const params: Record<string, string> = {};
256
+ if (options?.limit) params.limit = options.limit.toString();
257
+ if (options?.cursor) params.cursor = options.cursor;
258
+
259
+ const response = await this.client.get<
260
+ LunarPaginatedResponse<LunarMarketFull>
261
+ >(`/markets/${chainId}`, { params });
262
+ return response.data;
263
+ } catch (error) {
264
+ throw new LunarIndexerError(
265
+ `Failed to list markets for chain ${chainId}`,
266
+ axios.isAxiosError(error) ? error.response?.status : undefined,
267
+ `/markets/${chainId}`,
268
+ error as Error,
269
+ );
270
+ }
271
+ }
272
+
273
+ /**
274
+ * Get a single market by marketId (format: chainId-marketAddress)
275
+ * Returns full market data with real-time values, APYs, and incentives
276
+ */
277
+ async getMarket(marketId: string): Promise<LunarMarketFull> {
278
+ try {
279
+ const response = await this.client.get<LunarMarketFull>(
280
+ `/market/${marketId}`,
281
+ );
282
+ return response.data;
283
+ } catch (error) {
284
+ throw new LunarIndexerError(
285
+ `Failed to fetch market ${marketId}`,
286
+ axios.isAxiosError(error) ? error.response?.status : undefined,
287
+ `/market/${marketId}`,
288
+ error as Error,
289
+ );
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Get market snapshots with optional time range and granularity
295
+ */
296
+ async getMarketSnapshots(
297
+ marketId: string,
298
+ options?: LunarSnapshotOptions,
299
+ ): Promise<LunarPaginatedResponse<LunarMarketSnapshot>> {
300
+ try {
301
+ const params: Record<string, string> = {};
302
+ if (options?.limit) params.limit = options.limit.toString();
303
+ if (options?.cursor) params.cursor = options.cursor;
304
+ if (options?.granularity) params.granularity = options.granularity;
305
+ if (options?.startTime) params.startTime = options.startTime.toString();
306
+ if (options?.endTime) params.endTime = options.endTime.toString();
307
+
308
+ const response = await this.client.get<
309
+ LunarPaginatedResponse<LunarMarketSnapshot>
310
+ >(`/market/${marketId}/snapshots`, { params });
311
+ return response.data;
312
+ } catch (error) {
313
+ throw new LunarIndexerError(
314
+ `Failed to fetch market snapshots for ${marketId}`,
315
+ axios.isAxiosError(error) ? error.response?.status : undefined,
316
+ `/market/${marketId}/snapshots`,
317
+ error as Error,
318
+ );
319
+ }
320
+ }
321
+
322
+ /**
323
+ * List all tokens for a specific chain with pagination
324
+ */
325
+ async listTokens(
326
+ chainId: number,
327
+ options?: { limit?: number; cursor?: string },
328
+ ): Promise<LunarPaginatedResponse<LunarToken>> {
329
+ try {
330
+ const params: Record<string, string> = {};
331
+ if (options?.limit) params.limit = options.limit.toString();
332
+ if (options?.cursor) params.cursor = options.cursor;
333
+
334
+ const response = await this.client.get<
335
+ LunarPaginatedResponse<LunarToken>
336
+ >(`/tokens/${chainId}`, { params });
337
+ return response.data;
338
+ } catch (error) {
339
+ throw new LunarIndexerError(
340
+ `Failed to list tokens for chain ${chainId}`,
341
+ axios.isAxiosError(error) ? error.response?.status : undefined,
342
+ `/tokens/${chainId}`,
343
+ error as Error,
344
+ );
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Get a single token by tokenId (format: chainId-tokenAddress)
350
+ */
351
+ async getToken(tokenId: string): Promise<LunarToken> {
352
+ try {
353
+ const response = await this.client.get<LunarToken>(`/token/${tokenId}`);
354
+ return response.data;
355
+ } catch (error) {
356
+ throw new LunarIndexerError(
357
+ `Failed to fetch token ${tokenId}`,
358
+ axios.isAxiosError(error) ? error.response?.status : undefined,
359
+ `/token/${tokenId}`,
360
+ error as Error,
361
+ );
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Get account portfolio with historical positions
367
+ * NOTE: USD fields (supplyBalanceUsd, borrowBalanceUsd) are being added by Lunar team
368
+ */
369
+ async getAccountPortfolio(
370
+ accountAddress: string,
371
+ options: LunarPortfolioOptions,
372
+ ): Promise<LunarPortfolio> {
373
+ try {
374
+ const params: Record<string, string> = {
375
+ startTime: options.startTime.toString(),
376
+ endTime: options.endTime.toString(),
377
+ };
378
+ if (options.granularity) params.granularity = options.granularity;
379
+ if (options.chainId) params.chainId = options.chainId.toString();
380
+ if (options.market) params.market = options.market;
381
+
382
+ const response = await this.client.get<LunarPortfolio>(
383
+ `/account/${accountAddress.toLowerCase()}/portfolio`,
384
+ { params },
385
+ );
386
+ return response.data;
387
+ } catch (error) {
388
+ throw new LunarIndexerError(
389
+ `Failed to fetch portfolio for account ${accountAddress}`,
390
+ axios.isAxiosError(error) ? error.response?.status : undefined,
391
+ `/account/${accountAddress}/portfolio`,
392
+ error as Error,
393
+ );
394
+ }
395
+ }
396
+ }
397
+
398
+ // ============================================================================
399
+ // Factory Function
400
+ // ============================================================================
401
+
402
+ /**
403
+ * Create a new Lunar Indexer client instance
404
+ */
405
+ export function createLunarIndexerClient(
406
+ config: LunarIndexerConfig,
407
+ ): LunarIndexerClient {
408
+ return new LunarIndexerClient(config);
409
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Lunar Indexer Response Transformers
3
+ *
4
+ * Transforms Lunar Indexer API responses to match the SDK's internal types.
5
+ */
6
+
7
+ import type { MarketSnapshot } from "../types/market.js";
8
+ import type { UserPositionSnapshot } from "../types/userPosition.js";
9
+ import type {
10
+ LunarMarketSnapshot,
11
+ LunarPortfolio,
12
+ } from "./lunar-indexer-client.js";
13
+
14
+ // ============================================================================
15
+ // Market Snapshot Transformation
16
+ // ============================================================================
17
+
18
+ /**
19
+ * Transform a Lunar market snapshot to SDK MarketSnapshot format
20
+ *
21
+ * Key differences:
22
+ * - Lunar uses decimal numbers, SDK uses numbers
23
+ * - Lunar has timeInterval field (not needed in SDK)
24
+ * - Field name mapping: totalSupplies → totalSupply, totalBorrows → totalBorrows
25
+ */
26
+ export function transformMarketSnapshot(
27
+ lunar: LunarMarketSnapshot,
28
+ chainId: number,
29
+ ): MarketSnapshot {
30
+ return {
31
+ chainId,
32
+ marketId: lunar.marketAddress,
33
+ totalSupply: Number(lunar.totalSupplies),
34
+ totalSupplyUsd: Number(lunar.totalSuppliesUSD),
35
+ totalBorrows: Number(lunar.totalBorrows),
36
+ totalBorrowsUsd: Number(lunar.totalBorrowsUSD),
37
+ totalLiquidity: Number(lunar.totalLiquidity),
38
+ totalLiquidityUsd: Number(lunar.totalLiquidityUSD),
39
+ baseSupplyApy: Number(lunar.baseSupplyApy),
40
+ baseBorrowApy: Number(lunar.baseBorrowApy),
41
+ timestamp: Number(lunar.timestamp) * 1000, // Convert unix timestamp to milliseconds
42
+ loanTokenPrice: 0, // Calculated in getMarketSnapshots
43
+ collateralTokenPrice: 0, // Calculated in getMarketSnapshots
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Transform an array of Lunar market snapshots
49
+ */
50
+ export function transformMarketSnapshots(
51
+ snapshots: LunarMarketSnapshot[],
52
+ chainId: number,
53
+ ): MarketSnapshot[] {
54
+ return snapshots.map((snapshot) =>
55
+ transformMarketSnapshot(snapshot, chainId),
56
+ );
57
+ }
58
+
59
+ // ============================================================================
60
+ // Portfolio/User Position Transformation
61
+ // ============================================================================
62
+
63
+ /**
64
+ * Transform Lunar portfolio to SDK UserPositionSnapshot array
65
+ *
66
+ * Key transformation:
67
+ * - Aggregate per-market USD balances across all markets per timestamp
68
+ * - Sum supplyBalanceUsd → totalSupplyUsd
69
+ * - Sum borrowBalanceUsd → totalBorrowsUsd
70
+ * - Assume totalCollateralUsd = totalSupplyUsd (all supplies are collateral)
71
+ */
72
+ export function transformPortfolioToSnapshots(
73
+ lunarPortfolio: LunarPortfolio,
74
+ chainId: number,
75
+ ): UserPositionSnapshot[] {
76
+ return lunarPortfolio.positions.map((position) => {
77
+ const totalSupplyUsd = position.markets.reduce(
78
+ (sum, market) => sum + Number.parseFloat(market.supplyBalanceUsd || "0"),
79
+ 0,
80
+ );
81
+
82
+ const totalBorrowsUsd = position.markets.reduce(
83
+ (sum, market) => sum + Number.parseFloat(market.borrowBalanceUsd || "0"),
84
+ 0,
85
+ );
86
+
87
+ return {
88
+ chainId,
89
+ timestamp: position.timestamp * 1000, // Convert unix timestamp (seconds) to milliseconds
90
+ totalSupplyUsd,
91
+ totalBorrowsUsd,
92
+ totalCollateralUsd: totalSupplyUsd, // Assuming all supplies are collateral
93
+ };
94
+ });
95
+ }
96
+
97
+ // ============================================================================
98
+ // Pagination Transformation
99
+ // ============================================================================
100
+
101
+ /**
102
+ * Check if there are more pages available
103
+ */
104
+ export function hasMorePages(nextCursor: string | null): boolean {
105
+ return nextCursor !== null;
106
+ }
107
+
108
+ /**
109
+ * Extract cursor for next page
110
+ */
111
+ export function getNextCursor(nextCursor: string | null): string | undefined {
112
+ return nextCursor || undefined;
113
+ }
@@ -17,6 +17,7 @@ const createEnvironment = (
17
17
  rpcUrls?: string[],
18
18
  indexerUrl?: string,
19
19
  governanceIndexerUrl?: string,
20
+ lunarIndexerUrl?: string,
20
21
  ): Environment<
21
22
  typeof tokens,
22
23
  typeof markets,
@@ -40,6 +41,8 @@ const createEnvironment = (
40
41
  governanceIndexerUrl:
41
42
  governanceIndexerUrl ||
42
43
  "https://lunar-services-worker.moonwell.workers.dev",
44
+ lunarIndexerUrl:
45
+ lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
43
46
  tokens,
44
47
  markets,
45
48
  vaults,
@@ -10,6 +10,7 @@ const createEnvironment = (
10
10
  rpcUrls?: string[],
11
11
  indexerUrl?: string,
12
12
  governanceIndexerUrl?: string,
13
+ lunarIndexerUrl?: string,
13
14
  ) =>
14
15
  createEnvironmentConfig({
15
16
  key: "moonbeam",
@@ -24,6 +25,8 @@ const createEnvironment = (
24
25
  ? fallback(rpcUrls.map((url) => http(url)))
25
26
  : http("https://rpc.moonwell.fi/main/evm/1284"),
26
27
  indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
28
+ lunarIndexerUrl:
29
+ lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
27
30
  governanceIndexerUrl:
28
31
  governanceIndexerUrl ||
29
32
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -13,6 +13,7 @@ const createEnvironment = (
13
13
  rpcUrls?: string[],
14
14
  indexerUrl?: string,
15
15
  governanceIndexerUrl?: string,
16
+ lunarIndexerUrl?: string,
16
17
  ) =>
17
18
  createEnvironmentConfig({
18
19
  key: "optimism",
@@ -27,6 +28,8 @@ const createEnvironment = (
27
28
  ? fallback(rpcUrls.map((url) => http(url)))
28
29
  : http("https://rpc.moonwell.fi/main/evm/10"),
29
30
  indexerUrl: indexerUrl || "https://ponder.moonwell.fi",
31
+ lunarIndexerUrl:
32
+ lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
30
33
  governanceIndexerUrl:
31
34
  governanceIndexerUrl ||
32
35
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -231,6 +231,7 @@ export const createEnvironmentConfig = <
231
231
  transport: Transport;
232
232
  indexerUrl: string;
233
233
  governanceIndexerUrl: string;
234
+ lunarIndexerUrl?: string;
234
235
  tokens: TokensConfig<tokens>;
235
236
  markets: MarketsConfig<markets, tokens>;
236
237
  vaults: VaultsConfig<vaults, tokens>;
@@ -494,6 +495,7 @@ export const createEnvironmentConfig = <
494
495
  chain: config.chain,
495
496
  indexerUrl: config.indexerUrl,
496
497
  governanceIndexerUrl: config.governanceIndexerUrl,
498
+ lunarIndexerUrl: config.lunarIndexerUrl,
497
499
  tokens: tokenContracts,
498
500
  markets: marketContracts,
499
501
  vaults: vaultsContracts,
@@ -531,6 +533,7 @@ export type Environment<
531
533
  chain: Chain;
532
534
  indexerUrl: string;
533
535
  governanceIndexerUrl: string;
536
+ lunarIndexerUrl?: string;
534
537
  tokens: {
535
538
  [name in keyof tokens]: TokenContractReturnType;
536
539
  };
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.9.26'
1
+ export const version = '0.9.28'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@moonwell-fi/moonwell-sdk",
3
3
  "description": "TypeScript Interface for Moonwell",
4
- "version": "0.9.26",
4
+ "version": "0.9.28",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Helper functions for working with Lunar Indexer marketId and tokenId formats
3
+ */
4
+
5
+ /**
6
+ * Build a marketId string from chainId and market address
7
+ * Format: {chainId}-{marketAddress}
8
+ * @param chainId - The chain ID
9
+ * @param marketAddress - The market contract address
10
+ * @returns Formatted marketId string
11
+ */
12
+ export function buildMarketId(chainId: number, marketAddress: string): string {
13
+ return `${chainId}-${marketAddress.toLowerCase()}`;
14
+ }
15
+
16
+ /**
17
+ * Parse a marketId string into chainId and marketAddress
18
+ * @param marketId - The marketId string to parse
19
+ * @returns Object containing chainId and marketAddress
20
+ */
21
+ export function parseMarketId(marketId: string): {
22
+ chainId: number;
23
+ marketAddress: string;
24
+ } {
25
+ const [chainIdStr, ...addressParts] = marketId.split("-");
26
+ return {
27
+ chainId: Number.parseInt(chainIdStr, 10),
28
+ marketAddress: addressParts.join("-"), // Handle addresses that might contain dashes
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Build a tokenId string from chainId and token address
34
+ * Format: {chainId}-{tokenAddress}
35
+ * @param chainId - The chain ID
36
+ * @param tokenAddress - The token contract address
37
+ * @returns Formatted tokenId string
38
+ */
39
+ export function buildTokenId(chainId: number, tokenAddress: string): string {
40
+ return `${chainId}-${tokenAddress.toLowerCase()}`;
41
+ }
42
+
43
+ /**
44
+ * Parse a tokenId string into chainId and tokenAddress
45
+ * @param tokenId - The tokenId string to parse
46
+ * @returns Object containing chainId and tokenAddress
47
+ */
48
+ export function parseTokenId(tokenId: string): {
49
+ chainId: number;
50
+ tokenAddress: string;
51
+ } {
52
+ const [chainIdStr, ...addressParts] = tokenId.split("-");
53
+ return {
54
+ chainId: Number.parseInt(chainIdStr, 10),
55
+ tokenAddress: addressParts.join("-"), // Handle addresses that might contain dashes
56
+ };
57
+ }