@moonwell-fi/moonwell-sdk 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/_cjs/actions/axiosWithRetry.js +10 -11
  3. package/_cjs/actions/axiosWithRetry.js.map +1 -1
  4. package/_cjs/actions/core/getUserBalances.js +63 -32
  5. package/_cjs/actions/core/getUserBalances.js.map +1 -1
  6. package/_cjs/actions/core/markets/common.js +31 -42
  7. package/_cjs/actions/core/markets/common.js.map +1 -1
  8. package/_cjs/actions/core/markets/getMarkets.js +7 -3
  9. package/_cjs/actions/core/markets/getMarkets.js.map +1 -1
  10. package/_cjs/actions/core/user-positions/common.js +56 -60
  11. package/_cjs/actions/core/user-positions/common.js.map +1 -1
  12. package/_cjs/actions/core/user-positions/getUserPositions.js +9 -6
  13. package/_cjs/actions/core/user-positions/getUserPositions.js.map +1 -1
  14. package/_cjs/actions/governance/getStakingInfo.js +1 -7
  15. package/_cjs/actions/governance/getStakingInfo.js.map +1 -1
  16. package/_cjs/actions/governance/getUserStakingInfo.js +1 -7
  17. package/_cjs/actions/governance/getUserStakingInfo.js.map +1 -1
  18. package/_cjs/actions/governance/getWellPrice.js +51 -1
  19. package/_cjs/actions/governance/getWellPrice.js.map +1 -1
  20. package/_cjs/actions/governance/proposals/common.js +34 -15
  21. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  22. package/_cjs/actions/governance/proposals/getProposals.js +5 -4
  23. package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
  24. package/_cjs/actions/index.js +3 -1
  25. package/_cjs/actions/index.js.map +1 -1
  26. package/_cjs/actions/morpho/markets/common.js +155 -26
  27. package/_cjs/actions/morpho/markets/common.js.map +1 -1
  28. package/_cjs/actions/morpho/markets/getMorphoMarket.js +1 -0
  29. package/_cjs/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  30. package/_cjs/actions/morpho/markets/getMorphoMarkets.js +1 -0
  31. package/_cjs/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  32. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +46 -0
  33. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  34. package/_cjs/actions/morpho/user-positions/common.js +26 -24
  35. package/_cjs/actions/morpho/user-positions/common.js.map +1 -1
  36. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js +7 -8
  37. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  38. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js +7 -8
  39. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  40. package/_cjs/actions/morpho/user-rewards/common.js +1 -7
  41. package/_cjs/actions/morpho/user-rewards/common.js.map +1 -1
  42. package/_cjs/actions/morpho/vaults/common.js +104 -87
  43. package/_cjs/actions/morpho/vaults/common.js.map +1 -1
  44. package/_cjs/actions/morpho/vaults/lunarIndexerTransform.js +31 -3
  45. package/_cjs/actions/morpho/vaults/lunarIndexerTransform.js.map +1 -1
  46. package/_cjs/actions/retry.js +43 -13
  47. package/_cjs/actions/retry.js.map +1 -1
  48. package/_cjs/client/createActions.js +2 -0
  49. package/_cjs/client/createActions.js.map +1 -1
  50. package/_cjs/common/error.js +37 -1
  51. package/_cjs/common/error.js.map +1 -1
  52. package/_cjs/common/index.js +2 -1
  53. package/_cjs/common/index.js.map +1 -1
  54. package/_cjs/common/readAcrossEnvironments.js +17 -0
  55. package/_cjs/common/readAcrossEnvironments.js.map +1 -0
  56. package/_cjs/environments/types/config.js.map +1 -1
  57. package/_cjs/errors/version.js +1 -1
  58. package/_cjs/index.js +3 -1
  59. package/_cjs/index.js.map +1 -1
  60. package/_esm/actions/axiosWithRetry.js +11 -13
  61. package/_esm/actions/axiosWithRetry.js.map +1 -1
  62. package/_esm/actions/core/getUserBalances.js +72 -35
  63. package/_esm/actions/core/getUserBalances.js.map +1 -1
  64. package/_esm/actions/core/markets/common.js +36 -43
  65. package/_esm/actions/core/markets/common.js.map +1 -1
  66. package/_esm/actions/core/markets/getMarkets.js +7 -3
  67. package/_esm/actions/core/markets/getMarkets.js.map +1 -1
  68. package/_esm/actions/core/user-positions/common.js +65 -63
  69. package/_esm/actions/core/user-positions/common.js.map +1 -1
  70. package/_esm/actions/core/user-positions/getUserPositions.js +14 -6
  71. package/_esm/actions/core/user-positions/getUserPositions.js.map +1 -1
  72. package/_esm/actions/governance/getStakingInfo.js +2 -8
  73. package/_esm/actions/governance/getStakingInfo.js.map +1 -1
  74. package/_esm/actions/governance/getUserStakingInfo.js +2 -8
  75. package/_esm/actions/governance/getUserStakingInfo.js.map +1 -1
  76. package/_esm/actions/governance/getWellPrice.js +67 -7
  77. package/_esm/actions/governance/getWellPrice.js.map +1 -1
  78. package/_esm/actions/governance/proposals/common.js +37 -12
  79. package/_esm/actions/governance/proposals/common.js.map +1 -1
  80. package/_esm/actions/governance/proposals/getProposals.js +7 -5
  81. package/_esm/actions/governance/proposals/getProposals.js.map +1 -1
  82. package/_esm/actions/index.js +1 -0
  83. package/_esm/actions/index.js.map +1 -1
  84. package/_esm/actions/morpho/markets/common.js +168 -27
  85. package/_esm/actions/morpho/markets/common.js.map +1 -1
  86. package/_esm/actions/morpho/markets/getMorphoMarket.js +1 -0
  87. package/_esm/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  88. package/_esm/actions/morpho/markets/getMorphoMarkets.js +1 -0
  89. package/_esm/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  90. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +48 -0
  91. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  92. package/_esm/actions/morpho/user-positions/common.js +31 -24
  93. package/_esm/actions/morpho/user-positions/common.js.map +1 -1
  94. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js +12 -8
  95. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  96. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js +12 -8
  97. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  98. package/_esm/actions/morpho/user-rewards/common.js +2 -8
  99. package/_esm/actions/morpho/user-rewards/common.js.map +1 -1
  100. package/_esm/actions/morpho/vaults/common.js +110 -91
  101. package/_esm/actions/morpho/vaults/common.js.map +1 -1
  102. package/_esm/actions/morpho/vaults/lunarIndexerTransform.js +36 -4
  103. package/_esm/actions/morpho/vaults/lunarIndexerTransform.js.map +1 -1
  104. package/_esm/actions/retry.js +45 -15
  105. package/_esm/actions/retry.js.map +1 -1
  106. package/_esm/client/createActions.js +2 -0
  107. package/_esm/client/createActions.js.map +1 -1
  108. package/_esm/common/error.js +49 -0
  109. package/_esm/common/error.js.map +1 -1
  110. package/_esm/common/index.js +1 -1
  111. package/_esm/common/index.js.map +1 -1
  112. package/_esm/common/readAcrossEnvironments.js +30 -0
  113. package/_esm/common/readAcrossEnvironments.js.map +1 -0
  114. package/_esm/environments/types/config.js.map +1 -1
  115. package/_esm/errors/version.js +1 -1
  116. package/_esm/index.js +1 -0
  117. package/_esm/index.js.map +1 -1
  118. package/_types/actions/axiosWithRetry.d.ts +1 -0
  119. package/_types/actions/axiosWithRetry.d.ts.map +1 -1
  120. package/_types/actions/core/getUserBalances.d.ts.map +1 -1
  121. package/_types/actions/core/markets/common.d.ts.map +1 -1
  122. package/_types/actions/core/markets/getMarkets.d.ts.map +1 -1
  123. package/_types/actions/core/user-positions/common.d.ts.map +1 -1
  124. package/_types/actions/core/user-positions/getUserPositions.d.ts +5 -0
  125. package/_types/actions/core/user-positions/getUserPositions.d.ts.map +1 -1
  126. package/_types/actions/governance/getStakingInfo.d.ts.map +1 -1
  127. package/_types/actions/governance/getUserStakingInfo.d.ts.map +1 -1
  128. package/_types/actions/governance/getWellPrice.d.ts +9 -1
  129. package/_types/actions/governance/getWellPrice.d.ts.map +1 -1
  130. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  131. package/_types/actions/governance/proposals/getProposals.d.ts +10 -1
  132. package/_types/actions/governance/proposals/getProposals.d.ts.map +1 -1
  133. package/_types/actions/index.d.ts +1 -0
  134. package/_types/actions/index.d.ts.map +1 -1
  135. package/_types/actions/morpho/markets/common.d.ts +7 -10
  136. package/_types/actions/morpho/markets/common.d.ts.map +1 -1
  137. package/_types/actions/morpho/markets/getMorphoMarket.d.ts +2 -0
  138. package/_types/actions/morpho/markets/getMorphoMarket.d.ts.map +1 -1
  139. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts +2 -0
  140. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts.map +1 -1
  141. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts +17 -0
  142. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts.map +1 -0
  143. package/_types/actions/morpho/user-positions/common.d.ts.map +1 -1
  144. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts +5 -0
  145. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts.map +1 -1
  146. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts +5 -0
  147. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts.map +1 -1
  148. package/_types/actions/morpho/user-rewards/common.d.ts.map +1 -1
  149. package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
  150. package/_types/actions/morpho/vaults/lunarIndexerTransform.d.ts.map +1 -1
  151. package/_types/actions/retry.d.ts +5 -4
  152. package/_types/actions/retry.d.ts.map +1 -1
  153. package/_types/client/createActions.d.ts +2 -0
  154. package/_types/client/createActions.d.ts.map +1 -1
  155. package/_types/common/error.d.ts +31 -0
  156. package/_types/common/error.d.ts.map +1 -1
  157. package/_types/common/index.d.ts +2 -2
  158. package/_types/common/index.d.ts.map +1 -1
  159. package/_types/common/readAcrossEnvironments.d.ts +23 -0
  160. package/_types/common/readAcrossEnvironments.d.ts.map +1 -0
  161. package/_types/environments/types/config.d.ts +11 -1
  162. package/_types/environments/types/config.d.ts.map +1 -1
  163. package/_types/errors/version.d.ts +1 -1
  164. package/_types/index.d.ts +3 -1
  165. package/_types/index.d.ts.map +1 -1
  166. package/_types/types/morphoMarket.d.ts +9 -0
  167. package/_types/types/morphoMarket.d.ts.map +1 -1
  168. package/actions/axiosWithRetry.ts +19 -13
  169. package/actions/core/getUserBalances.ts +98 -51
  170. package/actions/core/markets/common.ts +49 -51
  171. package/actions/core/markets/getMarkets.ts +9 -5
  172. package/actions/core/user-positions/common.ts +107 -111
  173. package/actions/core/user-positions/getUserPositions.ts +11 -10
  174. package/actions/governance/getStakingInfo.ts +2 -9
  175. package/actions/governance/getUserStakingInfo.ts +2 -8
  176. package/actions/governance/getWellPrice.ts +99 -7
  177. package/actions/governance/proposals/common.ts +44 -19
  178. package/actions/governance/proposals/getProposals.ts +22 -5
  179. package/actions/index.ts +5 -0
  180. package/actions/morpho/markets/common.ts +324 -125
  181. package/actions/morpho/markets/getMorphoMarket.ts +3 -0
  182. package/actions/morpho/markets/getMorphoMarkets.ts +3 -0
  183. package/actions/morpho/markets/getMorphoMarketsSharedLiquidity.ts +93 -0
  184. package/actions/morpho/user-positions/common.ts +48 -42
  185. package/actions/morpho/user-positions/getMorphoMarketUserPositions.ts +14 -15
  186. package/actions/morpho/user-positions/getMorphoVaultUserPositions.ts +14 -15
  187. package/actions/morpho/user-rewards/common.ts +2 -8
  188. package/actions/morpho/vaults/common.ts +161 -127
  189. package/actions/morpho/vaults/lunarIndexerTransform.ts +41 -6
  190. package/actions/retry.ts +53 -18
  191. package/client/createActions.ts +13 -0
  192. package/common/error.ts +45 -0
  193. package/common/index.ts +2 -2
  194. package/common/readAcrossEnvironments.ts +45 -0
  195. package/environments/types/config.ts +11 -1
  196. package/errors/version.ts +1 -1
  197. package/index.ts +3 -0
  198. package/package.json +1 -1
  199. package/types/morphoMarket.ts +10 -0
@@ -4,6 +4,7 @@ import type { MultichainReturnType } from "../../../common/types.js";
4
4
  import type { Environment } from "../../../environments/index.js";
5
5
  import type {
6
6
  MorphoMarket,
7
+ MorphoMarketSharedLiquidity,
7
8
  PublicAllocatorSharedLiquidityType,
8
9
  } from "../../../types/morphoMarket.js";
9
10
  import type { MorphoReward } from "../../../types/morphoReward.js";
@@ -45,14 +46,164 @@ export interface LunarSharedLiquidityResponse {
45
46
  markets: Record<string, LunarMarketLiveData>;
46
47
  }
47
48
 
48
- async function fetchSharedLiquidityFromLunar(
49
+ function parseLiquidityQuantity(
50
+ value: unknown,
51
+ field: string,
52
+ raw = false,
53
+ ): number {
54
+ // Raw uint quantities routinely exceed Number.MAX_SAFE_INTEGER. Validate the
55
+ // integer string, not its safe-integer range; keep the existing numeric units.
56
+ const pattern = raw ? /^\d+$/ : /^(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
57
+ if (typeof value !== "string" || !pattern.test(value)) {
58
+ throw new TypeError(`Invalid shared-liquidity quantity: ${field}`);
59
+ }
60
+ const quantity = Number(value);
61
+ if (!Number.isFinite(quantity)) {
62
+ throw new TypeError(`Invalid shared-liquidity quantity: ${field}`);
63
+ }
64
+ return quantity;
65
+ }
66
+
67
+ function validateLoanDecimals(value: unknown): number {
68
+ if (
69
+ typeof value !== "number" ||
70
+ !Number.isInteger(value) ||
71
+ value < 0 ||
72
+ value > 255
73
+ ) {
74
+ throw new TypeError("Invalid shared-liquidity loan token decimals");
75
+ }
76
+ return value;
77
+ }
78
+
79
+ /** Summarizes an unexpected top-level body so the error says what arrived. */
80
+ function describeSharedLiquidityBody(data: unknown): string {
81
+ if (data === null || data === undefined) return `received ${data}`;
82
+ if (typeof data === "string") {
83
+ return `received string of ${data.length} chars: ${JSON.stringify(data.slice(0, 100))}`;
84
+ }
85
+ if (typeof data !== "object") return `received ${typeof data}`;
86
+ if (Array.isArray(data)) return `received array of ${data.length}`;
87
+ const body = data as Record<string, unknown>;
88
+ const kind = (value: unknown): string =>
89
+ Array.isArray(value) ? "array" : value === null ? "null" : typeof value;
90
+ const keys = Object.keys(body).slice(0, 10).join(", ");
91
+ return `received object with keys [${keys}]; vaults: ${kind(body.vaults)}, markets: ${kind(body.markets)}`;
92
+ }
93
+
94
+ function validatedMarketLiquidity(
95
+ data: LunarSharedLiquidityResponse,
96
+ ): Map<string, number> {
97
+ if (
98
+ !data ||
99
+ !Array.isArray(data.vaults) ||
100
+ !data.markets ||
101
+ typeof data.markets !== "object" ||
102
+ Array.isArray(data.markets)
103
+ ) {
104
+ throw new TypeError(
105
+ `Invalid shared-liquidity response (${describeSharedLiquidityBody(data)})`,
106
+ );
107
+ }
108
+ for (const vault of data.vaults) {
109
+ parseLiquidityQuantity(vault.fee, "vault.fee", true);
110
+ for (const market of vault.markets) {
111
+ for (const field of [
112
+ "flowCapIn",
113
+ "flowCapOut",
114
+ "supplyCap",
115
+ "vaultSupplyShares",
116
+ "vaultSupplyAssets",
117
+ ] as const) {
118
+ parseLiquidityQuantity(
119
+ market[field],
120
+ `${market.marketId}.${field}`,
121
+ true,
122
+ );
123
+ }
124
+ if (typeof market.supplyCapEnabled !== "boolean") {
125
+ throw new TypeError("Invalid shared-liquidity supplyCapEnabled");
126
+ }
127
+ }
128
+ }
129
+ return new Map(
130
+ Object.entries(data.markets).map(([marketId, market]) => {
131
+ if (market.loanToken !== undefined) {
132
+ validateLoanDecimals(market.loanToken.decimals);
133
+ }
134
+ for (const field of ["totalSupplyAssets", "totalBorrowAssets"] as const) {
135
+ if (market[field] !== undefined) {
136
+ parseLiquidityQuantity(market[field], `${marketId}.${field}`);
137
+ }
138
+ }
139
+ const liquidity =
140
+ market.totalLiquidity !== undefined
141
+ ? parseLiquidityQuantity(
142
+ market.totalLiquidity,
143
+ `${marketId}.totalLiquidity`,
144
+ )
145
+ : parseLiquidityQuantity(
146
+ market.totalSupplyAssets,
147
+ `${marketId}.totalSupplyAssets`,
148
+ ) -
149
+ parseLiquidityQuantity(
150
+ market.totalBorrowAssets,
151
+ `${marketId}.totalBorrowAssets`,
152
+ );
153
+ if (liquidity < 0) {
154
+ throw new TypeError(`Negative shared liquidity for ${marketId}`);
155
+ }
156
+ return [marketId, liquidity];
157
+ }),
158
+ );
159
+ }
160
+
161
+ export async function fetchSharedLiquidityFromLunar(
49
162
  lunarIndexerUrl: string,
50
163
  chainId: number,
164
+ options: { signal?: AbortSignal; timeoutMs?: number } = {},
51
165
  ): Promise<LunarSharedLiquidityResponse> {
52
- const response = await getWithRetry<LunarSharedLiquidityResponse>(
53
- `${lunarIndexerUrl}/api/v1/isolated/shared-liquidity/${chainId}`,
54
- );
55
- return response.data;
166
+ // One budget for the request AND its retries. The endpoint often takes more
167
+ // than five seconds, so let it finish instead of restarting the same work.
168
+ const timeoutMs = options.timeoutMs ?? 15_000;
169
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
170
+ throw new RangeError(
171
+ "Shared-liquidity timeoutMs must be positive and finite",
172
+ );
173
+ }
174
+ const controller = new AbortController();
175
+ const abort = (): void => controller.abort();
176
+ if (options.signal?.aborted) abort();
177
+ options.signal?.addEventListener("abort", abort, { once: true });
178
+ let timedOut = false;
179
+ const timer = setTimeout(() => {
180
+ timedOut = true;
181
+ abort();
182
+ }, timeoutMs);
183
+ try {
184
+ const response = await getWithRetry<LunarSharedLiquidityResponse>(
185
+ `${lunarIndexerUrl}/api/v1/isolated/shared-liquidity/${chainId}`,
186
+ { timeout: timeoutMs, signal: controller.signal },
187
+ );
188
+ return response.data;
189
+ } catch (error) {
190
+ // Our own deadline aborts the request, which axios reports as a bare
191
+ // `CanceledError: canceled` (Sentry MOONWELL-FRONTEND-1C7 & co). That is a
192
+ // timeout, not a cancellation: surface it as one. A caller's own abort
193
+ // still propagates as the CanceledError it is.
194
+ if (timedOut && !options.signal?.aborted) {
195
+ const timeoutError = new Error(
196
+ `Shared-liquidity request timed out after ${timeoutMs}ms (chainId=${chainId})`,
197
+ { cause: error },
198
+ );
199
+ timeoutError.name = "TimeoutError";
200
+ throw timeoutError;
201
+ }
202
+ throw error;
203
+ } finally {
204
+ clearTimeout(timer);
205
+ options.signal?.removeEventListener("abort", abort);
206
+ }
56
207
  }
57
208
 
58
209
  export function computeSharedLiquidityFromLunar(
@@ -69,7 +220,9 @@ export function computeSharedLiquidityFromLunar(
69
220
  }
70
221
  >,
71
222
  chainId: number,
72
- ): GetMorphoMarketsPublicAllocatorSharedLiquidityReturnType[] {
223
+ ): MorphoMarketSharedLiquidity[] {
224
+ // Validate the complete response before building any successful allocations.
225
+ const liquidityByMarket = validatedMarketLiquidity(data);
73
226
  return targetMarkets.map((targetMarket) => {
74
227
  const targetId = targetMarket.toLowerCase();
75
228
  const r: PublicAllocatorSharedLiquidityType[] = [];
@@ -83,10 +236,11 @@ export function computeSharedLiquidityFromLunar(
83
236
  // (wei-like). Markets data (totalSupplyAssets, totalBorrowAssets, totalLiquidity)
84
237
  // is already in token units (divided by decimals). We convert vault raw values
85
238
  // to token units using the loan token decimals before comparing.
86
- const targetLoanDecimals =
239
+ const targetLoanDecimals = validateLoanDecimals(
87
240
  targetLiveData?.loanToken?.decimals ??
88
- targetParams?.loanToken.decimals ??
89
- 18;
241
+ targetParams?.loanToken.decimals ??
242
+ 18,
243
+ );
90
244
  const targetScale = 10 ** targetLoanDecimals;
91
245
 
92
246
  for (const vault of data.vaults) {
@@ -135,25 +289,25 @@ export function computeSharedLiquidityFromLunar(
135
289
 
136
290
  const sourceLiveData =
137
291
  data.markets[sourceMarket.marketId.toLowerCase()];
138
- if (!sourceLiveData) continue;
292
+ const liquidity = liquidityByMarket.get(
293
+ sourceMarket.marketId.toLowerCase(),
294
+ );
295
+ // The indexer can omit an entire source record. Preserve that existing
296
+ // skip behavior; quantities in every returned record were validated above.
297
+ if (!sourceLiveData || liquidity === undefined) continue;
139
298
 
140
- const sourceLoanDecimals =
299
+ const sourceLoanDecimals = validateLoanDecimals(
141
300
  sourceLiveData.loanToken?.decimals ??
142
- marketParamsMap.get(sourceMarket.marketId.toLowerCase())?.loanToken
143
- .decimals ??
144
- 18;
301
+ marketParamsMap.get(sourceMarket.marketId.toLowerCase())?.loanToken
302
+ .decimals ??
303
+ 18,
304
+ );
145
305
  const sourceScale = 10 ** sourceLoanDecimals;
146
306
 
147
307
  const vaultSupplyInSource =
148
308
  Number(sourceMarket.vaultSupplyAssets) / sourceScale;
149
309
  const maxOut = Number(sourceMarket.flowCapOut) / sourceScale;
150
310
 
151
- // Use pre-computed totalLiquidity if available, else derive from supply/borrow
152
- const liquidity = sourceLiveData.totalLiquidity
153
- ? Number(sourceLiveData.totalLiquidity)
154
- : Number(sourceLiveData.totalSupplyAssets ?? 0) -
155
- Number(sourceLiveData.totalBorrowAssets ?? 0);
156
-
157
311
  if (vaultSupplyInSource > 0 && maxOut > 0 && liquidity > 0) {
158
312
  const sourceParams = marketParamsMap.get(
159
313
  sourceMarket.marketId.toLowerCase(),
@@ -219,6 +373,7 @@ export async function getMorphoMarketsData(params: {
219
373
  environments: Environment[];
220
374
  markets?: string[] | undefined;
221
375
  includeRewards?: boolean | undefined;
376
+ includeSharedLiquidity?: boolean | undefined;
222
377
  }): Promise<MorphoMarket[]> {
223
378
  const { environments } = params;
224
379
 
@@ -240,6 +395,7 @@ async function getMorphoMarketsDataFromOnChain(params: {
240
395
  environments: Environment[];
241
396
  markets?: string[] | undefined;
242
397
  includeRewards?: boolean | undefined;
398
+ includeSharedLiquidity?: boolean | undefined;
243
399
  }): Promise<MorphoMarket[]> {
244
400
  const { environments } = params;
245
401
 
@@ -281,7 +437,11 @@ async function getMorphoMarketsDataFromOnChain(params: {
281
437
  : [],
282
438
  );
283
439
 
284
- const initialMarkets: MorphoMarket[] = [];
440
+ const initialMarkets: {
441
+ chainId: number;
442
+ marketId: string;
443
+ marketKey: string;
444
+ }[] = [];
285
445
  fulfilledMarketsInfo.forEach(({ environment, marketsInfo }) => {
286
446
  marketsInfo.forEach((marketInfo) => {
287
447
  const marketKey = Object.keys(environment.config.morphoMarkets).find(
@@ -298,7 +458,7 @@ async function getMorphoMarketsDataFromOnChain(params: {
298
458
  chainId: environment.chainId,
299
459
  marketId: marketInfo.marketId,
300
460
  marketKey,
301
- } as MorphoMarket);
461
+ });
302
462
  });
303
463
  });
304
464
 
@@ -308,6 +468,7 @@ async function getMorphoMarketsDataFromOnChain(params: {
308
468
  const rewardsData = await getMorphoMarketRewards(
309
469
  rewardEnvironment,
310
470
  initialMarkets,
471
+ params,
311
472
  );
312
473
  const rewardsDataByChainAndMarket = new Map<
313
474
  string,
@@ -493,6 +654,10 @@ async function getMorphoMarketsDataFromOnChain(params: {
493
654
  rewards: [],
494
655
  publicAllocatorSharedLiquidity:
495
656
  marketRewardData?.publicAllocatorSharedLiquidity ?? [],
657
+ sharedLiquidityStatus:
658
+ params.includeSharedLiquidity === false
659
+ ? "not-requested"
660
+ : (marketRewardData?.sharedLiquidityStatus ?? "unavailable"),
496
661
  };
497
662
 
498
663
  return [mapping];
@@ -516,17 +681,11 @@ async function getMorphoMarketsDataFromOnChain(params: {
516
681
  return environment?.custom.morpho?.minimalDeployment === false;
517
682
  });
518
683
 
519
- const rewards = await getMorphoMarketRewards(
520
- params.environments.find((env) => env.custom?.morpho?.apiUrl) ??
521
- params.environments[0],
522
- markets,
523
- );
524
-
525
684
  markets.forEach((market) => {
526
- const marketReward = rewards.find(
527
- (reward) =>
528
- reward.marketId === market.marketId &&
529
- reward.chainId === market.chainId,
685
+ // Collateral, rewards and optional liquidity came from the same GraphQL
686
+ // response above. Do not repeat that expensive enrichment request.
687
+ const marketReward = rewardsDataByChainAndMarket.get(
688
+ `${market.chainId}-${market.marketId.toLowerCase()}`,
530
689
  );
531
690
  if (marketReward) {
532
691
  market.rewards = marketReward.rewards;
@@ -556,13 +715,6 @@ async function getMorphoMarketsDataFromOnChain(params: {
556
715
  });
557
716
  }
558
717
 
559
- type GetMorphoMarketsPublicAllocatorSharedLiquidityReturnType = {
560
- chainId: number;
561
- marketId: string;
562
- reallocatableLiquidityAssets: Amount;
563
- publicAllocatorSharedLiquidity: PublicAllocatorSharedLiquidityType[];
564
- };
565
-
566
718
  type GetMorphoMarketsRewardsReturnType = {
567
719
  chainId: number;
568
720
  marketId: string;
@@ -571,11 +723,16 @@ type GetMorphoMarketsRewardsReturnType = {
571
723
  reallocatableLiquidityAssets: Amount;
572
724
  publicAllocatorSharedLiquidity: PublicAllocatorSharedLiquidityType[];
573
725
  rewards: Required<MorphoReward>[];
726
+ sharedLiquidityStatus: "available" | "unavailable" | "not-requested";
574
727
  };
575
728
 
576
729
  async function getMorphoMarketRewards(
577
730
  environment: Environment,
578
731
  markets: { marketId: string; chainId: number }[],
732
+ options: {
733
+ includeRewards?: boolean | undefined;
734
+ includeSharedLiquidity?: boolean | undefined;
735
+ },
579
736
  ): Promise<GetMorphoMarketsRewardsReturnType[]> {
580
737
  if (markets.length === 0) {
581
738
  return [];
@@ -591,7 +748,10 @@ async function getMorphoMarketRewards(
591
748
  id
592
749
  }
593
750
  }
594
- reallocatableLiquidityAssets
751
+ ${
752
+ options.includeSharedLiquidity === false
753
+ ? ""
754
+ : `reallocatableLiquidityAssets
595
755
  publicAllocatorSharedLiquidity {
596
756
  assets
597
757
  vault {
@@ -621,6 +781,8 @@ async function getMorphoMarketRewards(
621
781
  lltv
622
782
  }
623
783
  }
784
+ `
785
+ }
624
786
  collateralAsset {
625
787
  decimals
626
788
  }
@@ -631,7 +793,9 @@ async function getMorphoMarketRewards(
631
793
  state {
632
794
  collateralAssets
633
795
  collateralAssetsUsd
634
- rewards {
796
+ ${
797
+ options.includeRewards
798
+ ? `rewards {
635
799
  asset {
636
800
  address
637
801
  symbol
@@ -640,6 +804,8 @@ async function getMorphoMarketRewards(
640
804
  }
641
805
  supplyApr
642
806
  borrowApr
807
+ }`
808
+ : ""
643
809
  }
644
810
  }
645
811
  marketId
@@ -718,7 +884,7 @@ async function getMorphoMarketRewards(
718
884
  chainId: item.morphoBlue.chain.id,
719
885
  marketId: item.marketId,
720
886
  reallocatableLiquidityAssets: new Amount(
721
- BigInt(item.reallocatableLiquidityAssets),
887
+ BigInt(item.reallocatableLiquidityAssets ?? "0"),
722
888
  loanAssetDecimals,
723
889
  ),
724
890
  // Note: The Morpho GraphQL API may return null for collateralAssets and
@@ -732,38 +898,49 @@ async function getMorphoMarketRewards(
732
898
  )
733
899
  : null,
734
900
  collateralAssetsUsd: item.state.collateralAssetsUsd ?? null,
735
- publicAllocatorSharedLiquidity: item.publicAllocatorSharedLiquidity.map(
736
- (item) => ({
737
- assets: Number(item.assets) / 10 ** loanAssetDecimals,
738
- vault: {
739
- address: item.vault.address,
740
- name: item.vault.name,
741
- // The Morpho API renamed Market.uniqueKey to marketId; map it
742
- // back to keep the SDK's public types unchanged.
743
- publicAllocatorConfig: {
744
- fee: item.vault.publicAllocatorConfig.fee,
745
- flowCaps: item.vault.publicAllocatorConfig.flowCaps.map(
746
- (flowCap) => ({
747
- market: { uniqueKey: flowCap.market.marketId },
748
- maxIn: flowCap.maxIn,
749
- maxOut: flowCap.maxOut,
750
- }),
751
- ),
752
- },
753
- },
754
- allocationMarket: {
755
- uniqueKey: item.allocationMarket.marketId,
756
- loanAsset: item.allocationMarket.loanAsset,
757
- ...(item.allocationMarket.collateralAsset
758
- ? { collateralAsset: item.allocationMarket.collateralAsset }
759
- : {}),
760
- oracleAddress: item.allocationMarket.oracleAddress,
761
- irmAddress: item.allocationMarket.irmAddress,
762
- lltv: item.allocationMarket.lltv,
901
+ sharedLiquidityStatus:
902
+ options.includeSharedLiquidity === false
903
+ ? "not-requested"
904
+ : item.publicAllocatorSharedLiquidity
905
+ ? "available"
906
+ : "unavailable",
907
+ publicAllocatorSharedLiquidity: (options.includeSharedLiquidity ===
908
+ false
909
+ ? []
910
+ : (item.publicAllocatorSharedLiquidity ?? [])
911
+ ).map((item) => ({
912
+ assets: Number(item.assets) / 10 ** loanAssetDecimals,
913
+ vault: {
914
+ address: item.vault.address,
915
+ name: item.vault.name,
916
+ // The Morpho API renamed Market.uniqueKey to marketId; map it
917
+ // back to keep the SDK's public types unchanged.
918
+ publicAllocatorConfig: {
919
+ fee: item.vault.publicAllocatorConfig.fee,
920
+ flowCaps: item.vault.publicAllocatorConfig.flowCaps.map(
921
+ (flowCap) => ({
922
+ market: { uniqueKey: flowCap.market.marketId },
923
+ maxIn: flowCap.maxIn,
924
+ maxOut: flowCap.maxOut,
925
+ }),
926
+ ),
763
927
  },
764
- }),
765
- ),
766
- rewards: item.state?.rewards.map((reward) => {
928
+ },
929
+ allocationMarket: {
930
+ uniqueKey: item.allocationMarket.marketId,
931
+ loanAsset: item.allocationMarket.loanAsset,
932
+ ...(item.allocationMarket.collateralAsset
933
+ ? { collateralAsset: item.allocationMarket.collateralAsset }
934
+ : {}),
935
+ oracleAddress: item.allocationMarket.oracleAddress,
936
+ irmAddress: item.allocationMarket.irmAddress,
937
+ lltv: item.allocationMarket.lltv,
938
+ },
939
+ })),
940
+ rewards: (options.includeRewards
941
+ ? (item.state?.rewards ?? [])
942
+ : []
943
+ ).map((reward) => {
767
944
  //Supply APR is used only for vaults, zeroing it for now to avoid confusion
768
945
  // Morpho removed the per-token amount fields from the API
769
946
  // (MarketStateReward.amountPerBorrowedToken et al.), so reward
@@ -795,6 +972,7 @@ async function getMorphoMarketsDataFromIndexer(params: {
795
972
  environments: Environment[];
796
973
  markets?: string[] | undefined;
797
974
  includeRewards?: boolean | undefined;
975
+ includeSharedLiquidity?: boolean | undefined;
798
976
  }): Promise<MorphoMarket[]> {
799
977
  const { environments } = params;
800
978
 
@@ -866,6 +1044,7 @@ async function getMorphoMarketsDataFromIndexer(params: {
866
1044
  environments: failedEnvironments,
867
1045
  markets: params.markets,
868
1046
  includeRewards: params.includeRewards,
1047
+ includeSharedLiquidity: params.includeSharedLiquidity,
869
1048
  });
870
1049
  } catch (rpcError) {
871
1050
  console.warn(
@@ -883,61 +1062,69 @@ async function getMorphoMarketsDataFromIndexer(params: {
883
1062
 
884
1063
  // Fetch shared liquidity from lunar-indexer.
885
1064
  const sharedLiquiditySettlements = await Promise.allSettled(
886
- fulfilledMarkets.map(async ({ environment, markets }) => {
887
- const lunarIndexerUrl = environment.lunarIndexerUrl;
888
- if (!lunarIndexerUrl)
889
- return {
890
- environment,
891
- data: [] as GetMorphoMarketsPublicAllocatorSharedLiquidityReturnType[],
892
- };
1065
+ (params.includeSharedLiquidity === false ? [] : fulfilledMarkets).map(
1066
+ async ({
1067
+ environment,
1068
+ markets,
1069
+ }): Promise<{
1070
+ environment: Environment;
1071
+ data: MorphoMarketSharedLiquidity[];
1072
+ }> => {
1073
+ const lunarIndexerUrl = environment.lunarIndexerUrl;
1074
+ if (!lunarIndexerUrl)
1075
+ return {
1076
+ environment,
1077
+ data: [],
1078
+ };
893
1079
 
894
- const marketParamsMap = new Map(
895
- markets.map((m) => [
896
- m.marketId.toLowerCase(),
897
- {
898
- oracle: m.oracle,
899
- irm: m.irm,
900
- lltv: m.lltv,
901
- loanToken: {
902
- address: m.loanToken.address,
903
- decimals: m.loanToken.decimals,
904
- },
905
- collateralToken: {
906
- address: m.collateralToken.address,
907
- decimals: m.collateralToken.decimals,
1080
+ const marketParamsMap = new Map(
1081
+ markets.map((m) => [
1082
+ m.marketId.toLowerCase(),
1083
+ {
1084
+ oracle: m.oracle,
1085
+ irm: m.irm,
1086
+ lltv: m.lltv,
1087
+ loanToken: {
1088
+ address: m.loanToken.address,
1089
+ decimals: m.loanToken.decimals,
1090
+ },
1091
+ collateralToken: {
1092
+ address: m.collateralToken.address,
1093
+ decimals: m.collateralToken.decimals,
1094
+ },
908
1095
  },
909
- },
910
- ]),
911
- );
912
-
913
- try {
914
- const rawData = await fetchSharedLiquidityFromLunar(
915
- lunarIndexerUrl,
916
- environment.chainId,
917
- );
918
- const marketIds = markets.map((m) => m.marketId);
919
- const data = computeSharedLiquidityFromLunar(
920
- rawData,
921
- marketIds,
922
- marketParamsMap,
923
- environment.chainId,
924
- );
925
- return { environment, data };
926
- } catch (error) {
927
- console.warn(
928
- `[getMorphoMarketsData] Lunar shared liquidity failed for chain ${environment.chainId}:`,
929
- error,
1096
+ ]),
930
1097
  );
931
- environment.onError?.(error, {
932
- source: "morpho-shared-liquidity",
933
- chainId: environment.chainId,
934
- });
935
- return {
936
- environment,
937
- data: [] as GetMorphoMarketsPublicAllocatorSharedLiquidityReturnType[],
938
- };
939
- }
940
- }),
1098
+
1099
+ try {
1100
+ const rawData = await fetchSharedLiquidityFromLunar(
1101
+ lunarIndexerUrl,
1102
+ environment.chainId,
1103
+ );
1104
+ const marketIds = markets.map((m) => m.marketId);
1105
+ const data = computeSharedLiquidityFromLunar(
1106
+ rawData,
1107
+ marketIds,
1108
+ marketParamsMap,
1109
+ environment.chainId,
1110
+ );
1111
+ return { environment, data };
1112
+ } catch (error) {
1113
+ console.warn(
1114
+ `[getMorphoMarketsData] Lunar shared liquidity failed for chain ${environment.chainId}:`,
1115
+ error,
1116
+ );
1117
+ environment.onError?.(error, {
1118
+ source: "morpho-shared-liquidity",
1119
+ chainId: environment.chainId,
1120
+ });
1121
+ return {
1122
+ environment,
1123
+ data: [],
1124
+ };
1125
+ }
1126
+ },
1127
+ ),
941
1128
  );
942
1129
 
943
1130
  const fulfilledSharedLiquidity = sharedLiquiditySettlements.flatMap((s) =>
@@ -1027,6 +1214,18 @@ async function getMorphoMarketsDataFromIndexer(params: {
1027
1214
  environment,
1028
1215
  rewardsDataMap,
1029
1216
  sharedLiquidityMap,
1217
+ ).map(
1218
+ (market): MorphoMarket => ({
1219
+ ...market,
1220
+ sharedLiquidityStatus:
1221
+ params.includeSharedLiquidity === false
1222
+ ? "not-requested"
1223
+ : sharedLiquidityMap.has(
1224
+ `${market.chainId}-${market.marketId.toLowerCase()}`,
1225
+ )
1226
+ ? "available"
1227
+ : "unavailable",
1228
+ }),
1030
1229
  );
1031
1230
  },
1032
1231
  );
@@ -17,6 +17,8 @@ export type GetMorphoMarketParameters<
17
17
  > = NetworkParameterType<environments, network> &
18
18
  MorphoMarketParameterType<network> & {
19
19
  includeRewards?: boolean | undefined;
20
+ /** Defaults to true. Disable to load base market data independently. */
21
+ includeSharedLiquidity?: boolean | undefined;
20
22
  };
21
23
 
22
24
  export type GetMorphoMarketReturnType = Promise<MorphoMarket | undefined>;
@@ -47,6 +49,7 @@ export async function getMorphoMarket<
47
49
  environments: [environment],
48
50
  markets: [marketId],
49
51
  includeRewards: args.includeRewards,
52
+ includeSharedLiquidity: args.includeSharedLiquidity,
50
53
  });
51
54
 
52
55
  return first(markets);
@@ -11,6 +11,8 @@ export type GetMorphoMarketsParameters<
11
11
  network extends Chain | undefined,
12
12
  > = OptionalNetworkParameterType<environments, network> & {
13
13
  includeRewards?: boolean | undefined;
14
+ /** Defaults to true. Disable to load base market data independently. */
15
+ includeSharedLiquidity?: boolean | undefined;
14
16
  };
15
17
 
16
18
  export type GetMorphoMarketsReturnType = Promise<MorphoMarket[]>;
@@ -32,6 +34,7 @@ export async function getMorphoMarkets<
32
34
  const result = await getMorphoMarketsData({
33
35
  environments: environments,
34
36
  includeRewards: args?.includeRewards,
37
+ includeSharedLiquidity: args?.includeSharedLiquidity,
35
38
  });
36
39
 
37
40
  logger.end(logId);