@moonwell-fi/moonwell-sdk 0.22.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 (165) hide show
  1. package/CHANGELOG.md +28 -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 +11 -24
  5. package/_cjs/actions/core/getUserBalances.js.map +1 -1
  6. package/_cjs/actions/core/markets/common.js +30 -35
  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/proposals/common.js +0 -5
  15. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  16. package/_cjs/actions/index.js +3 -1
  17. package/_cjs/actions/index.js.map +1 -1
  18. package/_cjs/actions/morpho/markets/common.js +128 -26
  19. package/_cjs/actions/morpho/markets/common.js.map +1 -1
  20. package/_cjs/actions/morpho/markets/getMorphoMarket.js +1 -0
  21. package/_cjs/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  22. package/_cjs/actions/morpho/markets/getMorphoMarkets.js +1 -0
  23. package/_cjs/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  24. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +46 -0
  25. package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  26. package/_cjs/actions/morpho/user-positions/common.js +26 -24
  27. package/_cjs/actions/morpho/user-positions/common.js.map +1 -1
  28. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js +7 -8
  29. package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  30. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js +7 -8
  31. package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  32. package/_cjs/actions/retry.js +43 -13
  33. package/_cjs/actions/retry.js.map +1 -1
  34. package/_cjs/client/createActions.js +2 -0
  35. package/_cjs/client/createActions.js.map +1 -1
  36. package/_cjs/client/createMoonwellClient.js.map +1 -1
  37. package/_cjs/common/error.js +37 -1
  38. package/_cjs/common/error.js.map +1 -1
  39. package/_cjs/common/index.js +2 -1
  40. package/_cjs/common/index.js.map +1 -1
  41. package/_cjs/common/readAcrossEnvironments.js +17 -0
  42. package/_cjs/common/readAcrossEnvironments.js.map +1 -0
  43. package/_cjs/environments/index.js.map +1 -1
  44. package/_cjs/environments/types/config.js.map +1 -1
  45. package/_cjs/errors/version.js +1 -1
  46. package/_cjs/index.js +3 -1
  47. package/_cjs/index.js.map +1 -1
  48. package/_esm/actions/axiosWithRetry.js +11 -13
  49. package/_esm/actions/axiosWithRetry.js.map +1 -1
  50. package/_esm/actions/core/getUserBalances.js +23 -24
  51. package/_esm/actions/core/getUserBalances.js.map +1 -1
  52. package/_esm/actions/core/markets/common.js +34 -35
  53. package/_esm/actions/core/markets/common.js.map +1 -1
  54. package/_esm/actions/core/markets/getMarkets.js +7 -3
  55. package/_esm/actions/core/markets/getMarkets.js.map +1 -1
  56. package/_esm/actions/core/user-positions/common.js +65 -63
  57. package/_esm/actions/core/user-positions/common.js.map +1 -1
  58. package/_esm/actions/core/user-positions/getUserPositions.js +14 -6
  59. package/_esm/actions/core/user-positions/getUserPositions.js.map +1 -1
  60. package/_esm/actions/governance/proposals/common.js +0 -2
  61. package/_esm/actions/governance/proposals/common.js.map +1 -1
  62. package/_esm/actions/index.js +1 -0
  63. package/_esm/actions/index.js.map +1 -1
  64. package/_esm/actions/morpho/markets/common.js +136 -27
  65. package/_esm/actions/morpho/markets/common.js.map +1 -1
  66. package/_esm/actions/morpho/markets/getMorphoMarket.js +1 -0
  67. package/_esm/actions/morpho/markets/getMorphoMarket.js.map +1 -1
  68. package/_esm/actions/morpho/markets/getMorphoMarkets.js +1 -0
  69. package/_esm/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  70. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +48 -0
  71. package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
  72. package/_esm/actions/morpho/user-positions/common.js +31 -24
  73. package/_esm/actions/morpho/user-positions/common.js.map +1 -1
  74. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js +12 -8
  75. package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
  76. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js +12 -8
  77. package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
  78. package/_esm/actions/retry.js +45 -15
  79. package/_esm/actions/retry.js.map +1 -1
  80. package/_esm/client/createActions.js +2 -0
  81. package/_esm/client/createActions.js.map +1 -1
  82. package/_esm/client/createMoonwellClient.js.map +1 -1
  83. package/_esm/common/error.js +49 -0
  84. package/_esm/common/error.js.map +1 -1
  85. package/_esm/common/index.js +1 -1
  86. package/_esm/common/index.js.map +1 -1
  87. package/_esm/common/readAcrossEnvironments.js +30 -0
  88. package/_esm/common/readAcrossEnvironments.js.map +1 -0
  89. package/_esm/environments/index.js.map +1 -1
  90. package/_esm/environments/types/config.js.map +1 -1
  91. package/_esm/errors/version.js +1 -1
  92. package/_esm/index.js +1 -0
  93. package/_esm/index.js.map +1 -1
  94. package/_types/actions/axiosWithRetry.d.ts +1 -0
  95. package/_types/actions/axiosWithRetry.d.ts.map +1 -1
  96. package/_types/actions/core/getUserBalances.d.ts.map +1 -1
  97. package/_types/actions/core/markets/common.d.ts.map +1 -1
  98. package/_types/actions/core/markets/getMarkets.d.ts.map +1 -1
  99. package/_types/actions/core/user-positions/common.d.ts.map +1 -1
  100. package/_types/actions/core/user-positions/getUserPositions.d.ts +5 -0
  101. package/_types/actions/core/user-positions/getUserPositions.d.ts.map +1 -1
  102. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  103. package/_types/actions/index.d.ts +1 -0
  104. package/_types/actions/index.d.ts.map +1 -1
  105. package/_types/actions/morpho/markets/common.d.ts +7 -10
  106. package/_types/actions/morpho/markets/common.d.ts.map +1 -1
  107. package/_types/actions/morpho/markets/getMorphoMarket.d.ts +2 -0
  108. package/_types/actions/morpho/markets/getMorphoMarket.d.ts.map +1 -1
  109. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts +2 -0
  110. package/_types/actions/morpho/markets/getMorphoMarkets.d.ts.map +1 -1
  111. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts +17 -0
  112. package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts.map +1 -0
  113. package/_types/actions/morpho/user-positions/common.d.ts.map +1 -1
  114. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts +5 -0
  115. package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts.map +1 -1
  116. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts +5 -0
  117. package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts.map +1 -1
  118. package/_types/actions/retry.d.ts +5 -4
  119. package/_types/actions/retry.d.ts.map +1 -1
  120. package/_types/client/createActions.d.ts +2 -0
  121. package/_types/client/createActions.d.ts.map +1 -1
  122. package/_types/client/createMoonwellClient.d.ts +2 -5
  123. package/_types/client/createMoonwellClient.d.ts.map +1 -1
  124. package/_types/common/error.d.ts +31 -0
  125. package/_types/common/error.d.ts.map +1 -1
  126. package/_types/common/index.d.ts +2 -2
  127. package/_types/common/index.d.ts.map +1 -1
  128. package/_types/common/readAcrossEnvironments.d.ts +23 -0
  129. package/_types/common/readAcrossEnvironments.d.ts.map +1 -0
  130. package/_types/environments/index.d.ts +2 -2
  131. package/_types/environments/index.d.ts.map +1 -1
  132. package/_types/environments/types/config.d.ts +8 -8
  133. package/_types/environments/types/config.d.ts.map +1 -1
  134. package/_types/errors/version.d.ts +1 -1
  135. package/_types/index.d.ts +3 -1
  136. package/_types/index.d.ts.map +1 -1
  137. package/_types/types/morphoMarket.d.ts +9 -0
  138. package/_types/types/morphoMarket.d.ts.map +1 -1
  139. package/actions/axiosWithRetry.ts +19 -13
  140. package/actions/core/getUserBalances.ts +25 -31
  141. package/actions/core/markets/common.ts +44 -43
  142. package/actions/core/markets/getMarkets.ts +9 -5
  143. package/actions/core/user-positions/common.ts +107 -111
  144. package/actions/core/user-positions/getUserPositions.ts +11 -10
  145. package/actions/governance/proposals/common.ts +0 -3
  146. package/actions/index.ts +5 -0
  147. package/actions/morpho/markets/common.ts +289 -125
  148. package/actions/morpho/markets/getMorphoMarket.ts +3 -0
  149. package/actions/morpho/markets/getMorphoMarkets.ts +3 -0
  150. package/actions/morpho/markets/getMorphoMarketsSharedLiquidity.ts +93 -0
  151. package/actions/morpho/user-positions/common.ts +48 -42
  152. package/actions/morpho/user-positions/getMorphoMarketUserPositions.ts +14 -15
  153. package/actions/morpho/user-positions/getMorphoVaultUserPositions.ts +14 -15
  154. package/actions/retry.ts +53 -18
  155. package/client/createActions.ts +13 -0
  156. package/client/createMoonwellClient.ts +2 -4
  157. package/common/error.ts +45 -0
  158. package/common/index.ts +2 -2
  159. package/common/readAcrossEnvironments.ts +45 -0
  160. package/environments/index.ts +6 -1
  161. package/environments/types/config.ts +10 -8
  162. package/errors/version.ts +1 -1
  163. package/index.ts +3 -0
  164. package/package.json +1 -1
  165. package/types/morphoMarket.ts +10 -0
@@ -22,27 +22,29 @@ export type GetUserBalancesParameters<
22
22
 
23
23
  export type GetUserBalancesReturnType = Promise<UserBalance[]>;
24
24
 
25
+ /**
26
+ * Reads one token balance. Rejects when the read fails — it must never resolve
27
+ * to a zero, which is what it did before MOO-832: an RPC failure surfaced to
28
+ * consumers as a "successful" empty wallet. The Moonwell frontend gates repay-all
29
+ * on this figure, so a transient RPC hiccup on a 5s refetch read as "wallet is
30
+ * empty" and disabled the confirm button for 59 users (Sentry
31
+ * MOONWELL-FRONTEND-195). Callers settle these with `Promise.allSettled` and
32
+ * omit the rejected tokens, so a consumer that finds no entry knows the balance
33
+ * is UNKNOWN rather than zero. The failure is routed to `environment.onError`
34
+ * (source `user-balances-token-read`) so Sentry-wired consumers can see the
35
+ * degraded read.
36
+ */
25
37
  const getTokenBalance = async (
26
38
  environment: Environment,
27
39
  userAddress: Address,
28
40
  tokenAddress: Address,
29
- ) => {
41
+ ): Promise<{ amount: bigint; token: `0x${string}` }> => {
30
42
  try {
31
43
  if (tokenAddress === zeroAddress) {
32
- return new Promise<{ amount: bigint; token: `0x${string}` }>(
33
- (resolve) => {
34
- environment.publicClient
35
- .getBalance({
36
- address: userAddress,
37
- })
38
- .then((balance) => {
39
- resolve({ amount: BigInt(balance), token: tokenAddress });
40
- })
41
- .catch(() => {
42
- resolve({ amount: 0n, token: tokenAddress });
43
- });
44
- },
45
- );
44
+ const balance = await environment.publicClient.getBalance({
45
+ address: userAddress,
46
+ });
47
+ return { amount: BigInt(balance), token: tokenAddress };
46
48
  }
47
49
 
48
50
  const erc20Abi = parseAbi([
@@ -55,23 +57,15 @@ const getTokenBalance = async (
55
57
  client: environment.publicClient,
56
58
  });
57
59
 
58
- const result = new Promise<{ amount: bigint; token: `0x${string}` }>(
59
- (resolve) => {
60
- erc20Contract.read
61
- .balanceOf([userAddress])
62
- .then((balance) => {
63
- resolve({ amount: BigInt(balance), token: tokenAddress });
64
- })
65
- .catch(() => {
66
- resolve({ amount: 0n, token: tokenAddress });
67
- });
68
- },
69
- );
70
-
71
- return result;
60
+ const balance = await erc20Contract.read.balanceOf([userAddress]);
61
+ return { amount: BigInt(balance), token: tokenAddress };
72
62
  } catch (error) {
73
- console.error("getTokenBalance error", error);
74
- return { amount: 0n, token: tokenAddress };
63
+ environment.onError?.(error, {
64
+ source: "user-balances-token-read",
65
+ chainId: environment.chainId,
66
+ token: tokenAddress,
67
+ });
68
+ throw error;
75
69
  }
76
70
  };
77
71
 
@@ -876,54 +876,55 @@ async function fetchMarketsFromLunar(
876
876
  }
877
877
 
878
878
  const fetchFromGenericCacheApi = async <T>(uri: string): Promise<T> => {
879
- const response = await fetch(
880
- "https://generic-api-cache.moonwell.workers.dev/",
881
- {
882
- method: "POST",
883
- body: `{"uri":"${uri}","cacheDuration":"300"}`,
884
- headers: {
885
- ...MOONWELL_FETCH_JSON_HEADERS,
886
- "Content-Type": "text/plain",
879
+ // AbortSignal.timeout is not available in every browser supported by SDK
880
+ // consumers. Keep the timeout local and release it after reading the body.
881
+ const controller = new AbortController();
882
+ const timer = setTimeout(() => controller.abort(), 5_000);
883
+ try {
884
+ const response = await fetch(
885
+ "https://generic-api-cache.moonwell.workers.dev/",
886
+ {
887
+ method: "POST",
888
+ body: `{"uri":"${uri}","cacheDuration":"300"}`,
889
+ signal: controller.signal,
890
+ headers: {
891
+ ...MOONWELL_FETCH_JSON_HEADERS,
892
+ "Content-Type": "text/plain",
893
+ },
887
894
  },
888
- },
889
- );
895
+ );
890
896
 
891
- return response.json() as T;
897
+ if (!response.ok)
898
+ throw new Error(`Staking APR request failed: ${response.status}`);
899
+ return await response.json();
900
+ } finally {
901
+ clearTimeout(timer);
902
+ }
892
903
  };
893
904
 
894
- export const fetchLiquidStakingRewards = async () => {
895
- const result = {
896
- cbETH: 0,
897
- rETH: 0,
898
- wstETH: 0,
899
- };
900
-
901
- try {
902
- const cbETH = await fetchFromGenericCacheApi<{ apy: string }>(
905
+ export const fetchLiquidStakingRewards = async (): Promise<{
906
+ cbETH: number;
907
+ rETH: number;
908
+ wstETH: number;
909
+ }> => {
910
+ // Each provider can succeed independently, and each has a bounded request.
911
+ // Preserve the existing zero fallback for callers of this optional enrichment.
912
+ const [cbETH, rETH, wstETH] = await Promise.all([
913
+ fetchFromGenericCacheApi<{ apy: string }>(
903
914
  "https://api.exchange.coinbase.com/wrapped-assets/CBETH",
904
- );
905
- result.cbETH = Number(cbETH.apy) * 100;
906
- } catch (error) {
907
- result.cbETH = 0;
908
- }
909
-
910
- try {
911
- const rETH = await fetchFromGenericCacheApi<{ rethAPR: string }>(
915
+ )
916
+ .then((result) => Number(result.apy) * 100)
917
+ .catch(() => 0),
918
+ fetchFromGenericCacheApi<{ rethAPR: string }>(
912
919
  "https://rocketpool.net/api/mainnet/payload",
913
- );
914
- result.rETH = Number(rETH.rethAPR);
915
- } catch (error) {
916
- result.rETH = 0;
917
- }
918
-
919
- try {
920
- const stETH = await fetchFromGenericCacheApi<{ data: { apr: number } }>(
920
+ )
921
+ .then((result) => Number(result.rethAPR))
922
+ .catch(() => 0),
923
+ fetchFromGenericCacheApi<{ data: { apr: number } }>(
921
924
  "https://eth-api.lido.fi/v1/protocol/steth/apr/last",
922
- );
923
- result.wstETH = stETH.data.apr;
924
- } catch (error) {
925
- result.wstETH = 0;
926
- }
927
-
928
- return result;
925
+ )
926
+ .then((result) => result.data.apr)
927
+ .catch(() => 0),
928
+ ]);
929
+ return { cbETH, rETH, wstETH };
929
930
  };
@@ -25,9 +25,14 @@ export async function getMarkets<
25
25
  const environments = getEnvironmentsFromArgs(client, args);
26
26
  const logId = logger.start("getMarkets", "Starting to get markets...");
27
27
 
28
- const settlements = await Promise.allSettled(
29
- environments.map((environment) => getMarketsData(environment)),
30
- );
28
+ const [settlements, liquidStakingRewards] = await Promise.all([
29
+ Promise.allSettled(
30
+ environments.map((environment) => getMarketsData(environment)),
31
+ ),
32
+ args?.includeLiquidStakingRewards === true
33
+ ? fetchLiquidStakingRewards()
34
+ : undefined,
35
+ ]);
31
36
 
32
37
  const result = settlements
33
38
  .filter(
@@ -35,8 +40,7 @@ export async function getMarkets<
35
40
  )
36
41
  .map((s) => s.value);
37
42
 
38
- if (args?.includeLiquidStakingRewards === true) {
39
- const liquidStakingRewards = await fetchLiquidStakingRewards();
43
+ if (liquidStakingRewards) {
40
44
  for (const item of result.flat()) {
41
45
  if (item.underlyingToken.symbol.toLowerCase() === "cbeth") {
42
46
  item.rewards.push({
@@ -15,117 +15,113 @@ export const getUserPositionData = async (params: {
15
15
  return [];
16
16
  }
17
17
 
18
- try {
19
- const [allMarketsResult, balancesResult, borrowsResult, membershipsResult] =
20
- await Promise.allSettled([
21
- viewsContract.read.getAllMarketsInfo(),
22
- viewsContract.read.getUserBalances([params.account]),
23
- viewsContract.read.getUserBorrowsBalances([params.account]),
24
- viewsContract.read.getUserMarketsMemberships([params.account]),
25
- ]);
26
-
27
- const balances =
28
- balancesResult.status === "fulfilled" ? balancesResult.value : [];
29
- const borrows =
30
- borrowsResult.status === "fulfilled" ? borrowsResult.value : [];
31
- const memberships =
32
- membershipsResult.status === "fulfilled" ? membershipsResult.value : [];
33
-
34
- // If getAllMarketsInfo failed (e.g. broken on-chain oracle), fall back to
35
- // per-mToken exchange rate calls. The user balance/borrow/membership calls
36
- // don't touch the oracle so they can still succeed.
37
- if (allMarketsResult.status === "rejected") {
38
- return getUserPositionsFromMTokenFallback(
39
- params,
40
- balances as { amount: bigint; token: `0x${string}` }[],
41
- borrows as { amount: bigint; token: `0x${string}` }[],
42
- memberships as { membership: boolean; token: `0x${string}` }[],
43
- );
44
- }
18
+ // Only getAllMarketsInfo is settled, because it has the mToken fallback
19
+ // below. The three user reads have no fallback: Promise.all lets their first
20
+ // rejection propagate instead of being treated as an empty list, which would
21
+ // misreport the user as having no position (MOO-885).
22
+ const [[allMarketsResult], balances, borrows, memberships] =
23
+ await Promise.all([
24
+ Promise.allSettled([viewsContract.read.getAllMarketsInfo()]),
25
+ viewsContract.read.getUserBalances([params.account]),
26
+ viewsContract.read.getUserBorrowsBalances([params.account]),
27
+ viewsContract.read.getUserMarketsMemberships([params.account]),
28
+ ]);
29
+
30
+ // If getAllMarketsInfo failed (e.g. broken on-chain oracle), fall back to
31
+ // per-mToken exchange rate calls. The user balance/borrow/membership calls
32
+ // don't touch the oracle so they can still succeed. The fallback reports
33
+ // every USD value as 0, so the degraded read is surfaced through onError
34
+ // instead of passing as a healthy result.
35
+ if (allMarketsResult.status === "rejected") {
36
+ params.environment.onError?.(allMarketsResult.reason, {
37
+ source: "user-positions-oracle-fallback",
38
+ chainId: params.environment.chainId,
39
+ });
40
+ return getUserPositionsFromMTokenFallback(
41
+ params,
42
+ balances,
43
+ borrows,
44
+ memberships,
45
+ );
46
+ }
45
47
 
46
- const allMarkets = allMarketsResult.value;
48
+ const allMarkets = allMarketsResult.value;
49
+
50
+ const markets = allMarkets
51
+ ?.map((marketInfo) => {
52
+ const market = findMarketByAddress(params.environment, marketInfo.market);
53
+ if (market) {
54
+ const { marketToken, underlyingToken } = market;
55
+
56
+ const underlyingPrice = new Amount(
57
+ marketInfo.underlyingPrice,
58
+ 36 - underlyingToken.decimals,
59
+ ).value;
60
+ const collateralFactor = new Amount(marketInfo.collateralFactor, 18)
61
+ .value;
62
+ const exchangeRate = new Amount(
63
+ marketInfo.exchangeRate,
64
+ 10 + underlyingToken.decimals,
65
+ ).value;
66
+
67
+ const marketCollateralEnabled =
68
+ memberships?.find((r) => r.token === marketInfo.market)
69
+ ?.membership === true;
70
+ const marketBorrowedRaw =
71
+ borrows?.find((r) => r.token === marketInfo.market)?.amount || 0n;
72
+ const marketSuppliedRaw =
73
+ balances?.find((r) => r.token === marketInfo.market)?.amount || 0n;
74
+
75
+ const borrowed = new Amount(
76
+ marketBorrowedRaw,
77
+ market.underlyingToken.decimals,
78
+ );
79
+ const borrowedUsd = borrowed.value * underlyingPrice;
47
80
 
48
- const markets = allMarkets
49
- ?.map((marketInfo) => {
50
- const market = findMarketByAddress(
51
- params.environment,
52
- marketInfo.market,
81
+ const marketSupplied = new Amount(
82
+ marketSuppliedRaw,
83
+ marketToken.decimals,
53
84
  );
54
- if (market) {
55
- const { marketToken, underlyingToken } = market;
56
-
57
- const underlyingPrice = new Amount(
58
- marketInfo.underlyingPrice,
59
- 36 - underlyingToken.decimals,
60
- ).value;
61
- const collateralFactor = new Amount(marketInfo.collateralFactor, 18)
62
- .value;
63
- const exchangeRate = new Amount(
64
- marketInfo.exchangeRate,
65
- 10 + underlyingToken.decimals,
66
- ).value;
67
-
68
- const marketCollateralEnabled =
69
- memberships?.find((r) => r.token === marketInfo.market)
70
- ?.membership === true;
71
- const marketBorrowedRaw =
72
- borrows?.find((r) => r.token === marketInfo.market)?.amount || 0n;
73
- const marketSuppliedRaw =
74
- balances?.find((r) => r.token === marketInfo.market)?.amount || 0n;
75
-
76
- const borrowed = new Amount(
77
- marketBorrowedRaw,
78
- market.underlyingToken.decimals,
79
- );
80
- const borrowedUsd = borrowed.value * underlyingPrice;
81
-
82
- const marketSupplied = new Amount(
83
- marketSuppliedRaw,
84
- marketToken.decimals,
85
- );
86
-
87
- const supplied = new Amount(
88
- marketSupplied.value * exchangeRate,
89
- underlyingToken.decimals,
90
- );
91
- const suppliedUsd = supplied.value * underlyingPrice;
92
-
93
- const collateral = marketCollateralEnabled
94
- ? new Amount(
95
- supplied.value * collateralFactor,
96
- underlyingToken.decimals,
97
- )
98
- : new Amount(0n, underlyingToken.decimals);
99
-
100
- const collateralUsd = collateral.value * underlyingPrice;
101
-
102
- const result: UserPosition = {
103
- chainId: params.environment.chainId,
104
- account: params.account,
105
- market: market.marketToken,
106
- collateralEnabled: marketCollateralEnabled,
107
- borrowed,
108
- borrowedUsd,
109
- collateral,
110
- collateralUsd,
111
- supplied,
112
- suppliedUsd,
113
- };
114
-
115
- return result;
116
- } else {
117
- return;
118
- }
119
- })
120
- .filter((r) => r !== undefined)
121
- .filter((r) =>
122
- params.markets ? params.markets.includes(r!.market.address) : true,
123
- ) as UserPosition[];
124
-
125
- return markets;
126
- } catch {
127
- return [];
128
- }
85
+
86
+ const supplied = new Amount(
87
+ marketSupplied.value * exchangeRate,
88
+ underlyingToken.decimals,
89
+ );
90
+ const suppliedUsd = supplied.value * underlyingPrice;
91
+
92
+ const collateral = marketCollateralEnabled
93
+ ? new Amount(
94
+ supplied.value * collateralFactor,
95
+ underlyingToken.decimals,
96
+ )
97
+ : new Amount(0n, underlyingToken.decimals);
98
+
99
+ const collateralUsd = collateral.value * underlyingPrice;
100
+
101
+ const result: UserPosition = {
102
+ chainId: params.environment.chainId,
103
+ account: params.account,
104
+ market: market.marketToken,
105
+ collateralEnabled: marketCollateralEnabled,
106
+ borrowed,
107
+ borrowedUsd,
108
+ collateral,
109
+ collateralUsd,
110
+ supplied,
111
+ suppliedUsd,
112
+ };
113
+
114
+ return result;
115
+ } else {
116
+ return;
117
+ }
118
+ })
119
+ .filter((r) => r !== undefined)
120
+ .filter((r) =>
121
+ params.markets ? params.markets.includes(r!.market.address) : true,
122
+ ) as UserPosition[];
123
+
124
+ return markets;
129
125
  };
130
126
 
131
127
  /**
@@ -141,9 +137,9 @@ async function getUserPositionsFromMTokenFallback(
141
137
  account: Address;
142
138
  markets?: string[] | undefined;
143
139
  },
144
- balances: { amount: bigint; token: `0x${string}` }[],
145
- borrows: { amount: bigint; token: `0x${string}` }[],
146
- memberships: { membership: boolean; token: `0x${string}` }[],
140
+ balances: readonly { amount: bigint; token: `0x${string}` }[],
141
+ borrows: readonly { amount: bigint; token: `0x${string}` }[],
142
+ memberships: readonly { membership: boolean; token: `0x${string}` }[],
147
143
  ): Promise<UserPosition[]> {
148
144
  const positions: UserPosition[] = [];
149
145
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1,6 +1,7 @@
1
1
  import type { Address, Chain } from "viem";
2
2
  import type { MoonwellClient } from "../../../client/createMoonwellClient.js";
3
3
  import { getEnvironmentsFromArgs } from "../../../common/index.js";
4
+ import { readAcrossEnvironments } from "../../../common/readAcrossEnvironments.js";
4
5
  import type { OptionalNetworkParameterType } from "../../../common/types.js";
5
6
  import type { UserPosition } from "../../../types/userPosition.js";
6
7
  import { getUserPositionData } from "./common.js";
@@ -15,6 +16,11 @@ export type GetUserPositionsParameters<
15
16
 
16
17
  export type GetUserPositionsReturnType = Promise<UserPosition[]>;
17
18
 
19
+ /**
20
+ * Rejects with a `ChainReadError` when the read fails on any requested chain,
21
+ * so a failed RPC never looks like an empty position list. The error lists the
22
+ * failed chains and carries the positions from the chains that succeeded.
23
+ */
18
24
  export async function getUserPositions<
19
25
  environments,
20
26
  Network extends Chain | undefined,
@@ -26,18 +32,13 @@ export async function getUserPositions<
26
32
 
27
33
  const environments = getEnvironmentsFromArgs(client, args);
28
34
 
29
- const settled = await Promise.allSettled(
30
- environments.map((environment) =>
35
+ return readAcrossEnvironments({
36
+ environments,
37
+ source: "getUserPositions",
38
+ read: (environment) =>
31
39
  getUserPositionData({
32
40
  environment,
33
41
  account: userAddress,
34
42
  }),
35
- ),
36
- );
37
-
38
- const result = settled.flatMap((s) =>
39
- s.status === "fulfilled" ? s.value : [],
40
- );
41
-
42
- return result;
43
+ });
43
44
  }
@@ -1,4 +1,3 @@
1
- import axios from "axios";
2
1
  import { mainnet } from "viem/chains";
3
2
  import { Amount } from "../../../common/index.js";
4
3
  import type { Environment } from "../../../environments/index.js";
@@ -23,8 +22,6 @@ const MULTICHAIN_WORMHOLE_BRIDGES: ReadonlySet<string> = new Set([
23
22
  "0x98f3c9e6e3face36baad05fe09d375ef1464288b", // Ethereum
24
23
  ]);
25
24
 
26
- axios.defaults.timeout = 5_000;
27
-
28
25
  /**
29
26
  * Extract proposal subtitle from description
30
27
  */
package/actions/index.ts CHANGED
@@ -116,6 +116,11 @@ export {
116
116
  type GetMorphoMarketsParameters,
117
117
  type GetMorphoMarketsReturnType,
118
118
  } from "./morpho/markets/getMorphoMarkets.js";
119
+ export {
120
+ getMorphoMarketsSharedLiquidity,
121
+ type GetMorphoMarketsSharedLiquidityParameters,
122
+ type GetMorphoMarketsSharedLiquidityReturnType,
123
+ } from "./morpho/markets/getMorphoMarketsSharedLiquidity.js";
119
124
  export {
120
125
  getMarketSnapshots as getMorphoMarketSnapshots,
121
126
  type GetMarketSnapshotsParameters as GetMorphoMarketSnapshotsParameters,