@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.
- package/CHANGELOG.md +36 -0
- package/_cjs/actions/axiosWithRetry.js +10 -11
- package/_cjs/actions/axiosWithRetry.js.map +1 -1
- package/_cjs/actions/core/getUserBalances.js +63 -32
- package/_cjs/actions/core/getUserBalances.js.map +1 -1
- package/_cjs/actions/core/markets/common.js +31 -42
- package/_cjs/actions/core/markets/common.js.map +1 -1
- package/_cjs/actions/core/markets/getMarkets.js +7 -3
- package/_cjs/actions/core/markets/getMarkets.js.map +1 -1
- package/_cjs/actions/core/user-positions/common.js +56 -60
- package/_cjs/actions/core/user-positions/common.js.map +1 -1
- package/_cjs/actions/core/user-positions/getUserPositions.js +9 -6
- package/_cjs/actions/core/user-positions/getUserPositions.js.map +1 -1
- package/_cjs/actions/governance/getStakingInfo.js +1 -7
- package/_cjs/actions/governance/getStakingInfo.js.map +1 -1
- package/_cjs/actions/governance/getUserStakingInfo.js +1 -7
- package/_cjs/actions/governance/getUserStakingInfo.js.map +1 -1
- package/_cjs/actions/governance/getWellPrice.js +51 -1
- package/_cjs/actions/governance/getWellPrice.js.map +1 -1
- package/_cjs/actions/governance/proposals/common.js +34 -15
- package/_cjs/actions/governance/proposals/common.js.map +1 -1
- package/_cjs/actions/governance/proposals/getProposals.js +5 -4
- package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
- package/_cjs/actions/index.js +3 -1
- package/_cjs/actions/index.js.map +1 -1
- package/_cjs/actions/morpho/markets/common.js +155 -26
- package/_cjs/actions/morpho/markets/common.js.map +1 -1
- package/_cjs/actions/morpho/markets/getMorphoMarket.js +1 -0
- package/_cjs/actions/morpho/markets/getMorphoMarket.js.map +1 -1
- package/_cjs/actions/morpho/markets/getMorphoMarkets.js +1 -0
- package/_cjs/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
- package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +46 -0
- package/_cjs/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
- package/_cjs/actions/morpho/user-positions/common.js +26 -24
- package/_cjs/actions/morpho/user-positions/common.js.map +1 -1
- package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js +7 -8
- package/_cjs/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
- package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js +7 -8
- package/_cjs/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
- package/_cjs/actions/morpho/user-rewards/common.js +1 -7
- package/_cjs/actions/morpho/user-rewards/common.js.map +1 -1
- package/_cjs/actions/morpho/vaults/common.js +104 -87
- package/_cjs/actions/morpho/vaults/common.js.map +1 -1
- package/_cjs/actions/morpho/vaults/lunarIndexerTransform.js +31 -3
- package/_cjs/actions/morpho/vaults/lunarIndexerTransform.js.map +1 -1
- package/_cjs/actions/retry.js +43 -13
- package/_cjs/actions/retry.js.map +1 -1
- package/_cjs/client/createActions.js +2 -0
- package/_cjs/client/createActions.js.map +1 -1
- package/_cjs/common/error.js +37 -1
- package/_cjs/common/error.js.map +1 -1
- package/_cjs/common/index.js +2 -1
- package/_cjs/common/index.js.map +1 -1
- package/_cjs/common/readAcrossEnvironments.js +17 -0
- package/_cjs/common/readAcrossEnvironments.js.map +1 -0
- package/_cjs/environments/types/config.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/index.js +3 -1
- package/_cjs/index.js.map +1 -1
- package/_esm/actions/axiosWithRetry.js +11 -13
- package/_esm/actions/axiosWithRetry.js.map +1 -1
- package/_esm/actions/core/getUserBalances.js +72 -35
- package/_esm/actions/core/getUserBalances.js.map +1 -1
- package/_esm/actions/core/markets/common.js +36 -43
- package/_esm/actions/core/markets/common.js.map +1 -1
- package/_esm/actions/core/markets/getMarkets.js +7 -3
- package/_esm/actions/core/markets/getMarkets.js.map +1 -1
- package/_esm/actions/core/user-positions/common.js +65 -63
- package/_esm/actions/core/user-positions/common.js.map +1 -1
- package/_esm/actions/core/user-positions/getUserPositions.js +14 -6
- package/_esm/actions/core/user-positions/getUserPositions.js.map +1 -1
- package/_esm/actions/governance/getStakingInfo.js +2 -8
- package/_esm/actions/governance/getStakingInfo.js.map +1 -1
- package/_esm/actions/governance/getUserStakingInfo.js +2 -8
- package/_esm/actions/governance/getUserStakingInfo.js.map +1 -1
- package/_esm/actions/governance/getWellPrice.js +67 -7
- package/_esm/actions/governance/getWellPrice.js.map +1 -1
- package/_esm/actions/governance/proposals/common.js +37 -12
- package/_esm/actions/governance/proposals/common.js.map +1 -1
- package/_esm/actions/governance/proposals/getProposals.js +7 -5
- package/_esm/actions/governance/proposals/getProposals.js.map +1 -1
- package/_esm/actions/index.js +1 -0
- package/_esm/actions/index.js.map +1 -1
- package/_esm/actions/morpho/markets/common.js +168 -27
- package/_esm/actions/morpho/markets/common.js.map +1 -1
- package/_esm/actions/morpho/markets/getMorphoMarket.js +1 -0
- package/_esm/actions/morpho/markets/getMorphoMarket.js.map +1 -1
- package/_esm/actions/morpho/markets/getMorphoMarkets.js +1 -0
- package/_esm/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
- package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js +48 -0
- package/_esm/actions/morpho/markets/getMorphoMarketsSharedLiquidity.js.map +1 -0
- package/_esm/actions/morpho/user-positions/common.js +31 -24
- package/_esm/actions/morpho/user-positions/common.js.map +1 -1
- package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js +12 -8
- package/_esm/actions/morpho/user-positions/getMorphoMarketUserPositions.js.map +1 -1
- package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js +12 -8
- package/_esm/actions/morpho/user-positions/getMorphoVaultUserPositions.js.map +1 -1
- package/_esm/actions/morpho/user-rewards/common.js +2 -8
- package/_esm/actions/morpho/user-rewards/common.js.map +1 -1
- package/_esm/actions/morpho/vaults/common.js +110 -91
- package/_esm/actions/morpho/vaults/common.js.map +1 -1
- package/_esm/actions/morpho/vaults/lunarIndexerTransform.js +36 -4
- package/_esm/actions/morpho/vaults/lunarIndexerTransform.js.map +1 -1
- package/_esm/actions/retry.js +45 -15
- package/_esm/actions/retry.js.map +1 -1
- package/_esm/client/createActions.js +2 -0
- package/_esm/client/createActions.js.map +1 -1
- package/_esm/common/error.js +49 -0
- package/_esm/common/error.js.map +1 -1
- package/_esm/common/index.js +1 -1
- package/_esm/common/index.js.map +1 -1
- package/_esm/common/readAcrossEnvironments.js +30 -0
- package/_esm/common/readAcrossEnvironments.js.map +1 -0
- package/_esm/environments/types/config.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/index.js +1 -0
- package/_esm/index.js.map +1 -1
- package/_types/actions/axiosWithRetry.d.ts +1 -0
- package/_types/actions/axiosWithRetry.d.ts.map +1 -1
- package/_types/actions/core/getUserBalances.d.ts.map +1 -1
- package/_types/actions/core/markets/common.d.ts.map +1 -1
- package/_types/actions/core/markets/getMarkets.d.ts.map +1 -1
- package/_types/actions/core/user-positions/common.d.ts.map +1 -1
- package/_types/actions/core/user-positions/getUserPositions.d.ts +5 -0
- package/_types/actions/core/user-positions/getUserPositions.d.ts.map +1 -1
- package/_types/actions/governance/getStakingInfo.d.ts.map +1 -1
- package/_types/actions/governance/getUserStakingInfo.d.ts.map +1 -1
- package/_types/actions/governance/getWellPrice.d.ts +9 -1
- package/_types/actions/governance/getWellPrice.d.ts.map +1 -1
- package/_types/actions/governance/proposals/common.d.ts.map +1 -1
- package/_types/actions/governance/proposals/getProposals.d.ts +10 -1
- package/_types/actions/governance/proposals/getProposals.d.ts.map +1 -1
- package/_types/actions/index.d.ts +1 -0
- package/_types/actions/index.d.ts.map +1 -1
- package/_types/actions/morpho/markets/common.d.ts +7 -10
- package/_types/actions/morpho/markets/common.d.ts.map +1 -1
- package/_types/actions/morpho/markets/getMorphoMarket.d.ts +2 -0
- package/_types/actions/morpho/markets/getMorphoMarket.d.ts.map +1 -1
- package/_types/actions/morpho/markets/getMorphoMarkets.d.ts +2 -0
- package/_types/actions/morpho/markets/getMorphoMarkets.d.ts.map +1 -1
- package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts +17 -0
- package/_types/actions/morpho/markets/getMorphoMarketsSharedLiquidity.d.ts.map +1 -0
- package/_types/actions/morpho/user-positions/common.d.ts.map +1 -1
- package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts +5 -0
- package/_types/actions/morpho/user-positions/getMorphoMarketUserPositions.d.ts.map +1 -1
- package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts +5 -0
- package/_types/actions/morpho/user-positions/getMorphoVaultUserPositions.d.ts.map +1 -1
- package/_types/actions/morpho/user-rewards/common.d.ts.map +1 -1
- package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
- package/_types/actions/morpho/vaults/lunarIndexerTransform.d.ts.map +1 -1
- package/_types/actions/retry.d.ts +5 -4
- package/_types/actions/retry.d.ts.map +1 -1
- package/_types/client/createActions.d.ts +2 -0
- package/_types/client/createActions.d.ts.map +1 -1
- package/_types/common/error.d.ts +31 -0
- package/_types/common/error.d.ts.map +1 -1
- package/_types/common/index.d.ts +2 -2
- package/_types/common/index.d.ts.map +1 -1
- package/_types/common/readAcrossEnvironments.d.ts +23 -0
- package/_types/common/readAcrossEnvironments.d.ts.map +1 -0
- package/_types/environments/types/config.d.ts +11 -1
- package/_types/environments/types/config.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/index.d.ts +3 -1
- package/_types/index.d.ts.map +1 -1
- package/_types/types/morphoMarket.d.ts +9 -0
- package/_types/types/morphoMarket.d.ts.map +1 -1
- package/actions/axiosWithRetry.ts +19 -13
- package/actions/core/getUserBalances.ts +98 -51
- package/actions/core/markets/common.ts +49 -51
- package/actions/core/markets/getMarkets.ts +9 -5
- package/actions/core/user-positions/common.ts +107 -111
- package/actions/core/user-positions/getUserPositions.ts +11 -10
- package/actions/governance/getStakingInfo.ts +2 -9
- package/actions/governance/getUserStakingInfo.ts +2 -8
- package/actions/governance/getWellPrice.ts +99 -7
- package/actions/governance/proposals/common.ts +44 -19
- package/actions/governance/proposals/getProposals.ts +22 -5
- package/actions/index.ts +5 -0
- package/actions/morpho/markets/common.ts +324 -125
- package/actions/morpho/markets/getMorphoMarket.ts +3 -0
- package/actions/morpho/markets/getMorphoMarkets.ts +3 -0
- package/actions/morpho/markets/getMorphoMarketsSharedLiquidity.ts +93 -0
- package/actions/morpho/user-positions/common.ts +48 -42
- package/actions/morpho/user-positions/getMorphoMarketUserPositions.ts +14 -15
- package/actions/morpho/user-positions/getMorphoVaultUserPositions.ts +14 -15
- package/actions/morpho/user-rewards/common.ts +2 -8
- package/actions/morpho/vaults/common.ts +161 -127
- package/actions/morpho/vaults/lunarIndexerTransform.ts +41 -6
- package/actions/retry.ts +53 -18
- package/client/createActions.ts +13 -0
- package/common/error.ts +45 -0
- package/common/index.ts +2 -2
- package/common/readAcrossEnvironments.ts +45 -0
- package/environments/types/config.ts +11 -1
- package/errors/version.ts +1 -1
- package/index.ts +3 -0
- package/package.json +1 -1
- package/types/morphoMarket.ts +10 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { MoonwellClient } from "../../../client/createMoonwellClient.js";
|
|
2
|
+
import { getEnvironmentFromArgs } from "../../../common/index.js";
|
|
3
|
+
import type { NetworkParameterType } from "../../../common/types.js";
|
|
4
|
+
import type { Chain } from "../../../environments/index.js";
|
|
5
|
+
import type {
|
|
6
|
+
MorphoMarket,
|
|
7
|
+
MorphoMarketSharedLiquidity,
|
|
8
|
+
} from "../../../types/morphoMarket.js";
|
|
9
|
+
import {
|
|
10
|
+
computeSharedLiquidityFromLunar,
|
|
11
|
+
fetchSharedLiquidityFromLunar,
|
|
12
|
+
} from "./common.js";
|
|
13
|
+
|
|
14
|
+
export type GetMorphoMarketsSharedLiquidityParameters<
|
|
15
|
+
environments,
|
|
16
|
+
network extends Chain | undefined,
|
|
17
|
+
> = NetworkParameterType<environments, network> & {
|
|
18
|
+
/** Pass the full chain's base market result to retain allocation parameters. */
|
|
19
|
+
markets: readonly MorphoMarket[];
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
/** Overall deadline, including retries and backoff. Defaults to 15 seconds. */
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type GetMorphoMarketsSharedLiquidityReturnType = Promise<
|
|
26
|
+
MorphoMarketSharedLiquidity[]
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
/** Fetch allocator liquidity independently, without refetching base market data.
|
|
30
|
+
* Rejects on failure so callers can retain the previous successful snapshot and
|
|
31
|
+
* distinguish unavailable liquidity from a successful empty allocation list. */
|
|
32
|
+
export async function getMorphoMarketsSharedLiquidity<
|
|
33
|
+
environments,
|
|
34
|
+
Network extends Chain | undefined,
|
|
35
|
+
>(
|
|
36
|
+
client: MoonwellClient,
|
|
37
|
+
args: GetMorphoMarketsSharedLiquidityParameters<environments, Network>,
|
|
38
|
+
): GetMorphoMarketsSharedLiquidityReturnType {
|
|
39
|
+
const environment = getEnvironmentFromArgs(client, args);
|
|
40
|
+
if (!environment?.lunarIndexerUrl) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
"Independent shared liquidity requires a configured Lunar Indexer environment",
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (args.markets.some((market) => market.chainId !== environment.chainId)) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
"Shared-liquidity markets must belong to the requested chain",
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (args.markets.length === 0) return [];
|
|
51
|
+
|
|
52
|
+
const marketParamsMap = new Map(
|
|
53
|
+
args.markets.map((market) => [
|
|
54
|
+
market.marketId.toLowerCase(),
|
|
55
|
+
{
|
|
56
|
+
oracle: market.marketParams.oracle,
|
|
57
|
+
irm: market.marketParams.irm,
|
|
58
|
+
lltv: market.marketParams.lltv.toString(),
|
|
59
|
+
// Display token metadata can use the native-token zero address for ETH.
|
|
60
|
+
// Allocator transactions need the actual ERC20 addresses from Morpho.
|
|
61
|
+
loanToken: {
|
|
62
|
+
address: market.marketParams.loanToken,
|
|
63
|
+
decimals: market.loanToken.decimals,
|
|
64
|
+
},
|
|
65
|
+
collateralToken: {
|
|
66
|
+
address: market.marketParams.collateralToken,
|
|
67
|
+
decimals: market.collateralToken.decimals,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
]),
|
|
71
|
+
);
|
|
72
|
+
try {
|
|
73
|
+
const data = await fetchSharedLiquidityFromLunar(
|
|
74
|
+
environment.lunarIndexerUrl,
|
|
75
|
+
environment.chainId,
|
|
76
|
+
args,
|
|
77
|
+
);
|
|
78
|
+
return computeSharedLiquidityFromLunar(
|
|
79
|
+
data,
|
|
80
|
+
args.markets.map((market) => market.marketId),
|
|
81
|
+
marketParamsMap,
|
|
82
|
+
environment.chainId,
|
|
83
|
+
);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (!args.signal?.aborted) {
|
|
86
|
+
environment.onError?.(error, {
|
|
87
|
+
source: "morpho-shared-liquidity",
|
|
88
|
+
chainId: environment.chainId,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -59,50 +59,56 @@ export async function getMorphoMarketUserPositionsData(params: {
|
|
|
59
59
|
account: Address;
|
|
60
60
|
markets?: string[] | undefined;
|
|
61
61
|
}): Promise<MorphoMarketUserPosition[]> {
|
|
62
|
+
// A chain without a Morpho deployment has no positions to read. Both the
|
|
63
|
+
// plural action and the singular getMorphoMarketUserPosition come through
|
|
64
|
+
// here, so the guard lives at the source rather than in each caller.
|
|
65
|
+
const morphoViews = params.environment.contracts.morphoViews;
|
|
66
|
+
if (!morphoViews) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
const markets = Object.values(params.environment.config.morphoMarkets).filter(
|
|
63
71
|
(market) => (params.markets ? params.markets.includes(market.id) : true),
|
|
64
72
|
);
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
return [];
|
|
107
|
-
}
|
|
74
|
+
// A failed read must propagate: swallowing it here made a Base RPC outage
|
|
75
|
+
// look like "user has no isolated positions" (MOO-884).
|
|
76
|
+
const userMarketPositions = await morphoViews.read.getMorphoBlueUserBalances([
|
|
77
|
+
markets.map((market) => market.id),
|
|
78
|
+
params.account,
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
return markets.map((market, index) => {
|
|
82
|
+
const position = userMarketPositions[index];
|
|
83
|
+
|
|
84
|
+
const loanToken = params.environment.config.tokens[market.loanToken];
|
|
85
|
+
|
|
86
|
+
const collateralToken =
|
|
87
|
+
params.environment.config.tokens[market.collateralToken];
|
|
88
|
+
|
|
89
|
+
const supplied = new Amount(
|
|
90
|
+
position.collateralAssets,
|
|
91
|
+
collateralToken.decimals,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const borrowed = new Amount(position.loanAssets, loanToken.decimals);
|
|
95
|
+
|
|
96
|
+
const borrowedShares = new Amount(
|
|
97
|
+
position.loanShares,
|
|
98
|
+
loanToken.decimals + 6,
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
const result: MorphoMarketUserPosition = {
|
|
102
|
+
chainId: params.environment.chainId,
|
|
103
|
+
account: params.account,
|
|
104
|
+
marketId: market.id,
|
|
105
|
+
loanToken,
|
|
106
|
+
collateralToken,
|
|
107
|
+
supplied,
|
|
108
|
+
borrowed,
|
|
109
|
+
borrowedShares,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return result;
|
|
113
|
+
});
|
|
108
114
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Address } 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 { Chain } from "../../../environments/index.js";
|
|
6
7
|
import type { MorphoMarketUserPosition } from "../../../types/morphoUserPosition.js";
|
|
@@ -17,6 +18,11 @@ export type GetMorphoMarketUserPositionsReturnType = Promise<
|
|
|
17
18
|
MorphoMarketUserPosition[]
|
|
18
19
|
>;
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Rejects with a `ChainReadError` when the read fails on any requested chain,
|
|
23
|
+
* so a failed RPC never looks like an empty position list. The error lists the
|
|
24
|
+
* failed chains and carries the positions from the chains that succeeded.
|
|
25
|
+
*/
|
|
20
26
|
export async function getMorphoMarketUserPositions<
|
|
21
27
|
environments,
|
|
22
28
|
Network extends Chain | undefined,
|
|
@@ -26,20 +32,13 @@ export async function getMorphoMarketUserPositions<
|
|
|
26
32
|
): GetMorphoMarketUserPositionsReturnType {
|
|
27
33
|
const environments = getEnvironmentsFromArgs(client, args);
|
|
28
34
|
|
|
29
|
-
|
|
30
|
-
environments
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
35
|
+
return readAcrossEnvironments({
|
|
36
|
+
environments,
|
|
37
|
+
source: "getMorphoMarketUserPositions",
|
|
38
|
+
read: (environment) =>
|
|
39
|
+
getMorphoMarketUserPositionsData({
|
|
40
|
+
environment,
|
|
41
|
+
account: args.userAddress,
|
|
37
42
|
}),
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const result = settled.flatMap((s) =>
|
|
41
|
-
s.status === "fulfilled" ? s.value : [],
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
return result;
|
|
43
|
+
});
|
|
45
44
|
}
|
|
@@ -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 { MorphoVaultUserPosition } from "../../../types/morphoUserPosition.js";
|
|
6
7
|
import { getMorphoVaultUserPositionsData } from "./common.js";
|
|
@@ -16,6 +17,11 @@ export type GetMorphoVaultUserPositionsReturnType = Promise<
|
|
|
16
17
|
MorphoVaultUserPosition[]
|
|
17
18
|
>;
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Rejects with a `ChainReadError` when the read fails on any requested chain,
|
|
22
|
+
* so a failed RPC never looks like an empty position list. The error lists the
|
|
23
|
+
* failed chains and carries the positions from the chains that succeeded.
|
|
24
|
+
*/
|
|
19
25
|
export async function getMorphoVaultUserPositions<
|
|
20
26
|
environments,
|
|
21
27
|
Network extends Chain | undefined,
|
|
@@ -25,20 +31,13 @@ export async function getMorphoVaultUserPositions<
|
|
|
25
31
|
): GetMorphoVaultUserPositionsReturnType {
|
|
26
32
|
const environments = getEnvironmentsFromArgs(client, args);
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
environments
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
34
|
+
return readAcrossEnvironments({
|
|
35
|
+
environments,
|
|
36
|
+
source: "getMorphoVaultUserPositions",
|
|
37
|
+
read: (environment) =>
|
|
38
|
+
getMorphoVaultUserPositionsData({
|
|
39
|
+
environment,
|
|
40
|
+
account: args.userAddress,
|
|
36
41
|
}),
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
const result = settled.flatMap((s) =>
|
|
40
|
-
s.status === "fulfilled" ? s.value : [],
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
return result;
|
|
42
|
+
});
|
|
44
43
|
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
} from "../../../environments/utils/index.js";
|
|
14
14
|
import type { MorphoUserReward } from "../../../types/morphoUserReward.js";
|
|
15
15
|
import type { MorphoUserStakingReward } from "../../../types/morphoUserStakingReward.js";
|
|
16
|
-
import {
|
|
16
|
+
import { getGovernanceTokenPriceOrZero } from "../../governance/getWellPrice.js";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Error thrown for any failure communicating with the Merkl API: non-ok HTTP
|
|
@@ -166,13 +166,7 @@ export async function getUserMorphoStakingRewardsData(params: {
|
|
|
166
166
|
await Promise.all([
|
|
167
167
|
viewsContract?.read.getAllMarketsInfo(),
|
|
168
168
|
homeViewsContract?.read.getNativeTokenPrice(),
|
|
169
|
-
|
|
170
|
-
params.environment.onError?.(err, {
|
|
171
|
-
source: "governance-token-price",
|
|
172
|
-
chainId: params.environment.chainId,
|
|
173
|
-
});
|
|
174
|
-
return 0n;
|
|
175
|
-
}),
|
|
169
|
+
getGovernanceTokenPriceOrZero(params.environment),
|
|
176
170
|
]);
|
|
177
171
|
|
|
178
172
|
const governanceTokenPrice = new Amount(governanceTokenPriceRaw, 18);
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
MorphoVault,
|
|
20
20
|
MorphoVaultMarket,
|
|
21
21
|
} from "../../../types/morphoVault.js";
|
|
22
|
-
import {
|
|
22
|
+
import { getGovernanceTokenPriceOrZero } from "../../governance/getWellPrice.js";
|
|
23
23
|
import { getGraphQL, getVaultV2Apy } from "../utils/graphql.js";
|
|
24
24
|
import {
|
|
25
25
|
SECONDS_PER_YEAR,
|
|
@@ -300,144 +300,184 @@ async function getMorphoVaultsDataFromIndexer(params: {
|
|
|
300
300
|
|
|
301
301
|
// Add staking rewards if includeRewards is true
|
|
302
302
|
if (params.includeRewards) {
|
|
303
|
+
const vaultsByEnvironment = new Map<
|
|
304
|
+
Environment,
|
|
305
|
+
{ vault: MorphoVault; multiReward: Address }[]
|
|
306
|
+
>();
|
|
303
307
|
for (const vault of allVaults) {
|
|
304
308
|
const environment = environments.find(
|
|
305
309
|
(env) => env.chainId === vault.chainId,
|
|
306
310
|
);
|
|
307
311
|
if (!environment) continue;
|
|
308
312
|
|
|
309
|
-
const
|
|
310
|
-
|
|
313
|
+
const multiReward =
|
|
314
|
+
environment.config.vaults[vault.vaultKey]?.multiReward;
|
|
315
|
+
if (!multiReward) continue;
|
|
311
316
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
e.custom?.governance?.chainIds?.includes(environment.chainId),
|
|
317
|
-
) || environment;
|
|
318
|
-
|
|
319
|
-
const viewsContract = environment.contracts.views;
|
|
320
|
-
const homeViewsContract = homeEnvironment.contracts.views;
|
|
321
|
-
|
|
322
|
-
const data = await Promise.all([
|
|
323
|
-
viewsContract?.read.getAllMarketsInfo(),
|
|
324
|
-
homeViewsContract?.read.getNativeTokenPrice(),
|
|
325
|
-
getGovernanceTokenPriceFor(environment).catch((err) => {
|
|
326
|
-
environment.onError?.(err, {
|
|
327
|
-
source: "governance-token-price",
|
|
328
|
-
chainId: environment.chainId,
|
|
329
|
-
});
|
|
330
|
-
return 0n;
|
|
331
|
-
}),
|
|
332
|
-
]);
|
|
317
|
+
const group = vaultsByEnvironment.get(environment) ?? [];
|
|
318
|
+
group.push({ vault, multiReward });
|
|
319
|
+
vaultsByEnvironment.set(environment, group);
|
|
320
|
+
}
|
|
333
321
|
|
|
334
|
-
|
|
322
|
+
// Price reads are per environment, not per vault: read them once per
|
|
323
|
+
// environment (in parallel across environments) and report failures once.
|
|
324
|
+
await Promise.all(
|
|
325
|
+
[...vaultsByEnvironment].map(([environment, group]) =>
|
|
326
|
+
addStakingRewardsForEnvironment(environment, group),
|
|
327
|
+
),
|
|
328
|
+
);
|
|
329
|
+
}
|
|
335
330
|
|
|
336
|
-
|
|
337
|
-
|
|
331
|
+
return [...allVaults, ...fallbackVaults];
|
|
332
|
+
}
|
|
338
333
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
},
|
|
369
|
-
];
|
|
370
|
-
}
|
|
334
|
+
async function getStakingRewardTokenPrices(
|
|
335
|
+
environment: Environment,
|
|
336
|
+
): Promise<{ token: TokenConfig; tokenPrice: Amount }[]> {
|
|
337
|
+
// Fetch market prices from the views contract to calculate rewards
|
|
338
|
+
const homeEnvironment =
|
|
339
|
+
(Object.values(publicEnvironments) as Environment[]).find((e) =>
|
|
340
|
+
e.custom?.governance?.chainIds?.includes(environment.chainId),
|
|
341
|
+
) || environment;
|
|
342
|
+
|
|
343
|
+
const [allMarkets, nativeTokenPriceRaw, governanceTokenPriceRaw] =
|
|
344
|
+
await Promise.all([
|
|
345
|
+
environment.contracts.views?.read.getAllMarketsInfo(),
|
|
346
|
+
homeEnvironment.contracts.views?.read.getNativeTokenPrice(),
|
|
347
|
+
getGovernanceTokenPriceOrZero(environment),
|
|
348
|
+
]);
|
|
349
|
+
|
|
350
|
+
const tokenPrices: { token: TokenConfig; tokenPrice: Amount }[] = [];
|
|
351
|
+
for (const marketInfo of allMarkets ?? []) {
|
|
352
|
+
const marketFound = findMarketByAddress(environment, marketInfo.market);
|
|
353
|
+
if (marketFound) {
|
|
354
|
+
tokenPrices.push({
|
|
355
|
+
token: marketFound.underlyingToken,
|
|
356
|
+
tokenPrice: new Amount(
|
|
357
|
+
marketInfo.underlyingPrice,
|
|
358
|
+
36 - marketFound.underlyingToken.decimals,
|
|
359
|
+
),
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
371
363
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
364
|
+
// Add governance token to token prices
|
|
365
|
+
const governanceToken = environment.custom?.governance?.token
|
|
366
|
+
? environment.config.tokens[environment.custom.governance.token]
|
|
367
|
+
: undefined;
|
|
368
|
+
if (governanceToken) {
|
|
369
|
+
tokenPrices.push({
|
|
370
|
+
token: governanceToken,
|
|
371
|
+
tokenPrice: new Amount(governanceTokenPriceRaw, 18),
|
|
372
|
+
});
|
|
373
|
+
}
|
|
380
374
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
375
|
+
// Add native token to token prices
|
|
376
|
+
const nativeToken = findTokenByAddress(environment, zeroAddress);
|
|
377
|
+
if (nativeToken) {
|
|
378
|
+
tokenPrices.push({
|
|
379
|
+
token: nativeToken,
|
|
380
|
+
tokenPrice: new Amount(nativeTokenPriceRaw ?? 0n, 18),
|
|
381
|
+
});
|
|
382
|
+
}
|
|
385
383
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
vaultConfig.multiReward,
|
|
389
|
-
);
|
|
384
|
+
return tokenPrices;
|
|
385
|
+
}
|
|
390
386
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
)
|
|
397
|
-
.forEach((reward) => {
|
|
398
|
-
const token = Object.values(environment.config.tokens).find(
|
|
399
|
-
(token) => token.address === reward?.token,
|
|
400
|
-
);
|
|
401
|
-
if (!token || !reward?.rewardRate) return;
|
|
387
|
+
async function addStakingRewardsForEnvironment(
|
|
388
|
+
environment: Environment,
|
|
389
|
+
group: { vault: MorphoVault; multiReward: Address }[],
|
|
390
|
+
): Promise<void> {
|
|
391
|
+
const vaultKeys = group.map(({ vault }) => vault.vaultKey);
|
|
402
392
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
393
|
+
let tokenPrices: { token: TokenConfig; tokenPrice: Amount }[];
|
|
394
|
+
try {
|
|
395
|
+
tokenPrices = await getStakingRewardTokenPrices(environment);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
console.warn(
|
|
398
|
+
`Failed to fetch staking reward prices for chain ${environment.chainId}:`,
|
|
399
|
+
error,
|
|
400
|
+
);
|
|
401
|
+
environment.onError?.(error, {
|
|
402
|
+
source: "morpho-vault-staking-rewards",
|
|
403
|
+
chainId: environment.chainId,
|
|
404
|
+
operation: "staking-reward-prices",
|
|
405
|
+
failedCount: group.length,
|
|
406
|
+
totalCount: group.length,
|
|
407
|
+
items: vaultKeys,
|
|
408
|
+
});
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
406
411
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
412
|
+
const settlements = await Promise.allSettled(
|
|
413
|
+
group.map(async ({ vault, multiReward }) => {
|
|
414
|
+
const [rewards, distributorTotalSupply] = await Promise.all([
|
|
415
|
+
getRewardsData(environment, multiReward),
|
|
416
|
+
getTotalSupplyData(environment, multiReward),
|
|
417
|
+
]);
|
|
418
|
+
|
|
419
|
+
rewards
|
|
420
|
+
.filter(
|
|
421
|
+
(reward) =>
|
|
422
|
+
reward?.periodFinish &&
|
|
423
|
+
dayjs.utc().isBefore(dayjs.unix(Number(reward.periodFinish))),
|
|
424
|
+
)
|
|
425
|
+
.forEach((reward) => {
|
|
426
|
+
const token = Object.values(environment.config.tokens).find(
|
|
427
|
+
(token) => token.address === reward?.token,
|
|
428
|
+
);
|
|
429
|
+
if (!token || !reward?.rewardRate) return;
|
|
430
|
+
|
|
431
|
+
const market = tokenPrices.find(
|
|
432
|
+
(m) => m?.token.address === reward.token,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
const rewardPriceUsd = market?.tokenPrice.value ?? 0;
|
|
436
|
+
|
|
437
|
+
const rewardsPerYear =
|
|
438
|
+
new Amount(reward.rewardRate, market?.token.decimals ?? 18).value *
|
|
439
|
+
SECONDS_PER_YEAR *
|
|
440
|
+
rewardPriceUsd;
|
|
441
|
+
|
|
442
|
+
vault.stakingRewards.push({
|
|
443
|
+
apr:
|
|
444
|
+
(rewardsPerYear /
|
|
445
|
+
(new Amount(distributorTotalSupply, vault.vaultToken.decimals)
|
|
446
|
+
.value *
|
|
447
|
+
vault.underlyingPrice)) *
|
|
448
|
+
100,
|
|
449
|
+
token: token,
|
|
424
450
|
});
|
|
451
|
+
});
|
|
425
452
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
`Failed to fetch staking rewards for vault ${vault.vaultKey}:`,
|
|
434
|
-
error,
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
453
|
+
vault.stakingRewardsApr = vault.stakingRewards.reduce(
|
|
454
|
+
(acc, curr) => acc + curr.apr,
|
|
455
|
+
0,
|
|
456
|
+
);
|
|
457
|
+
vault.totalStakingApr = vault.stakingRewardsApr + vault.baseApy;
|
|
458
|
+
}),
|
|
459
|
+
);
|
|
439
460
|
|
|
440
|
-
|
|
461
|
+
const failedVaultKeys = vaultKeys.filter(
|
|
462
|
+
(_, i) => settlements[i]?.status === "rejected",
|
|
463
|
+
);
|
|
464
|
+
const firstFailure = settlements.find(
|
|
465
|
+
(s): s is PromiseRejectedResult => s.status === "rejected",
|
|
466
|
+
);
|
|
467
|
+
if (firstFailure) {
|
|
468
|
+
console.warn(
|
|
469
|
+
`Failed to fetch staking rewards for vault(s) ${failedVaultKeys.join(", ")} (chain ${environment.chainId}):`,
|
|
470
|
+
firstFailure.reason,
|
|
471
|
+
);
|
|
472
|
+
environment.onError?.(firstFailure.reason, {
|
|
473
|
+
source: "morpho-vault-staking-rewards",
|
|
474
|
+
chainId: environment.chainId,
|
|
475
|
+
operation: "staking-rewards",
|
|
476
|
+
failedCount: failedVaultKeys.length,
|
|
477
|
+
totalCount: group.length,
|
|
478
|
+
items: failedVaultKeys,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
441
481
|
}
|
|
442
482
|
|
|
443
483
|
export async function getMorphoVaultsData(params: {
|
|
@@ -1060,13 +1100,7 @@ async function getMorphoVaultsDataFromOnChain(params: {
|
|
|
1060
1100
|
const data = await Promise.all([
|
|
1061
1101
|
viewsContract?.read.getAllMarketsInfo(),
|
|
1062
1102
|
homeViewsContract?.read.getNativeTokenPrice(),
|
|
1063
|
-
|
|
1064
|
-
environment.onError?.(err, {
|
|
1065
|
-
source: "governance-token-price",
|
|
1066
|
-
chainId: environment.chainId,
|
|
1067
|
-
});
|
|
1068
|
-
return 0n;
|
|
1069
|
-
}),
|
|
1103
|
+
getGovernanceTokenPriceOrZero(environment),
|
|
1070
1104
|
]);
|
|
1071
1105
|
|
|
1072
1106
|
const [allMarkets, nativeTokenPriceRaw, governanceTokenPriceRaw] = data;
|