@moonwell-fi/moonwell-sdk 0.23.0 → 0.24.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 (144) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/_cjs/actions/axiosWithRetry.js +10 -11
  3. package/_cjs/actions/axiosWithRetry.js.map +1 -1
  4. package/_cjs/actions/core/markets/common.js +30 -35
  5. package/_cjs/actions/core/markets/common.js.map +1 -1
  6. package/_cjs/actions/core/markets/getMarkets.js +7 -3
  7. package/_cjs/actions/core/markets/getMarkets.js.map +1 -1
  8. package/_cjs/actions/core/user-positions/common.js +56 -60
  9. package/_cjs/actions/core/user-positions/common.js.map +1 -1
  10. package/_cjs/actions/core/user-positions/getUserPositions.js +9 -6
  11. package/_cjs/actions/core/user-positions/getUserPositions.js.map +1 -1
  12. package/_cjs/actions/governance/proposals/common.js +0 -5
  13. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  14. package/_cjs/actions/index.js +3 -1
  15. package/_cjs/actions/index.js.map +1 -1
  16. package/_cjs/actions/morpho/markets/common.js +128 -26
  17. package/_cjs/actions/morpho/markets/common.js.map +1 -1
  18. package/_cjs/actions/morpho/markets/getMorphoMarket.js +1 -0
  19. package/_cjs/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  20. package/_cjs/actions/morpho/markets/getMorphoMarkets.js +1 -0
  21. package/_cjs/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  22. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +46 -0
  23. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  24. package/_cjs/actions/morpho/user-positions/common.js +26 -24
  25. package/_cjs/actions/morpho/user-positions/common.js.map +1 -1
  26. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js +7 -8
  27. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  28. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js +7 -8
  29. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  30. package/_cjs/actions/retry.js +43 -13
  31. package/_cjs/actions/retry.js.map +1 -1
  32. package/_cjs/client/createActions.js +2 -0
  33. package/_cjs/client/createActions.js.map +1 -1
  34. package/_cjs/common/error.js +37 -1
  35. package/_cjs/common/error.js.map +1 -1
  36. package/_cjs/common/index.js +2 -1
  37. package/_cjs/common/index.js.map +1 -1
  38. package/_cjs/common/readAcrossEnvironments.js +17 -0
  39. package/_cjs/common/readAcrossEnvironments.js.map +1 -0
  40. package/_cjs/errors/version.js +1 -1
  41. package/_cjs/index.js +3 -1
  42. package/_cjs/index.js.map +1 -1
  43. package/_esm/actions/axiosWithRetry.js +11 -13
  44. package/_esm/actions/axiosWithRetry.js.map +1 -1
  45. package/_esm/actions/core/markets/common.js +34 -35
  46. package/_esm/actions/core/markets/common.js.map +1 -1
  47. package/_esm/actions/core/markets/getMarkets.js +7 -3
  48. package/_esm/actions/core/markets/getMarkets.js.map +1 -1
  49. package/_esm/actions/core/user-positions/common.js +65 -63
  50. package/_esm/actions/core/user-positions/common.js.map +1 -1
  51. package/_esm/actions/core/user-positions/getUserPositions.js +14 -6
  52. package/_esm/actions/core/user-positions/getUserPositions.js.map +1 -1
  53. package/_esm/actions/governance/proposals/common.js +0 -2
  54. package/_esm/actions/governance/proposals/common.js.map +1 -1
  55. package/_esm/actions/index.js +1 -0
  56. package/_esm/actions/index.js.map +1 -1
  57. package/_esm/actions/morpho/markets/common.js +136 -27
  58. package/_esm/actions/morpho/markets/common.js.map +1 -1
  59. package/_esm/actions/morpho/markets/getMorphoMarket.js +1 -0
  60. package/_esm/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  61. package/_esm/actions/morpho/markets/getMorphoMarkets.js +1 -0
  62. package/_esm/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  63. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +48 -0
  64. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  65. package/_esm/actions/morpho/user-positions/common.js +31 -24
  66. package/_esm/actions/morpho/user-positions/common.js.map +1 -1
  67. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js +12 -8
  68. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  69. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js +12 -8
  70. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  71. package/_esm/actions/retry.js +45 -15
  72. package/_esm/actions/retry.js.map +1 -1
  73. package/_esm/client/createActions.js +2 -0
  74. package/_esm/client/createActions.js.map +1 -1
  75. package/_esm/common/error.js +49 -0
  76. package/_esm/common/error.js.map +1 -1
  77. package/_esm/common/index.js +1 -1
  78. package/_esm/common/index.js.map +1 -1
  79. package/_esm/common/readAcrossEnvironments.js +30 -0
  80. package/_esm/common/readAcrossEnvironments.js.map +1 -0
  81. package/_esm/errors/version.js +1 -1
  82. package/_esm/index.js +1 -0
  83. package/_esm/index.js.map +1 -1
  84. package/_types/actions/axiosWithRetry.d.ts +1 -0
  85. package/_types/actions/axiosWithRetry.d.ts.map +1 -1
  86. package/_types/actions/core/markets/common.d.ts.map +1 -1
  87. package/_types/actions/core/markets/getMarkets.d.ts.map +1 -1
  88. package/_types/actions/core/user-positions/common.d.ts.map +1 -1
  89. package/_types/actions/core/user-positions/getUserPositions.d.ts +5 -0
  90. package/_types/actions/core/user-positions/getUserPositions.d.ts.map +1 -1
  91. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  92. package/_types/actions/index.d.ts +1 -0
  93. package/_types/actions/index.d.ts.map +1 -1
  94. package/_types/actions/morpho/markets/common.d.ts +7 -10
  95. package/_types/actions/morpho/markets/common.d.ts.map +1 -1
  96. package/_types/actions/morpho/markets/getMorphoMarket.d.ts +2 -0
  97. package/_types/actions/morpho/markets/getMorphoMarket.d.ts.map +1 -1
  98. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts +2 -0
  99. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts.map +1 -1
  100. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts +17 -0
  101. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts.map +1 -0
  102. package/_types/actions/morpho/user-positions/common.d.ts.map +1 -1
  103. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts +5 -0
  104. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts.map +1 -1
  105. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts +5 -0
  106. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts.map +1 -1
  107. package/_types/actions/retry.d.ts +5 -4
  108. package/_types/actions/retry.d.ts.map +1 -1
  109. package/_types/client/createActions.d.ts +2 -0
  110. package/_types/client/createActions.d.ts.map +1 -1
  111. package/_types/common/error.d.ts +31 -0
  112. package/_types/common/error.d.ts.map +1 -1
  113. package/_types/common/index.d.ts +2 -2
  114. package/_types/common/index.d.ts.map +1 -1
  115. package/_types/common/readAcrossEnvironments.d.ts +23 -0
  116. package/_types/common/readAcrossEnvironments.d.ts.map +1 -0
  117. package/_types/errors/version.d.ts +1 -1
  118. package/_types/index.d.ts +3 -1
  119. package/_types/index.d.ts.map +1 -1
  120. package/_types/types/morphoMarket.d.ts +9 -0
  121. package/_types/types/morphoMarket.d.ts.map +1 -1
  122. package/actions/axiosWithRetry.ts +19 -13
  123. package/actions/core/markets/common.ts +44 -43
  124. package/actions/core/markets/getMarkets.ts +9 -5
  125. package/actions/core/user-positions/common.ts +107 -111
  126. package/actions/core/user-positions/getUserPositions.ts +11 -10
  127. package/actions/governance/proposals/common.ts +0 -3
  128. package/actions/index.ts +5 -0
  129. package/actions/morpho/markets/common.ts +289 -125
  130. package/actions/morpho/markets/getMorphoMarket.ts +3 -0
  131. package/actions/morpho/markets/getMorphoMarkets.ts +3 -0
  132. package/actions/morpho/markets/getMorphoMarketsSharedLiquidity.ts +93 -0
  133. package/actions/morpho/user-positions/common.ts +48 -42
  134. package/actions/morpho/user-positions/getMorphoMarketUserPositions.ts +14 -15
  135. package/actions/morpho/user-positions/getMorphoVaultUserPositions.ts +14 -15
  136. package/actions/retry.ts +53 -18
  137. package/client/createActions.ts +13 -0
  138. package/common/error.ts +45 -0
  139. package/common/index.ts +2 -2
  140. package/common/readAcrossEnvironments.ts +45 -0
  141. package/errors/version.ts +1 -1
  142. package/index.ts +3 -0
  143. package/package.json +1 -1
  144. 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,129 @@ 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
+ function validatedMarketLiquidity(
80
+ data: LunarSharedLiquidityResponse,
81
+ ): Map<string, number> {
82
+ if (
83
+ !data ||
84
+ !Array.isArray(data.vaults) ||
85
+ !data.markets ||
86
+ typeof data.markets !== "object" ||
87
+ Array.isArray(data.markets)
88
+ ) {
89
+ throw new TypeError("Invalid shared-liquidity response");
90
+ }
91
+ for (const vault of data.vaults) {
92
+ parseLiquidityQuantity(vault.fee, "vault.fee", true);
93
+ for (const market of vault.markets) {
94
+ for (const field of [
95
+ "flowCapIn",
96
+ "flowCapOut",
97
+ "supplyCap",
98
+ "vaultSupplyShares",
99
+ "vaultSupplyAssets",
100
+ ] as const) {
101
+ parseLiquidityQuantity(
102
+ market[field],
103
+ `${market.marketId}.${field}`,
104
+ true,
105
+ );
106
+ }
107
+ if (typeof market.supplyCapEnabled !== "boolean") {
108
+ throw new TypeError("Invalid shared-liquidity supplyCapEnabled");
109
+ }
110
+ }
111
+ }
112
+ return new Map(
113
+ Object.entries(data.markets).map(([marketId, market]) => {
114
+ if (market.loanToken !== undefined) {
115
+ validateLoanDecimals(market.loanToken.decimals);
116
+ }
117
+ for (const field of ["totalSupplyAssets", "totalBorrowAssets"] as const) {
118
+ if (market[field] !== undefined) {
119
+ parseLiquidityQuantity(market[field], `${marketId}.${field}`);
120
+ }
121
+ }
122
+ const liquidity =
123
+ market.totalLiquidity !== undefined
124
+ ? parseLiquidityQuantity(
125
+ market.totalLiquidity,
126
+ `${marketId}.totalLiquidity`,
127
+ )
128
+ : parseLiquidityQuantity(
129
+ market.totalSupplyAssets,
130
+ `${marketId}.totalSupplyAssets`,
131
+ ) -
132
+ parseLiquidityQuantity(
133
+ market.totalBorrowAssets,
134
+ `${marketId}.totalBorrowAssets`,
135
+ );
136
+ if (liquidity < 0) {
137
+ throw new TypeError(`Negative shared liquidity for ${marketId}`);
138
+ }
139
+ return [marketId, liquidity];
140
+ }),
141
+ );
142
+ }
143
+
144
+ export async function fetchSharedLiquidityFromLunar(
49
145
  lunarIndexerUrl: string,
50
146
  chainId: number,
147
+ options: { signal?: AbortSignal; timeoutMs?: number } = {},
51
148
  ): Promise<LunarSharedLiquidityResponse> {
52
- const response = await getWithRetry<LunarSharedLiquidityResponse>(
53
- `${lunarIndexerUrl}/api/v1/isolated/shared-liquidity/${chainId}`,
54
- );
55
- return response.data;
149
+ // One budget for the request AND its retries. The endpoint often takes more
150
+ // than five seconds, so let it finish instead of restarting the same work.
151
+ const timeoutMs = options.timeoutMs ?? 15_000;
152
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
153
+ throw new RangeError(
154
+ "Shared-liquidity timeoutMs must be positive and finite",
155
+ );
156
+ }
157
+ const controller = new AbortController();
158
+ const abort = (): void => controller.abort();
159
+ if (options.signal?.aborted) abort();
160
+ options.signal?.addEventListener("abort", abort, { once: true });
161
+ const timer = setTimeout(abort, timeoutMs);
162
+ try {
163
+ const response = await getWithRetry<LunarSharedLiquidityResponse>(
164
+ `${lunarIndexerUrl}/api/v1/isolated/shared-liquidity/${chainId}`,
165
+ { timeout: timeoutMs, signal: controller.signal },
166
+ );
167
+ return response.data;
168
+ } finally {
169
+ clearTimeout(timer);
170
+ options.signal?.removeEventListener("abort", abort);
171
+ }
56
172
  }
57
173
 
58
174
  export function computeSharedLiquidityFromLunar(
@@ -69,7 +185,9 @@ export function computeSharedLiquidityFromLunar(
69
185
  }
70
186
  >,
71
187
  chainId: number,
72
- ): GetMorphoMarketsPublicAllocatorSharedLiquidityReturnType[] {
188
+ ): MorphoMarketSharedLiquidity[] {
189
+ // Validate the complete response before building any successful allocations.
190
+ const liquidityByMarket = validatedMarketLiquidity(data);
73
191
  return targetMarkets.map((targetMarket) => {
74
192
  const targetId = targetMarket.toLowerCase();
75
193
  const r: PublicAllocatorSharedLiquidityType[] = [];
@@ -83,10 +201,11 @@ export function computeSharedLiquidityFromLunar(
83
201
  // (wei-like). Markets data (totalSupplyAssets, totalBorrowAssets, totalLiquidity)
84
202
  // is already in token units (divided by decimals). We convert vault raw values
85
203
  // to token units using the loan token decimals before comparing.
86
- const targetLoanDecimals =
204
+ const targetLoanDecimals = validateLoanDecimals(
87
205
  targetLiveData?.loanToken?.decimals ??
88
- targetParams?.loanToken.decimals ??
89
- 18;
206
+ targetParams?.loanToken.decimals ??
207
+ 18,
208
+ );
90
209
  const targetScale = 10 ** targetLoanDecimals;
91
210
 
92
211
  for (const vault of data.vaults) {
@@ -135,25 +254,25 @@ export function computeSharedLiquidityFromLunar(
135
254
 
136
255
  const sourceLiveData =
137
256
  data.markets[sourceMarket.marketId.toLowerCase()];
138
- if (!sourceLiveData) continue;
257
+ const liquidity = liquidityByMarket.get(
258
+ sourceMarket.marketId.toLowerCase(),
259
+ );
260
+ // The indexer can omit an entire source record. Preserve that existing
261
+ // skip behavior; quantities in every returned record were validated above.
262
+ if (!sourceLiveData || liquidity === undefined) continue;
139
263
 
140
- const sourceLoanDecimals =
264
+ const sourceLoanDecimals = validateLoanDecimals(
141
265
  sourceLiveData.loanToken?.decimals ??
142
- marketParamsMap.get(sourceMarket.marketId.toLowerCase())?.loanToken
143
- .decimals ??
144
- 18;
266
+ marketParamsMap.get(sourceMarket.marketId.toLowerCase())?.loanToken
267
+ .decimals ??
268
+ 18,
269
+ );
145
270
  const sourceScale = 10 ** sourceLoanDecimals;
146
271
 
147
272
  const vaultSupplyInSource =
148
273
  Number(sourceMarket.vaultSupplyAssets) / sourceScale;
149
274
  const maxOut = Number(sourceMarket.flowCapOut) / sourceScale;
150
275
 
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
276
  if (vaultSupplyInSource > 0 && maxOut > 0 && liquidity > 0) {
158
277
  const sourceParams = marketParamsMap.get(
159
278
  sourceMarket.marketId.toLowerCase(),
@@ -219,6 +338,7 @@ export async function getMorphoMarketsData(params: {
219
338
  environments: Environment[];
220
339
  markets?: string[] | undefined;
221
340
  includeRewards?: boolean | undefined;
341
+ includeSharedLiquidity?: boolean | undefined;
222
342
  }): Promise<MorphoMarket[]> {
223
343
  const { environments } = params;
224
344
 
@@ -240,6 +360,7 @@ async function getMorphoMarketsDataFromOnChain(params: {
240
360
  environments: Environment[];
241
361
  markets?: string[] | undefined;
242
362
  includeRewards?: boolean | undefined;
363
+ includeSharedLiquidity?: boolean | undefined;
243
364
  }): Promise<MorphoMarket[]> {
244
365
  const { environments } = params;
245
366
 
@@ -281,7 +402,11 @@ async function getMorphoMarketsDataFromOnChain(params: {
281
402
  : [],
282
403
  );
283
404
 
284
- const initialMarkets: MorphoMarket[] = [];
405
+ const initialMarkets: {
406
+ chainId: number;
407
+ marketId: string;
408
+ marketKey: string;
409
+ }[] = [];
285
410
  fulfilledMarketsInfo.forEach(({ environment, marketsInfo }) => {
286
411
  marketsInfo.forEach((marketInfo) => {
287
412
  const marketKey = Object.keys(environment.config.morphoMarkets).find(
@@ -298,7 +423,7 @@ async function getMorphoMarketsDataFromOnChain(params: {
298
423
  chainId: environment.chainId,
299
424
  marketId: marketInfo.marketId,
300
425
  marketKey,
301
- } as MorphoMarket);
426
+ });
302
427
  });
303
428
  });
304
429
 
@@ -308,6 +433,7 @@ async function getMorphoMarketsDataFromOnChain(params: {
308
433
  const rewardsData = await getMorphoMarketRewards(
309
434
  rewardEnvironment,
310
435
  initialMarkets,
436
+ params,
311
437
  );
312
438
  const rewardsDataByChainAndMarket = new Map<
313
439
  string,
@@ -493,6 +619,10 @@ async function getMorphoMarketsDataFromOnChain(params: {
493
619
  rewards: [],
494
620
  publicAllocatorSharedLiquidity:
495
621
  marketRewardData?.publicAllocatorSharedLiquidity ?? [],
622
+ sharedLiquidityStatus:
623
+ params.includeSharedLiquidity === false
624
+ ? "not-requested"
625
+ : (marketRewardData?.sharedLiquidityStatus ?? "unavailable"),
496
626
  };
497
627
 
498
628
  return [mapping];
@@ -516,17 +646,11 @@ async function getMorphoMarketsDataFromOnChain(params: {
516
646
  return environment?.custom.morpho?.minimalDeployment === false;
517
647
  });
518
648
 
519
- const rewards = await getMorphoMarketRewards(
520
- params.environments.find((env) => env.custom?.morpho?.apiUrl) ??
521
- params.environments[0],
522
- markets,
523
- );
524
-
525
649
  markets.forEach((market) => {
526
- const marketReward = rewards.find(
527
- (reward) =>
528
- reward.marketId === market.marketId &&
529
- reward.chainId === market.chainId,
650
+ // Collateral, rewards and optional liquidity came from the same GraphQL
651
+ // response above. Do not repeat that expensive enrichment request.
652
+ const marketReward = rewardsDataByChainAndMarket.get(
653
+ `${market.chainId}-${market.marketId.toLowerCase()}`,
530
654
  );
531
655
  if (marketReward) {
532
656
  market.rewards = marketReward.rewards;
@@ -556,13 +680,6 @@ async function getMorphoMarketsDataFromOnChain(params: {
556
680
  });
557
681
  }
558
682
 
559
- type GetMorphoMarketsPublicAllocatorSharedLiquidityReturnType = {
560
- chainId: number;
561
- marketId: string;
562
- reallocatableLiquidityAssets: Amount;
563
- publicAllocatorSharedLiquidity: PublicAllocatorSharedLiquidityType[];
564
- };
565
-
566
683
  type GetMorphoMarketsRewardsReturnType = {
567
684
  chainId: number;
568
685
  marketId: string;
@@ -571,11 +688,16 @@ type GetMorphoMarketsRewardsReturnType = {
571
688
  reallocatableLiquidityAssets: Amount;
572
689
  publicAllocatorSharedLiquidity: PublicAllocatorSharedLiquidityType[];
573
690
  rewards: Required<MorphoReward>[];
691
+ sharedLiquidityStatus: "available" | "unavailable" | "not-requested";
574
692
  };
575
693
 
576
694
  async function getMorphoMarketRewards(
577
695
  environment: Environment,
578
696
  markets: { marketId: string; chainId: number }[],
697
+ options: {
698
+ includeRewards?: boolean | undefined;
699
+ includeSharedLiquidity?: boolean | undefined;
700
+ },
579
701
  ): Promise<GetMorphoMarketsRewardsReturnType[]> {
580
702
  if (markets.length === 0) {
581
703
  return [];
@@ -591,7 +713,10 @@ async function getMorphoMarketRewards(
591
713
  id
592
714
  }
593
715
  }
594
- reallocatableLiquidityAssets
716
+ ${
717
+ options.includeSharedLiquidity === false
718
+ ? ""
719
+ : `reallocatableLiquidityAssets
595
720
  publicAllocatorSharedLiquidity {
596
721
  assets
597
722
  vault {
@@ -621,6 +746,8 @@ async function getMorphoMarketRewards(
621
746
  lltv
622
747
  }
623
748
  }
749
+ `
750
+ }
624
751
  collateralAsset {
625
752
  decimals
626
753
  }
@@ -631,7 +758,9 @@ async function getMorphoMarketRewards(
631
758
  state {
632
759
  collateralAssets
633
760
  collateralAssetsUsd
634
- rewards {
761
+ ${
762
+ options.includeRewards
763
+ ? `rewards {
635
764
  asset {
636
765
  address
637
766
  symbol
@@ -640,6 +769,8 @@ async function getMorphoMarketRewards(
640
769
  }
641
770
  supplyApr
642
771
  borrowApr
772
+ }`
773
+ : ""
643
774
  }
644
775
  }
645
776
  marketId
@@ -718,7 +849,7 @@ async function getMorphoMarketRewards(
718
849
  chainId: item.morphoBlue.chain.id,
719
850
  marketId: item.marketId,
720
851
  reallocatableLiquidityAssets: new Amount(
721
- BigInt(item.reallocatableLiquidityAssets),
852
+ BigInt(item.reallocatableLiquidityAssets ?? "0"),
722
853
  loanAssetDecimals,
723
854
  ),
724
855
  // Note: The Morpho GraphQL API may return null for collateralAssets and
@@ -732,38 +863,49 @@ async function getMorphoMarketRewards(
732
863
  )
733
864
  : null,
734
865
  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,
866
+ sharedLiquidityStatus:
867
+ options.includeSharedLiquidity === false
868
+ ? "not-requested"
869
+ : item.publicAllocatorSharedLiquidity
870
+ ? "available"
871
+ : "unavailable",
872
+ publicAllocatorSharedLiquidity: (options.includeSharedLiquidity ===
873
+ false
874
+ ? []
875
+ : (item.publicAllocatorSharedLiquidity ?? [])
876
+ ).map((item) => ({
877
+ assets: Number(item.assets) / 10 ** loanAssetDecimals,
878
+ vault: {
879
+ address: item.vault.address,
880
+ name: item.vault.name,
881
+ // The Morpho API renamed Market.uniqueKey to marketId; map it
882
+ // back to keep the SDK's public types unchanged.
883
+ publicAllocatorConfig: {
884
+ fee: item.vault.publicAllocatorConfig.fee,
885
+ flowCaps: item.vault.publicAllocatorConfig.flowCaps.map(
886
+ (flowCap) => ({
887
+ market: { uniqueKey: flowCap.market.marketId },
888
+ maxIn: flowCap.maxIn,
889
+ maxOut: flowCap.maxOut,
890
+ }),
891
+ ),
763
892
  },
764
- }),
765
- ),
766
- rewards: item.state?.rewards.map((reward) => {
893
+ },
894
+ allocationMarket: {
895
+ uniqueKey: item.allocationMarket.marketId,
896
+ loanAsset: item.allocationMarket.loanAsset,
897
+ ...(item.allocationMarket.collateralAsset
898
+ ? { collateralAsset: item.allocationMarket.collateralAsset }
899
+ : {}),
900
+ oracleAddress: item.allocationMarket.oracleAddress,
901
+ irmAddress: item.allocationMarket.irmAddress,
902
+ lltv: item.allocationMarket.lltv,
903
+ },
904
+ })),
905
+ rewards: (options.includeRewards
906
+ ? (item.state?.rewards ?? [])
907
+ : []
908
+ ).map((reward) => {
767
909
  //Supply APR is used only for vaults, zeroing it for now to avoid confusion
768
910
  // Morpho removed the per-token amount fields from the API
769
911
  // (MarketStateReward.amountPerBorrowedToken et al.), so reward
@@ -795,6 +937,7 @@ async function getMorphoMarketsDataFromIndexer(params: {
795
937
  environments: Environment[];
796
938
  markets?: string[] | undefined;
797
939
  includeRewards?: boolean | undefined;
940
+ includeSharedLiquidity?: boolean | undefined;
798
941
  }): Promise<MorphoMarket[]> {
799
942
  const { environments } = params;
800
943
 
@@ -866,6 +1009,7 @@ async function getMorphoMarketsDataFromIndexer(params: {
866
1009
  environments: failedEnvironments,
867
1010
  markets: params.markets,
868
1011
  includeRewards: params.includeRewards,
1012
+ includeSharedLiquidity: params.includeSharedLiquidity,
869
1013
  });
870
1014
  } catch (rpcError) {
871
1015
  console.warn(
@@ -883,61 +1027,69 @@ async function getMorphoMarketsDataFromIndexer(params: {
883
1027
 
884
1028
  // Fetch shared liquidity from lunar-indexer.
885
1029
  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
- };
1030
+ (params.includeSharedLiquidity === false ? [] : fulfilledMarkets).map(
1031
+ async ({
1032
+ environment,
1033
+ markets,
1034
+ }): Promise<{
1035
+ environment: Environment;
1036
+ data: MorphoMarketSharedLiquidity[];
1037
+ }> => {
1038
+ const lunarIndexerUrl = environment.lunarIndexerUrl;
1039
+ if (!lunarIndexerUrl)
1040
+ return {
1041
+ environment,
1042
+ data: [],
1043
+ };
893
1044
 
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,
1045
+ const marketParamsMap = new Map(
1046
+ markets.map((m) => [
1047
+ m.marketId.toLowerCase(),
1048
+ {
1049
+ oracle: m.oracle,
1050
+ irm: m.irm,
1051
+ lltv: m.lltv,
1052
+ loanToken: {
1053
+ address: m.loanToken.address,
1054
+ decimals: m.loanToken.decimals,
1055
+ },
1056
+ collateralToken: {
1057
+ address: m.collateralToken.address,
1058
+ decimals: m.collateralToken.decimals,
1059
+ },
908
1060
  },
909
- },
910
- ]),
911
- );
912
-
913
- try {
914
- const rawData = await fetchSharedLiquidityFromLunar(
915
- lunarIndexerUrl,
916
- environment.chainId,
1061
+ ]),
917
1062
  );
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,
930
- );
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
- }),
1063
+
1064
+ try {
1065
+ const rawData = await fetchSharedLiquidityFromLunar(
1066
+ lunarIndexerUrl,
1067
+ environment.chainId,
1068
+ );
1069
+ const marketIds = markets.map((m) => m.marketId);
1070
+ const data = computeSharedLiquidityFromLunar(
1071
+ rawData,
1072
+ marketIds,
1073
+ marketParamsMap,
1074
+ environment.chainId,
1075
+ );
1076
+ return { environment, data };
1077
+ } catch (error) {
1078
+ console.warn(
1079
+ `[getMorphoMarketsData] Lunar shared liquidity failed for chain ${environment.chainId}:`,
1080
+ error,
1081
+ );
1082
+ environment.onError?.(error, {
1083
+ source: "morpho-shared-liquidity",
1084
+ chainId: environment.chainId,
1085
+ });
1086
+ return {
1087
+ environment,
1088
+ data: [],
1089
+ };
1090
+ }
1091
+ },
1092
+ ),
941
1093
  );
942
1094
 
943
1095
  const fulfilledSharedLiquidity = sharedLiquiditySettlements.flatMap((s) =>
@@ -1027,6 +1179,18 @@ async function getMorphoMarketsDataFromIndexer(params: {
1027
1179
  environment,
1028
1180
  rewardsDataMap,
1029
1181
  sharedLiquidityMap,
1182
+ ).map(
1183
+ (market): MorphoMarket => ({
1184
+ ...market,
1185
+ sharedLiquidityStatus:
1186
+ params.includeSharedLiquidity === false
1187
+ ? "not-requested"
1188
+ : sharedLiquidityMap.has(
1189
+ `${market.chainId}-${market.marketId.toLowerCase()}`,
1190
+ )
1191
+ ? "available"
1192
+ : "unavailable",
1193
+ }),
1030
1194
  );
1031
1195
  },
1032
1196
  );
@@ -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);