@moonwell-fi/moonwell-sdk 0.9.21 → 0.9.23

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 (37) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/_cjs/actions/governance/common.js +33 -4
  3. package/_cjs/actions/governance/common.js.map +1 -1
  4. package/_cjs/actions/morpho/vaults/common.js +61 -2
  5. package/_cjs/actions/morpho/vaults/common.js.map +1 -1
  6. package/_cjs/environments/definitions/base/morpho-markets.js +0 -5
  7. package/_cjs/environments/definitions/base/morpho-markets.js.map +1 -1
  8. package/_cjs/environments/definitions/base/morpho-vaults.js +3 -3
  9. package/_cjs/environments/definitions/base/morpho-vaults.js.map +1 -1
  10. package/_cjs/environments/definitions/base/tokens.js +5 -5
  11. package/_cjs/errors/version.js +1 -1
  12. package/_esm/actions/governance/common.js +35 -4
  13. package/_esm/actions/governance/common.js.map +1 -1
  14. package/_esm/actions/morpho/vaults/common.js +85 -6
  15. package/_esm/actions/morpho/vaults/common.js.map +1 -1
  16. package/_esm/environments/definitions/base/morpho-markets.js +0 -5
  17. package/_esm/environments/definitions/base/morpho-markets.js.map +1 -1
  18. package/_esm/environments/definitions/base/morpho-vaults.js +3 -3
  19. package/_esm/environments/definitions/base/morpho-vaults.js.map +1 -1
  20. package/_esm/environments/definitions/base/tokens.js +5 -5
  21. package/_esm/errors/version.js +1 -1
  22. package/_types/actions/governance/common.d.ts.map +1 -1
  23. package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
  24. package/_types/client/createMoonwellClient.d.ts +32 -32
  25. package/_types/environments/definitions/base/morpho-markets.d.ts +0 -5
  26. package/_types/environments/definitions/base/morpho-markets.d.ts.map +1 -1
  27. package/_types/environments/definitions/base/morpho-vaults.d.ts +3 -3
  28. package/_types/environments/definitions/base/tokens.d.ts +5 -5
  29. package/_types/environments/index.d.ts +8 -8
  30. package/_types/errors/version.d.ts +1 -1
  31. package/actions/governance/common.ts +51 -4
  32. package/actions/morpho/vaults/common.ts +208 -7
  33. package/environments/definitions/base/morpho-markets.ts +0 -5
  34. package/environments/definitions/base/morpho-vaults.ts +3 -3
  35. package/environments/definitions/base/tokens.ts +5 -5
  36. package/errors/version.ts +1 -1
  37. package/package.json +1 -1
@@ -28,6 +28,108 @@ import {
28
28
  wMulDown,
29
29
  } from "../utils/math.js";
30
30
 
31
+ /**
32
+ * Morpho Vault Data Aggregation
33
+ *
34
+ * This module handles data retrieval for both V1 (MetaMorpho) and V2 (Morpho Vault) vaults.
35
+ *
36
+ * IMPORTANT: Vault Key Naming Convention
37
+ * ------------------------------------------
38
+ * V2 vaults wrap V1 vaults, creating a nested structure. The naming convention reflects this:
39
+ *
40
+ * - `meUSDC` = V2 vault (version 2) - wraps the V1 vault below
41
+ * - `meUSDCv1` = V1 vault (version 1) - the underlying vault wrapped by V2
42
+ *
43
+ * The V2 vault allocates its assets to one or more V1 vaults via adapters.
44
+ * Market allocations for V2 vaults are calculated by scaling the V1 vault's
45
+ * market positions based on V2's ownership percentage in the V1 vault.
46
+ *
47
+ * Example:
48
+ * - meUSDC (V2) owns 60% of meUSDCv1 (V1)
49
+ * - meUSDCv1 (V1) has 100 USDC supplied to Market A
50
+ * - meUSDC's (V2) effective supply to Market A = 60 USDC
51
+ *
52
+ * @module morpho/vaults/common
53
+ */
54
+
55
+ // Type definitions for V2 vault data structures
56
+ type MorphoViewsV2GetVaultsInfoReturn = readonly {
57
+ readonly vault: Address;
58
+ readonly totalSupply: bigint;
59
+ readonly totalAssets: bigint;
60
+ readonly underlyingPrice: bigint;
61
+ readonly adapters: readonly {
62
+ readonly adapter: Address;
63
+ readonly realAssets: bigint;
64
+ readonly underlyingVault: Address;
65
+ readonly underlyingVaultName: string;
66
+ readonly underlyingVaultTotalAssets: bigint;
67
+ readonly underlyingVaultFee: bigint;
68
+ readonly underlyingVaultTimelock: bigint;
69
+ readonly allocationPercentage: bigint;
70
+ readonly underlyingMarkets: readonly {
71
+ readonly marketId: `0x${string}`;
72
+ readonly collateralToken: Address;
73
+ readonly collateralName: string;
74
+ readonly collateralSymbol: string;
75
+ readonly marketLiquidity: bigint;
76
+ readonly marketLltv: bigint;
77
+ readonly marketSupplyApy: bigint;
78
+ readonly marketBorrowApy: bigint;
79
+ }[];
80
+ }[];
81
+ }[];
82
+
83
+ type V2VaultInfo = MorphoViewsV2GetVaultsInfoReturn[number];
84
+ type AdapterInfo = V2VaultInfo["adapters"][number];
85
+ type UnderlyingMarket = AdapterInfo["underlyingMarkets"][number];
86
+
87
+ // Type definitions for V1 vault data structures
88
+ type MorphoViewsGetVaultsInfoReturn = readonly {
89
+ readonly vault: Address;
90
+ readonly totalSupply: bigint;
91
+ readonly totalAssets: bigint;
92
+ readonly underlyingPrice: bigint;
93
+ readonly fee: bigint;
94
+ readonly timelock: bigint;
95
+ readonly markets: readonly {
96
+ readonly marketId: `0x${string}`;
97
+ readonly marketCollateral: Address;
98
+ readonly marketCollateralName: string;
99
+ readonly marketCollateralSymbol: string;
100
+ readonly marketLltv: bigint;
101
+ readonly marketApy: bigint;
102
+ readonly marketLiquidity: bigint;
103
+ readonly vaultSupplied: bigint;
104
+ }[];
105
+ }[];
106
+
107
+ type V1VaultInfo = MorphoViewsGetVaultsInfoReturn[number];
108
+ type V1MarketInfo = V1VaultInfo["markets"][number];
109
+
110
+ /**
111
+ * Scales a V1 vault's market position by V2's ownership percentage.
112
+ *
113
+ * V2 vaults wrap V1 vaults - this calculates the V2 vault's effective
114
+ * position in a V1 vault's market by scaling based on ownership:
115
+ * V2 ownership = realAssets / underlyingVaultTotalAssets
116
+ *
117
+ * @param v1VaultSupplied - The V1 vault's supplied amount in the market
118
+ * @param v2RealAssets - The V2 vault's real assets in the V1 vault
119
+ * @param v1VaultTotalAssets - Total assets in the underlying V1 vault
120
+ * @returns Scaled vault supplied amount, or 0n if V1 vault has no assets
121
+ */
122
+ function scaleV1MarketPositionByV2Ownership(
123
+ v1VaultSupplied: bigint,
124
+ v2RealAssets: bigint,
125
+ v1VaultTotalAssets: bigint,
126
+ ): bigint {
127
+ if (v1VaultTotalAssets === 0n) {
128
+ return 0n;
129
+ }
130
+ return mulDivDown(v1VaultSupplied, v2RealAssets, v1VaultTotalAssets);
131
+ }
132
+
31
133
  export async function getMorphoVaultsData(params: {
32
134
  environments: Environment[];
33
135
  vaults?: string[];
@@ -111,6 +213,8 @@ export async function getMorphoVaultsData(params: {
111
213
  }
112
214
 
113
215
  // Query v2 vaults with morphoViewsV2
216
+ // Note: V2 vaults (e.g., meUSDC) wrap V1 vaults (e.g., meUSDCv1).
217
+ // The V2 vault allocates its assets to underlying V1 vaults via adapters.
114
218
  if (v2VaultsAddresses.length > 0 && environment.contracts.morphoViewsV2) {
115
219
  queryPromises.push(
116
220
  (async () => {
@@ -120,8 +224,45 @@ export async function getMorphoVaultsData(params: {
120
224
  v2VaultsAddresses,
121
225
  ]);
122
226
 
227
+ // Extract unique underlying vault addresses from V2 adapters
228
+ const underlyingVaultAddresses =
229
+ (vaultInfoV2 as MorphoViewsV2GetVaultsInfoReturn | undefined)
230
+ ?.flatMap((v2Vault) =>
231
+ v2Vault.adapters?.map((adapter) => adapter.underlyingVault),
232
+ )
233
+ .filter((addr) => addr && addr !== zeroAddress) || [];
234
+
235
+ const uniqueUnderlyingAddresses = [
236
+ ...new Set(underlyingVaultAddresses),
237
+ ] as `0x${string}`[];
238
+
239
+ // Query underlying V1 vaults to get their market positions
240
+ const underlyingVaultsData: Map<string, V1VaultInfo> = new Map();
241
+ if (
242
+ uniqueUnderlyingAddresses.length > 0 &&
243
+ environment.contracts.morphoViews
244
+ ) {
245
+ const underlyingInfo =
246
+ await environment.contracts.morphoViews.read.getVaultsInfo([
247
+ uniqueUnderlyingAddresses,
248
+ ]);
249
+
250
+ // Map by vault address for quick lookup
251
+ underlyingInfo?.forEach(
252
+ (vaultData: V1VaultInfo, index: number) => {
253
+ underlyingVaultsData.set(
254
+ uniqueUnderlyingAddresses[index].toLowerCase(),
255
+ vaultData,
256
+ );
257
+ },
258
+ );
259
+ }
260
+
123
261
  // Transform v2 structure to v1 structure
124
- const transformedVaults = vaultInfoV2?.map((v2Vault: any) => {
262
+ // V2 vaults wrap V1 vaults - we fetch the V1 data and scale allocations
263
+ const transformedVaults = (
264
+ vaultInfoV2 as MorphoViewsV2GetVaultsInfoReturn | undefined
265
+ )?.map((v2Vault) => {
125
266
  // Get the first adapter (assuming single adapter for now)
126
267
  const adapter = v2Vault.adapters?.[0];
127
268
 
@@ -137,11 +278,55 @@ export async function getMorphoVaultsData(params: {
137
278
  };
138
279
  }
139
280
 
140
- // For v2 vaults, markets are not included since they are wrappers
141
- // around v1 vaults and we don't have accurate per-market allocations
142
- // from the v2 API. Users should query the underlying vault directly
143
- // if they need market-level data.
144
- const markets: any[] = [];
281
+ // Get underlying vault data for accurate market allocations
282
+ const underlyingVaultData = underlyingVaultsData.get(
283
+ adapter.underlyingVault.toLowerCase(),
284
+ );
285
+
286
+ let markets: V1MarketInfo[] = [];
287
+
288
+ if (underlyingVaultData?.markets) {
289
+ // Map V1 vault's markets with scaled allocations
290
+ markets = underlyingVaultData.markets.map(
291
+ (v1Market: V1MarketInfo) => {
292
+ // Scale the V1 vault's position by V2's ownership
293
+ // V2 ownership = realAssets / underlyingVaultTotalAssets
294
+ const scaledVaultSupplied =
295
+ scaleV1MarketPositionByV2Ownership(
296
+ v1Market.vaultSupplied,
297
+ adapter.realAssets,
298
+ adapter.underlyingVaultTotalAssets,
299
+ );
300
+
301
+ return {
302
+ marketId: v1Market.marketId,
303
+ marketCollateral: v1Market.marketCollateral,
304
+ marketCollateralName: v1Market.marketCollateralName,
305
+ marketCollateralSymbol: v1Market.marketCollateralSymbol,
306
+ marketLltv: v1Market.marketLltv,
307
+ marketApy: v1Market.marketApy,
308
+ marketLiquidity: v1Market.marketLiquidity,
309
+ vaultSupplied: scaledVaultSupplied,
310
+ };
311
+ },
312
+ );
313
+ } else {
314
+ // Fallback: if we can't get V1 data, use underlyingMarkets with 0 allocations
315
+ markets =
316
+ (adapter.underlyingMarkets || []).map(
317
+ (underlyingMarket: UnderlyingMarket) => ({
318
+ marketId: underlyingMarket.marketId,
319
+ marketCollateral: underlyingMarket.collateralToken,
320
+ marketCollateralName: underlyingMarket.collateralName,
321
+ marketCollateralSymbol:
322
+ underlyingMarket.collateralSymbol,
323
+ marketLltv: underlyingMarket.marketLltv,
324
+ marketApy: underlyingMarket.marketSupplyApy,
325
+ marketLiquidity: underlyingMarket.marketLiquidity,
326
+ vaultSupplied: 0n,
327
+ }),
328
+ ) || [];
329
+ }
145
330
 
146
331
  return {
147
332
  vault: v2Vault.vault,
@@ -167,7 +352,23 @@ export async function getMorphoVaultsData(params: {
167
352
  .filter((r): r is NonNullable<typeof r> => r !== undefined)
168
353
  .flat();
169
354
 
170
- return results;
355
+ // Sort results to match the order in environment.config.vaults
356
+ const vaultKeys = Object.keys(environment.config.vaults);
357
+ const sortedResults = results.sort((a, b) => {
358
+ const aIndex = vaultKeys.findIndex(
359
+ (key) =>
360
+ environment.vaults[key]?.address.toLowerCase() ===
361
+ a.vault.toLowerCase(),
362
+ );
363
+ const bIndex = vaultKeys.findIndex(
364
+ (key) =>
365
+ environment.vaults[key]?.address.toLowerCase() ===
366
+ b.vault.toLowerCase(),
367
+ );
368
+ return aIndex - bIndex;
369
+ });
370
+
371
+ return sortedResults;
171
372
  }),
172
373
  );
173
374
 
@@ -45,11 +45,6 @@ export const morphoMarkets = createMorphoMarketConfig({
45
45
  id: "0xa066f3893b780833699043f824e5bb88b8df039886f524f62b9a1ac83cb7f1f0",
46
46
  deprecated: true,
47
47
  },
48
- "rETH-USDC": {
49
- collateralToken: "rETH",
50
- loanToken: "USDC",
51
- id: "0xdb0bc9f10a174f29a345c5f30a719933f71ccea7a2a75a632a281929bba1b535",
52
- },
53
48
  "cbBTC-USDC": {
54
49
  collateralToken: "cbBTC",
55
50
  loanToken: "USDC",
@@ -33,13 +33,13 @@ export const vaults = createVaultConfig({
33
33
  vaultToken: "meUSDC",
34
34
  campaignId:
35
35
  "0x6738320fdf80785ff7a1d45ed93a6ffa07068ce9ec4170c1887d09f32fba7b57",
36
+ version: 2,
36
37
  },
37
- meUSDCv2: {
38
+ meUSDCv1: {
38
39
  underlyingToken: "USDC",
39
- vaultToken: "meUSDCv2",
40
+ vaultToken: "meUSDCv1",
40
41
  campaignId:
41
42
  "0x6738320fdf80785ff7a1d45ed93a6ffa07068ce9ec4170c1887d09f32fba7b57",
42
- version: 2,
43
43
  },
44
44
  },
45
45
  });
@@ -279,16 +279,16 @@ export const tokens = createTokenConfig({
279
279
  symbol: "mcbXRP",
280
280
  },
281
281
  meUSDC: {
282
- address: "0xe1ba476304255353aef290e6474a417d06e7b773",
282
+ address: "0xbB2F06CeAE42CBcF5559Ed0713538c8892D977c9",
283
283
  decimals: 18,
284
284
  name: "Moonwell Ecosystem USDC Vault",
285
285
  symbol: "meUSDC",
286
286
  },
287
- meUSDCv2: {
288
- address: "0xbB2F06CeAE42CBcF5559Ed0713538c8892D977c9",
287
+ meUSDCv1: {
288
+ address: "0xe1ba476304255353aef290e6474a417d06e7b773",
289
289
  decimals: 18,
290
- name: "Moonwell Ecosystem USDC Vault V2",
291
- symbol: "meUSDCv2",
290
+ name: "Moonwell Ecosystem USDC Vault V1",
291
+ symbol: "meUSDCv1",
292
292
  },
293
293
  MAMO: {
294
294
  address: "0x7300B37DfdfAb110d83290A29DfB31B1740219fE",
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.9.21'
1
+ export const version = '0.9.23'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@moonwell-fi/moonwell-sdk",
3
3
  "description": "TypeScript Interface for Moonwell",
4
- "version": "0.9.21",
4
+ "version": "0.9.23",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",