@moonwell-fi/moonwell-sdk 0.10.0 → 0.10.2

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 (67) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/_cjs/actions/core/markets/common.js +17 -7
  3. package/_cjs/actions/core/markets/common.js.map +1 -1
  4. package/_cjs/actions/core/markets/getMarkets.js +17 -7
  5. package/_cjs/actions/core/markets/getMarkets.js.map +1 -1
  6. package/_cjs/actions/governance/getDelegates.js +17 -7
  7. package/_cjs/actions/governance/getDelegates.js.map +1 -1
  8. package/_cjs/actions/governance/getDiscussions.js +17 -7
  9. package/_cjs/actions/governance/getDiscussions.js.map +1 -1
  10. package/_cjs/actions/governance/getGovernanceTokenInfo.js +17 -7
  11. package/_cjs/actions/governance/getGovernanceTokenInfo.js.map +1 -1
  12. package/_cjs/actions/governance/proposals/getProposals.js +17 -7
  13. package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
  14. package/_cjs/actions/governance/snapshot/getSnapshotProposals.js +17 -7
  15. package/_cjs/actions/governance/snapshot/getSnapshotProposals.js.map +1 -1
  16. package/_cjs/actions/morpho/markets/getMorphoMarkets.js +17 -7
  17. package/_cjs/actions/morpho/markets/getMorphoMarkets.js.map +1 -1
  18. package/_cjs/actions/morpho/user-rewards/common.js +62 -89
  19. package/_cjs/actions/morpho/user-rewards/common.js.map +1 -1
  20. package/_cjs/actions/morpho/vaults/getMorphoVaults.js +17 -7
  21. package/_cjs/actions/morpho/vaults/getMorphoVaults.js.map +1 -1
  22. package/_cjs/environments/definitions/base/core-markets.js +4 -0
  23. package/_cjs/environments/definitions/base/core-markets.js.map +1 -1
  24. package/_cjs/environments/definitions/base/tokens.js +12 -0
  25. package/_cjs/environments/definitions/base/tokens.js.map +1 -1
  26. package/_cjs/errors/version.js +1 -1
  27. package/_esm/actions/morpho/user-rewards/common.js +71 -96
  28. package/_esm/actions/morpho/user-rewards/common.js.map +1 -1
  29. package/_esm/environments/definitions/base/core-markets.js +4 -0
  30. package/_esm/environments/definitions/base/core-markets.js.map +1 -1
  31. package/_esm/environments/definitions/base/tokens.js +12 -0
  32. package/_esm/environments/definitions/base/tokens.js.map +1 -1
  33. package/_esm/errors/version.js +1 -1
  34. package/_types/actions/core/markets/common.d.ts.map +1 -1
  35. package/_types/actions/core/user-positions/common.d.ts.map +1 -1
  36. package/_types/actions/core/user-rewards/common.d.ts.map +1 -1
  37. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  38. package/_types/actions/governance/snapshot/common.d.ts.map +1 -1
  39. package/_types/actions/morpho/user-rewards/common.d.ts.map +1 -1
  40. package/_types/actions/morpho/utils/accrueInterests.d.ts.map +1 -1
  41. package/_types/actions/morpho/utils/math.d.ts.map +1 -1
  42. package/_types/client/createActions.d.ts.map +1 -1
  43. package/_types/client/createMoonwellClient.d.ts +35 -2393
  44. package/_types/client/createMoonwellClient.d.ts.map +1 -1
  45. package/_types/common/index.d.ts.map +1 -1
  46. package/_types/environments/definitions/arbitrum/environment.d.ts.map +1 -1
  47. package/_types/environments/definitions/avalanche/environment.d.ts.map +1 -1
  48. package/_types/environments/definitions/base/core-markets.d.ts +4 -0
  49. package/_types/environments/definitions/base/core-markets.d.ts.map +1 -1
  50. package/_types/environments/definitions/base/environment.d.ts.map +1 -1
  51. package/_types/environments/definitions/base/tokens.d.ts +12 -0
  52. package/_types/environments/definitions/base/tokens.d.ts.map +1 -1
  53. package/_types/environments/definitions/ethereum/environment.d.ts.map +1 -1
  54. package/_types/environments/definitions/moonbeam/environment.d.ts.map +1 -1
  55. package/_types/environments/definitions/moonriver/environment.d.ts.map +1 -1
  56. package/_types/environments/definitions/optimism/environment.d.ts.map +1 -1
  57. package/_types/environments/definitions/polygon/environment.d.ts.map +1 -1
  58. package/_types/environments/index.d.ts +16 -0
  59. package/_types/environments/index.d.ts.map +1 -1
  60. package/_types/environments/types/config.d.ts.map +1 -1
  61. package/_types/environments/utils/index.d.ts.map +1 -1
  62. package/_types/errors/version.d.ts +1 -1
  63. package/actions/morpho/user-rewards/common.ts +113 -226
  64. package/environments/definitions/base/core-markets.ts +4 -0
  65. package/environments/definitions/base/tokens.ts +12 -0
  66. package/errors/version.ts +1 -1
  67. package/package.json +1 -1
@@ -20,17 +20,19 @@ export async function getUserMorphoRewardsData(params: {
20
20
  environment: Environment;
21
21
  account: `0x${string}`;
22
22
  }): Promise<MorphoUserReward[]> {
23
- const merklRewards = await getMerklRewardsData(
24
- params.environment,
25
- params.account,
26
- );
23
+ const isFullDeployment =
24
+ params.environment.custom.morpho?.minimalDeployment === false;
25
+
26
+ const emptyMorphoRewards: MorphoRewardsResponse[] = [];
27
+ const [merklRewards, morphoRewards] = await Promise.all([
28
+ getMerklRewardsData(params.environment, params.account),
29
+ isFullDeployment
30
+ ? getMorphoRewardsData(params.environment, params.account)
31
+ : Promise.resolve(emptyMorphoRewards),
32
+ ]);
27
33
 
28
- if (params.environment.custom.morpho?.minimalDeployment === false) {
29
- const morphoRewards = await getMorphoRewardsData(
30
- params.environment,
31
- params.account,
32
- );
33
- // Process Morpho rewards
34
+ if (isFullDeployment) {
35
+ // Process Morpho rewards (GraphQL query depends on morphoRewards result)
34
36
  const morphoAssets = await getMorphoAssetsData(
35
37
  params.environment,
36
38
  morphoRewards.map((r) => r.asset.address),
@@ -189,6 +191,28 @@ export async function getUserMorphoRewardsData(params: {
189
191
  );
190
192
 
191
193
  // Process Merkl rewards
194
+ const vaultCampaignIds = new Set<string>(
195
+ (Object.values(publicEnvironments) as Environment[]).flatMap(
196
+ (environment) =>
197
+ Object.values(environment.config.vaults ?? {})
198
+ .map((vault) => vault.campaignId)
199
+ .filter((id): id is string => id !== undefined),
200
+ ),
201
+ );
202
+
203
+ const getVaultRewardAmount = (
204
+ breakdowns: any[],
205
+ field: "amount" | "claimed" | "pending",
206
+ ) => {
207
+ return breakdowns.reduce(
208
+ (acc, curr) =>
209
+ vaultCampaignIds.has(curr.campaignId)
210
+ ? acc + BigInt(curr[field])
211
+ : acc,
212
+ 0n,
213
+ );
214
+ };
215
+
192
216
  const merklResult: MorphoUserReward[] = [];
193
217
 
194
218
  for (const chainData of merklRewards) {
@@ -205,30 +229,6 @@ export async function getUserMorphoRewardsData(params: {
205
229
  name: morphoAsset?.name ?? reward.token.symbol,
206
230
  };
207
231
 
208
- const getVaultRewardAmount = (
209
- breakdowns: any[],
210
- field: "amount" | "claimed" | "pending",
211
- ) => {
212
- return breakdowns.reduce((acc, curr) => {
213
- // Check if campaign exists in vaults across all chains
214
- const isVaultCampaign = Object.values(publicEnvironments).some(
215
- (environment) => {
216
- // Check if environment has vaults
217
- if (
218
- environment.config.vaults &&
219
- Object.keys(environment.config.vaults).length > 0
220
- ) {
221
- return Object.values(environment.config.vaults).some(
222
- (vault) => vault.campaignId === curr.campaignId,
223
- );
224
- }
225
- return false;
226
- },
227
- );
228
- return isVaultCampaign ? acc + BigInt(curr[field]) : acc;
229
- }, 0n);
230
- };
231
-
232
232
  const amount = getVaultRewardAmount(reward.breakdowns, "amount");
233
233
  const claimed = getVaultRewardAmount(reward.breakdowns, "claimed");
234
234
  const pending = getVaultRewardAmount(reward.breakdowns, "pending");
@@ -319,6 +319,69 @@ export async function getUserMorphoStakingRewardsData(params: {
319
319
  return [];
320
320
  }
321
321
 
322
+ // Hoist shared contract reads outside the per-vault loop
323
+ const homeEnvironment =
324
+ (Object.values(publicEnvironments) as Environment[]).find((e) =>
325
+ e.custom?.governance?.chainIds?.includes(params.environment.chainId),
326
+ ) || params.environment;
327
+
328
+ const viewsContract = params.environment.contracts.views;
329
+ const homeViewsContract = homeEnvironment.contracts.views;
330
+
331
+ const [allMarkets, nativeTokenPriceRaw, governanceTokenPriceRaw] =
332
+ await Promise.all([
333
+ viewsContract?.read.getAllMarketsInfo(),
334
+ homeViewsContract?.read.getNativeTokenPrice(),
335
+ homeViewsContract?.read.getGovernanceTokenPrice(),
336
+ ]);
337
+
338
+ const governanceTokenPrice = new Amount(governanceTokenPriceRaw || 0n, 18);
339
+ const nativeTokenPrice = new Amount(nativeTokenPriceRaw || 0n, 18);
340
+
341
+ let tokenPrices =
342
+ allMarkets
343
+ ?.map((marketInfo) => {
344
+ const marketFound = findMarketByAddress(
345
+ params.environment,
346
+ marketInfo.market,
347
+ );
348
+ if (marketFound) {
349
+ return {
350
+ token: marketFound.underlyingToken,
351
+ tokenPrice: new Amount(
352
+ marketInfo.underlyingPrice,
353
+ 36 - marketFound.underlyingToken.decimals,
354
+ ),
355
+ };
356
+ } else {
357
+ return;
358
+ }
359
+ })
360
+ .filter((token) => !!token) || [];
361
+
362
+ // Add governance token to token prices
363
+ if (params.environment.custom?.governance?.token) {
364
+ tokenPrices = [
365
+ ...tokenPrices,
366
+ {
367
+ token:
368
+ params.environment.config.tokens[
369
+ params.environment.custom.governance.token
370
+ ]!,
371
+ tokenPrice: governanceTokenPrice,
372
+ },
373
+ ];
374
+ }
375
+
376
+ // Add native token to token prices
377
+ tokenPrices = [
378
+ ...tokenPrices,
379
+ {
380
+ token: findTokenByAddress(params.environment, zeroAddress)!,
381
+ tokenPrice: nativeTokenPrice,
382
+ },
383
+ ];
384
+
322
385
  const rewards = await Promise.all(
323
386
  vaultsWithStaking.map(async (vault) => {
324
387
  if (!vault.multiReward) return [];
@@ -329,73 +392,6 @@ export async function getUserMorphoStakingRewardsData(params: {
329
392
  vault.multiReward,
330
393
  );
331
394
 
332
- const homeEnvironment =
333
- (Object.values(publicEnvironments) as Environment[]).find((e) =>
334
- e.custom?.governance?.chainIds?.includes(params.environment.chainId),
335
- ) || params.environment;
336
-
337
- const viewsContract = params.environment.contracts.views;
338
- const homeViewsContract = homeEnvironment.contracts.views;
339
-
340
- const userData = await Promise.all([
341
- viewsContract?.read.getAllMarketsInfo(),
342
- homeViewsContract?.read.getNativeTokenPrice(),
343
- homeViewsContract?.read.getGovernanceTokenPrice(),
344
- ]);
345
-
346
- const [allMarkets, nativeTokenPriceRaw, governanceTokenPriceRaw] =
347
- userData;
348
-
349
- const governanceTokenPrice = new Amount(
350
- governanceTokenPriceRaw || 0n,
351
- 18,
352
- );
353
- const nativeTokenPrice = new Amount(nativeTokenPriceRaw || 0n, 18);
354
-
355
- let tokenPrices =
356
- allMarkets
357
- ?.map((marketInfo) => {
358
- const marketFound = findMarketByAddress(
359
- params.environment,
360
- marketInfo.market,
361
- );
362
- if (marketFound) {
363
- return {
364
- token: marketFound.underlyingToken,
365
- tokenPrice: new Amount(
366
- marketInfo.underlyingPrice,
367
- 36 - marketFound.underlyingToken.decimals,
368
- ),
369
- };
370
- } else {
371
- return;
372
- }
373
- })
374
- .filter((token) => !!token) || [];
375
-
376
- // Add governance token to token prices
377
- if (params.environment.custom?.governance?.token) {
378
- tokenPrices = [
379
- ...tokenPrices,
380
- {
381
- token:
382
- params.environment.config.tokens[
383
- params.environment.custom.governance.token
384
- ]!,
385
- tokenPrice: governanceTokenPrice,
386
- },
387
- ];
388
- }
389
-
390
- // Add native token to token prices
391
- tokenPrices = [
392
- ...tokenPrices,
393
- {
394
- token: findTokenByAddress(params.environment, zeroAddress)!,
395
- tokenPrice: nativeTokenPrice,
396
- },
397
- ];
398
-
399
395
  return vaultRewards
400
396
  .filter((reward): reward is { amount: Amount; token: TokenConfig } => {
401
397
  return reward !== undefined && reward.amount.value > 0;
@@ -587,140 +583,31 @@ type MerklRewardsResponse = {
587
583
  }>;
588
584
  };
589
585
 
590
- // Types for Merkl Opportunities API
591
- type MerklToken = {
592
- id: string;
593
- name: string;
594
- chainId: number;
595
- address: string;
596
- decimals: number;
597
- symbol: string;
598
- displaySymbol: string;
599
- icon: string;
600
- verified: boolean;
601
- isTest: boolean;
602
- type: string;
603
- isNative: boolean;
604
- price: number;
605
- };
606
-
607
- type MerklRewardBreakdown = {
608
- token: MerklToken;
609
- amount: string;
610
- value: number;
611
- distributionType: string;
612
- id: string;
613
- timestamp: string;
614
- campaignId: string;
615
- dailyRewardsRecordId: string;
616
- };
617
-
618
- type MerklOpportunity = {
619
- chainId: number;
620
- type: string;
621
- identifier: string;
622
- name: string;
623
- description: string;
624
- howToSteps: string[];
625
- status: string;
626
- action: string;
627
- tvl: number;
628
- apr: number;
629
- dailyRewards: number;
630
- tags: any[];
631
- id: string;
632
- depositUrl: string;
633
- explorerAddress: string;
634
- lastCampaignCreatedAt: number;
635
- aprRecord: {
636
- cumulated: number;
637
- timestamp: string;
638
- breakdowns: {
639
- distributionType: string;
640
- identifier: string;
641
- type: string;
642
- value: number;
643
- timestamp: string;
644
- }[];
645
- };
646
- rewardsRecord: {
647
- id: string;
648
- total: number;
649
- timestamp: string;
650
- breakdowns: MerklRewardBreakdown[];
651
- };
652
- };
653
-
654
586
  async function getMerklRewardsData(
655
587
  environment: Environment,
656
588
  account: Address,
657
589
  ): Promise<MerklRewardsResponse[]> {
658
590
  try {
659
- // Get unique chain IDs from vault opportunities
660
- const chainIdsPromises = Object.values(environment.config.vaults).map(
661
- async (vault) => {
662
- try {
663
- const response = await fetch(
664
- `https://api.merkl.xyz/v4/opportunities?identifier=${environment.config.tokens[vault.vaultToken]?.address}&chainId=${environment.chainId}&status=LIVE`,
665
- {
666
- headers: MOONWELL_FETCH_JSON_HEADERS,
667
- },
668
- );
669
-
670
- if (!response.ok) {
671
- console.warn(
672
- `Failed to fetch opportunities: ${response.status} ${response.statusText}`,
673
- );
674
- return [];
675
- }
676
-
677
- const data: MerklOpportunity[] = await response.json();
678
- return data.flatMap((opportunity) =>
679
- opportunity.rewardsRecord.breakdowns.map(
680
- (breakdown) => breakdown.token.chainId,
681
- ),
682
- );
683
- } catch (error) {
684
- console.warn(
685
- `Error fetching opportunities for vault ${vault.vaultToken}:`,
686
- error,
687
- );
688
- return [];
689
- }
591
+ // Merkl campaigns always distribute rewards on the same chain as the
592
+ // opportunity, so environment.chainId is the only chain we need to query.
593
+ // The previous two-phase approach (fetch opportunities per vault extract
594
+ // chain IDs → fetch rewards per chain) made N+1 HTTP calls to discover
595
+ // a chain ID we already know.
596
+ const response = await fetch(
597
+ `https://api.merkl.xyz/v4/users/${account}/rewards?chainId=${environment.chainId}&test=false&breakdownPage=0&reloadChainId=${environment.chainId}`,
598
+ {
599
+ headers: MOONWELL_FETCH_JSON_HEADERS,
690
600
  },
691
601
  );
692
602
 
693
- const chainIds = [...new Set((await Promise.all(chainIdsPromises)).flat())];
694
-
695
- // Fetch rewards for each unique chain ID
696
- const rewardsPromises = chainIds.map(async (chainId) => {
697
- try {
698
- const response = await fetch(
699
- `https://api.merkl.xyz/v4/users/${account}/rewards?chainId=${chainId}&test=false&breakdownPage=0&reloadChainId=${chainId}`,
700
- {
701
- headers: MOONWELL_FETCH_JSON_HEADERS,
702
- },
703
- );
704
-
705
- if (!response.ok) {
706
- console.warn(
707
- `Merkl API request failed: ${response.status} ${response.statusText}`,
708
- );
709
- return [];
710
- }
711
-
712
- return (await response.json()) as MerklRewardsResponse[];
713
- } catch (error) {
714
- console.warn(
715
- `Error fetching Merkl rewards for chain ${chainId}:`,
716
- error,
717
- );
718
- return [];
719
- }
720
- });
603
+ if (!response.ok) {
604
+ console.warn(
605
+ `Merkl API request failed: ${response.status} ${response.statusText}`,
606
+ );
607
+ return [];
608
+ }
721
609
 
722
- const allRewards = await Promise.all(rewardsPromises);
723
- return allRewards.flat();
610
+ return (await response.json()) as MerklRewardsResponse[];
724
611
  } catch (error) {
725
612
  console.error("Error in getMerklRewardsData:", error);
726
613
  return [];
@@ -85,5 +85,9 @@ export const markets = createMarketConfig({
85
85
  marketToken: "MOONWELL_MAMO",
86
86
  underlyingToken: "MAMO",
87
87
  },
88
+ MOONWELL_VVV: {
89
+ marketToken: "MOONWELL_VVV",
90
+ underlyingToken: "VVV",
91
+ },
88
92
  },
89
93
  });
@@ -302,4 +302,16 @@ export const tokens = createTokenConfig({
302
302
  name: "Moonwell MAMO",
303
303
  symbol: "mMAMO",
304
304
  },
305
+ VVV: {
306
+ address: "0xacfE6019Ed1A7Dc6f7B508C02d1b04ec88cC21bf",
307
+ decimals: 18,
308
+ name: "Venice Token",
309
+ symbol: "VVV",
310
+ },
311
+ MOONWELL_VVV: {
312
+ address: "0xd64bcb70c613a6d1f4d7d57ba64bb4a0767a9682",
313
+ decimals: 8,
314
+ name: "Moonwell VVV",
315
+ symbol: "mVVV",
316
+ },
305
317
  });
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.10.0'
1
+ export const version = '0.10.2'
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.10.0",
4
+ "version": "0.10.2",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",