@moonwell-fi/moonwell-sdk 0.13.0 → 0.14.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 (85) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/_cjs/actions/core/markets/common.js +11 -4
  3. package/_cjs/actions/core/markets/common.js.map +1 -1
  4. package/_cjs/actions/core/user-rewards/common.js +6 -5
  5. package/_cjs/actions/core/user-rewards/common.js.map +1 -1
  6. package/_cjs/actions/governance/getStakingInfo.js +113 -31
  7. package/_cjs/actions/governance/getStakingInfo.js.map +1 -1
  8. package/_cjs/actions/governance/getUserStakingInfo.js +106 -18
  9. package/_cjs/actions/governance/getUserStakingInfo.js.map +1 -1
  10. package/_cjs/actions/governance/getUserVoteReceipt.js +39 -25
  11. package/_cjs/actions/governance/getUserVoteReceipt.js.map +1 -1
  12. package/_cjs/actions/governance/getWellPrice.js +26 -0
  13. package/_cjs/actions/governance/getWellPrice.js.map +1 -0
  14. package/_cjs/actions/governance/governor-api-client.js +70 -33
  15. package/_cjs/actions/governance/governor-api-client.js.map +1 -1
  16. package/_cjs/actions/governance/proposals/common.js +29 -1
  17. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  18. package/_cjs/actions/governance/proposals/getProposal.js +24 -17
  19. package/_cjs/actions/governance/proposals/getProposal.js.map +1 -1
  20. package/_cjs/actions/governance/proposals/getProposals.js +27 -9
  21. package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
  22. package/_cjs/actions/morpho/user-rewards/common.js +10 -3
  23. package/_cjs/actions/morpho/user-rewards/common.js.map +1 -1
  24. package/_cjs/actions/morpho/vaults/common.js +19 -6
  25. package/_cjs/actions/morpho/vaults/common.js.map +1 -1
  26. package/_cjs/errors/version.js +1 -1
  27. package/_esm/actions/core/markets/common.js +11 -4
  28. package/_esm/actions/core/markets/common.js.map +1 -1
  29. package/_esm/actions/core/user-rewards/common.js +6 -5
  30. package/_esm/actions/core/user-rewards/common.js.map +1 -1
  31. package/_esm/actions/governance/getStakingInfo.js +136 -32
  32. package/_esm/actions/governance/getStakingInfo.js.map +1 -1
  33. package/_esm/actions/governance/getUserStakingInfo.js +120 -19
  34. package/_esm/actions/governance/getUserStakingInfo.js.map +1 -1
  35. package/_esm/actions/governance/getUserVoteReceipt.js +48 -26
  36. package/_esm/actions/governance/getUserVoteReceipt.js.map +1 -1
  37. package/_esm/actions/governance/getWellPrice.js +50 -0
  38. package/_esm/actions/governance/getWellPrice.js.map +1 -0
  39. package/_esm/actions/governance/governor-api-client.js +87 -35
  40. package/_esm/actions/governance/governor-api-client.js.map +1 -1
  41. package/_esm/actions/governance/proposals/common.js +44 -1
  42. package/_esm/actions/governance/proposals/common.js.map +1 -1
  43. package/_esm/actions/governance/proposals/getProposal.js +36 -23
  44. package/_esm/actions/governance/proposals/getProposal.js.map +1 -1
  45. package/_esm/actions/governance/proposals/getProposals.js +44 -10
  46. package/_esm/actions/governance/proposals/getProposals.js.map +1 -1
  47. package/_esm/actions/morpho/user-rewards/common.js +10 -3
  48. package/_esm/actions/morpho/user-rewards/common.js.map +1 -1
  49. package/_esm/actions/morpho/vaults/common.js +19 -6
  50. package/_esm/actions/morpho/vaults/common.js.map +1 -1
  51. package/_esm/errors/version.js +1 -1
  52. package/_types/actions/core/markets/common.d.ts.map +1 -1
  53. package/_types/actions/core/user-rewards/common.d.ts.map +1 -1
  54. package/_types/actions/governance/getStakingInfo.d.ts +1 -1
  55. package/_types/actions/governance/getStakingInfo.d.ts.map +1 -1
  56. package/_types/actions/governance/getUserStakingInfo.d.ts.map +1 -1
  57. package/_types/actions/governance/getUserVoteReceipt.d.ts +16 -0
  58. package/_types/actions/governance/getUserVoteReceipt.d.ts.map +1 -1
  59. package/_types/actions/governance/getWellPrice.d.ts +29 -0
  60. package/_types/actions/governance/getWellPrice.d.ts.map +1 -0
  61. package/_types/actions/governance/governor-api-client.d.ts +37 -12
  62. package/_types/actions/governance/governor-api-client.d.ts.map +1 -1
  63. package/_types/actions/governance/proposals/common.d.ts +14 -1
  64. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  65. package/_types/actions/governance/proposals/getProposal.d.ts +6 -1
  66. package/_types/actions/governance/proposals/getProposal.d.ts.map +1 -1
  67. package/_types/actions/governance/proposals/getProposals.d.ts +1 -1
  68. package/_types/actions/governance/proposals/getProposals.d.ts.map +1 -1
  69. package/_types/actions/morpho/user-rewards/common.d.ts.map +1 -1
  70. package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
  71. package/_types/errors/version.d.ts +1 -1
  72. package/actions/core/markets/common.ts +11 -6
  73. package/actions/core/user-rewards/common.ts +6 -5
  74. package/actions/governance/getStakingInfo.ts +195 -87
  75. package/actions/governance/getUserStakingInfo.ts +168 -54
  76. package/actions/governance/getUserVoteReceipt.ts +71 -31
  77. package/actions/governance/getWellPrice.ts +66 -0
  78. package/actions/governance/governor-api-client.ts +136 -62
  79. package/actions/governance/proposals/common.ts +51 -1
  80. package/actions/governance/proposals/getProposal.ts +46 -26
  81. package/actions/governance/proposals/getProposals.ts +48 -14
  82. package/actions/morpho/user-rewards/common.ts +10 -3
  83. package/actions/morpho/vaults/common.ts +19 -12
  84. package/errors/version.ts +1 -1
  85. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"getProposals.d.ts","sourceRoot":"","sources":["../../../../actions/governance/proposals/getProposals.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,gCAAgC,CAAC;AAEzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAY3D,MAAM,MAAM,sBAAsB,CAChC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,IAC/B,4BAA4B,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAExD,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;AAEzD,wBAAsB,YAAY,CAChC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,EAEjC,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,sBAAsB,CAAC,YAAY,EAAE,OAAO,CAAC,GACnD,sBAAsB,CAkCxB"}
1
+ {"version":3,"file":"getProposals.d.ts","sourceRoot":"","sources":["../../../../actions/governance/proposals/getProposals.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,gCAAgC,CAAC;AAEzE,OAAO,EAAE,KAAK,QAAQ,EAAiB,MAAM,4BAA4B,CAAC;AAY1E,MAAM,MAAM,sBAAsB,CAChC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,IAC/B,4BAA4B,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAExD,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;AAEzD,wBAAsB,YAAY,CAChC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,EAEjC,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,sBAAsB,CAAC,YAAY,EAAE,OAAO,CAAC,GACnD,sBAAsB,CAyCxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../actions/morpho/user-rewards/common.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,WAAW,EAGjB,MAAM,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AAEzF;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,MAAM,EAAE;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;CAWF;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAsF9B;AAED,wBAAsB,+BAA+B,CAAC,MAAM,EAAE;IAC5D,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;CACxB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAsGrC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../actions/morpho/user-rewards/common.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,WAAW,EAGjB,MAAM,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AAGzF;;;;;;;GAOG;AACH,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,MAAM,EAAE;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAChC,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;CAWF;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;IACvB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAsF9B;AAED,wBAAsB,+BAA+B,CAAC,MAAM,EAAE;IAC5D,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;CACxB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CA4GrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../actions/morpho/vaults/common.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAEjB,MAAM,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EACV,WAAW,EAEZ,MAAM,+BAA+B,CAAC;AAkavC,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAazB;AAy3BD,KAAK,4BAA4B,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,WAAW,CAAC;IACxB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,WAAW,EAAE,EACrB,uBAAuB,CAAC,EAAE,OAAO,GAChC,OAAO,CAAC,4BAA4B,EAAE,CAAC,CA8NzC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../actions/morpho/vaults/common.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAEjB,MAAM,gCAAgC,CAAC;AAKxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,KAAK,EACV,WAAW,EAEZ,MAAM,+BAA+B,CAAC;AAsavC,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAazB;AA43BD,KAAK,4BAA4B,GAAG;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,WAAW,CAAC;IACxB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB,CAAC;AAEF,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,WAAW,EAAE,EACrB,uBAAuB,CAAC,EAAE,OAAO,GAChC,OAAO,CAAC,4BAA4B,EAAE,CAAC,CA8NzC"}
@@ -1,2 +1,2 @@
1
- export declare const version = "0.13.0";
1
+ export declare const version = "0.14.0";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -17,6 +17,7 @@ import {
17
17
  findTokenByAddress,
18
18
  } from "../../../environments/utils/index.js";
19
19
  import type { Market } from "../../../types/market.js";
20
+ import { getGovernanceTokenPriceFor } from "../../governance/getWellPrice.js";
20
21
 
21
22
  export const getMarketsData = async (environment: Environment) => {
22
23
  // Moonriver (chainId 1285) should always use on-chain data
@@ -54,7 +55,7 @@ export const getMarketsData = async (environment: Environment) => {
54
55
  viewsContract?.read.getProtocolInfo(),
55
56
  viewsContract?.read.getAllMarketsInfo(),
56
57
  homeViewsContract?.read.getNativeTokenPrice(),
57
- homeViewsContract?.read.getGovernanceTokenPrice(),
58
+ getGovernanceTokenPriceFor(environment),
58
59
  ]);
59
60
 
60
61
  // If getAllMarketsInfo failed (e.g. broken on-chain oracle), fall back to
@@ -506,13 +507,17 @@ async function fetchMarketsFromLunar(
506
507
 
507
508
  const [nativeTokenPriceRaw, governanceTokenPriceRaw] = await Promise.all([
508
509
  homeEnvironment.contracts.views?.read.getNativeTokenPrice(),
509
- homeEnvironment.contracts.views?.read.getGovernanceTokenPrice(),
510
+ getGovernanceTokenPriceFor(environment).catch((err) => {
511
+ environment.onError?.(err, {
512
+ source: "governance-token-price",
513
+ chainId: environment.chainId,
514
+ });
515
+ return 0n;
516
+ }),
510
517
  ]);
511
518
 
512
- if (!nativeTokenPriceRaw || !governanceTokenPriceRaw) {
513
- throw new Error(
514
- "Failed to fetch native or governance token prices from home chain",
515
- );
519
+ if (nativeTokenPriceRaw === undefined) {
520
+ throw new Error("Failed to fetch native token price from home chain");
516
521
  }
517
522
 
518
523
  governanceTokenPrice = new Amount(governanceTokenPriceRaw, 18);
@@ -9,6 +9,7 @@ import {
9
9
  findTokenByAddress,
10
10
  } from "../../../environments/utils/index.js";
11
11
  import type { UserReward } from "../../../types/userReward.js";
12
+ import { getGovernanceTokenPriceFor } from "../../governance/getWellPrice.js";
12
13
 
13
14
  export const getUserRewardsData = async (params: {
14
15
  environment: Environment;
@@ -27,7 +28,7 @@ export const getUserRewardsData = async (params: {
27
28
  viewsContract?.read.getAllMarketsInfo(),
28
29
  viewsContract?.read.getUserRewards([params.account]),
29
30
  homeViewsContract?.read.getNativeTokenPrice(),
30
- homeViewsContract?.read.getGovernanceTokenPrice(),
31
+ getGovernanceTokenPriceFor(params.environment),
31
32
  ] as const);
32
33
 
33
34
  // Narrow each one by status and coerce to undefined on failure:
@@ -43,14 +44,14 @@ export const getUserRewardsData = async (params: {
43
44
  if (
44
45
  !allMarkets ||
45
46
  !userRewards ||
46
- !nativeTokenPriceRaw ||
47
- !governanceTokenPriceRaw
47
+ nativeTokenPriceRaw === undefined ||
48
+ governanceTokenPriceRaw === undefined
48
49
  ) {
49
50
  return [];
50
51
  }
51
52
 
52
- const governanceTokenPrice = new Amount(governanceTokenPriceRaw || 0n, 18);
53
- const nativeTokenPrice = new Amount(nativeTokenPriceRaw || 0n, 18);
53
+ const governanceTokenPrice = new Amount(governanceTokenPriceRaw, 18);
54
+ const nativeTokenPrice = new Amount(nativeTokenPriceRaw, 18);
54
55
 
55
56
  let tokenPrices =
56
57
  allMarkets
@@ -7,14 +7,10 @@ import {
7
7
  getEnvironmentsFromArgs,
8
8
  } from "../../common/index.js";
9
9
  import type { NetworkParameterType } from "../../common/types.js";
10
- import {
11
- type Chain,
12
- type Environment,
13
- type TokensType,
14
- publicEnvironments,
15
- } from "../../environments/index.js";
10
+ import type { Chain, Environment } from "../../environments/index.js";
16
11
  import type { StakingInfo } from "../../types/staking.js";
17
12
  import { getMerklStakingApr } from "./common.js";
13
+ import { getGovernanceTokenPriceFor } from "./getWellPrice.js";
18
14
 
19
15
  export type GetStakingInfoParameters<
20
16
  environments,
@@ -23,6 +19,108 @@ export type GetStakingInfoParameters<
23
19
 
24
20
  export type GetStakingInfoReturnType = Promise<StakingInfo[]>;
25
21
 
22
+ type StakingInfoStruct = {
23
+ cooldown: bigint;
24
+ distributionEnd: bigint;
25
+ emissionPerSecond: bigint;
26
+ totalSupply: bigint;
27
+ unstakeWindow: bigint;
28
+ };
29
+
30
+ const isStakingInfoStruct = (value: unknown): value is StakingInfoStruct => {
31
+ if (typeof value !== "object" || value === null) return false;
32
+ const v = value as Record<string, unknown>;
33
+ return (
34
+ typeof v.cooldown === "bigint" &&
35
+ typeof v.distributionEnd === "bigint" &&
36
+ typeof v.emissionPerSecond === "bigint" &&
37
+ typeof v.totalSupply === "bigint" &&
38
+ typeof v.unstakeWindow === "bigint"
39
+ );
40
+ };
41
+
42
+ /**
43
+ * Reads the staking fields directly from the stkWELL token contract when the
44
+ * core views' getStakingInfo() is unavailable or returns zeroed data
45
+ * (e.g. reverts on Moonbeam). Reads each field independently so a single
46
+ * transient RPC failure doesn't erase the whole fallback.
47
+ *
48
+ * The `assets` mapping is keyed by the stkWELL contract's own address — that's
49
+ * the Aave-fork convention (`address(this)` in StakedAave._initialize), not
50
+ * the underlying staked token. Verified on Moonbeam: assets(stkWELL) returns
51
+ * non-zero emissionPerSecond; assets(WELL) returns zero.
52
+ */
53
+ async function getStakingInfoFromStkWell(
54
+ environment: Environment,
55
+ ): Promise<StakingInfoStruct | undefined> {
56
+ const stakingToken = environment.contracts.stakingToken;
57
+ const stakingTokenKey = environment.config.contracts.stakingToken;
58
+ const tokens = environment.config.tokens as Record<
59
+ string,
60
+ { address: `0x${string}` } | undefined
61
+ >;
62
+ const stakingTokenAddress = stakingTokenKey
63
+ ? tokens[stakingTokenKey]?.address
64
+ : undefined;
65
+ if (!stakingToken || !stakingTokenAddress) {
66
+ environment.onError?.(
67
+ new Error("getStakingInfoFromStkWell: missing stkWELL config"),
68
+ { source: "staking-fallback", chainId: environment.chainId },
69
+ );
70
+ return undefined;
71
+ }
72
+
73
+ const [
74
+ cooldownR,
75
+ unstakeWindowR,
76
+ distributionEndR,
77
+ totalSupplyR,
78
+ assetDataR,
79
+ ] = await Promise.allSettled([
80
+ stakingToken.read.COOLDOWN_SECONDS(),
81
+ stakingToken.read.UNSTAKE_WINDOW(),
82
+ stakingToken.read.DISTRIBUTION_END(),
83
+ stakingToken.read.totalSupply(),
84
+ stakingToken.read.assets([stakingTokenAddress]),
85
+ ]);
86
+
87
+ // Surface every rejection so operators don't have to guess which read failed.
88
+ for (const r of [
89
+ cooldownR,
90
+ unstakeWindowR,
91
+ distributionEndR,
92
+ totalSupplyR,
93
+ assetDataR,
94
+ ]) {
95
+ if (r.status === "rejected") {
96
+ environment.onError?.(r.reason, {
97
+ source: "staking-fallback",
98
+ chainId: environment.chainId,
99
+ });
100
+ }
101
+ }
102
+
103
+ // totalSupply is load-bearing for APR; if its read failed (vs. legitimately
104
+ // returning 0n on an empty new chain) we can't produce a sensible struct.
105
+ if (totalSupplyR.status === "rejected") return undefined;
106
+
107
+ const assetData =
108
+ assetDataR.status === "fulfilled" ? assetDataR.value : undefined;
109
+ // viem returns multi-output reads as a tuple (Readonly<[bigint, bigint, bigint]>)
110
+ // even when the ABI names the outputs.
111
+ const emissionPerSecond = assetData ? assetData[0] : 0n;
112
+
113
+ return {
114
+ cooldown: cooldownR.status === "fulfilled" ? cooldownR.value : 0n,
115
+ unstakeWindow:
116
+ unstakeWindowR.status === "fulfilled" ? unstakeWindowR.value : 0n,
117
+ distributionEnd:
118
+ distributionEndR.status === "fulfilled" ? distributionEndR.value : 0n,
119
+ totalSupply: totalSupplyR.value,
120
+ emissionPerSecond,
121
+ };
122
+ }
123
+
26
124
  export async function getStakingInfo<
27
125
  environments,
28
126
  Network extends Chain | undefined,
@@ -36,85 +134,104 @@ export async function getStakingInfo<
36
134
  (env) => env.config.contracts.stakingToken,
37
135
  );
38
136
 
137
+ const baseEnvironment = (
138
+ client.environments as { base?: Environment } | undefined
139
+ )?.base;
140
+
39
141
  const envStakingInfoSettlements = await Promise.allSettled(
40
142
  envsWithStaking.map(async (environment) => {
41
- const homeEnvironment =
42
- (Object.values(publicEnvironments) as Environment[]).find((e) =>
43
- e.custom?.governance?.chainIds?.includes(environment.chainId),
44
- ) || environment;
45
-
46
143
  const isBase = environment.chainId === base.id;
47
144
 
48
- const settlements = await Promise.allSettled([
49
- environment.contracts.views?.read.getStakingInfo(),
50
- homeEnvironment.contracts.views?.read.getGovernanceTokenPrice(),
51
- ...(isBase
52
- ? [
53
- environment.contracts.views?.read.getStakingInfo({
145
+ const [viewsStakingResult, historicalStakingResult, priceResult] =
146
+ await Promise.allSettled([
147
+ environment.contracts.views?.read.getStakingInfo(),
148
+ isBase
149
+ ? environment.contracts.views?.read.getStakingInfo({
54
150
  blockNumber: BigInt(34149943),
55
- }),
56
- ]
57
- : []),
58
- ]);
59
-
60
- return settlements.map((s) =>
61
- s.status === "fulfilled" ? s.value : undefined,
62
- );
151
+ })
152
+ : Promise.resolve(undefined),
153
+ getGovernanceTokenPriceFor(environment, baseEnvironment),
154
+ ]);
155
+
156
+ const viewsStaking =
157
+ viewsStakingResult.status === "fulfilled"
158
+ ? viewsStakingResult.value
159
+ : undefined;
160
+
161
+ // Fall back to direct stkWELL reads when the views call rejected (the
162
+ // known Moonbeam failure mode) or returned a fully-zeroed struct
163
+ // (suspicious — a real deployment always has cooldown and unstake
164
+ // window configured > 0). A new chain with zero stakers but real
165
+ // schedule constants still goes through views.
166
+ const allZeroed =
167
+ isStakingInfoStruct(viewsStaking) &&
168
+ viewsStaking.cooldown === 0n &&
169
+ viewsStaking.unstakeWindow === 0n &&
170
+ viewsStaking.totalSupply === 0n &&
171
+ viewsStaking.emissionPerSecond === 0n;
172
+ const viewsValid = isStakingInfoStruct(viewsStaking) && !allZeroed;
173
+ const stakingInfo: StakingInfoStruct | undefined = viewsValid
174
+ ? viewsStaking
175
+ : await getStakingInfoFromStkWell(environment);
176
+
177
+ const historicalStaking =
178
+ historicalStakingResult.status === "fulfilled"
179
+ ? historicalStakingResult.value
180
+ : undefined;
181
+
182
+ const price = priceResult.status === "fulfilled" ? priceResult.value : 0n;
183
+
184
+ if (priceResult.status === "rejected") {
185
+ environment.onError?.(priceResult.reason, {
186
+ source: "governance-token-price",
187
+ chainId: environment.chainId,
188
+ });
189
+ }
190
+
191
+ return { stakingInfo, historicalStaking, price };
63
192
  }),
64
193
  );
65
194
 
66
- const envStakingInfo = envStakingInfoSettlements
67
- .filter((s) => s.status === "fulfilled")
68
- .map(
69
- (s) =>
70
- (
71
- s as PromiseFulfilledResult<
72
- (
73
- | bigint
74
- | {
75
- cooldown: bigint;
76
- unstakeWindow: bigint;
77
- distributionEnd: bigint;
78
- totalSupply: bigint;
79
- emissionPerSecond: bigint;
80
- lastUpdateTimestamp: bigint;
81
- index: bigint;
82
- }
83
- | undefined
84
- )[]
85
- >
86
- ).value,
87
- )
88
- .filter((val) => val !== undefined);
195
+ const envStakingInfo = envStakingInfoSettlements.map((s) =>
196
+ s.status === "fulfilled"
197
+ ? s.value
198
+ : { stakingInfo: undefined, historicalStaking: undefined, price: 0n },
199
+ );
89
200
 
90
201
  const baseEnv = envsWithStaking.find((env) => env.chainId === base.id);
91
- const stakingTokenKey = baseEnv?.config.contracts.stakingToken;
92
- const baseStkToken =
93
- baseEnv != null && stakingTokenKey != null
94
- ? baseEnv.config.tokens[stakingTokenKey]
95
- : undefined;
96
- const baseStakingApr =
97
- baseStkToken != null ? await getMerklStakingApr(baseStkToken.address) : 0;
202
+ const baseStakingTokenKey = baseEnv?.config.contracts.stakingToken;
203
+ const baseTokens = baseEnv?.config.tokens as
204
+ | Record<string, { address: `0x${string}` } | undefined>
205
+ | undefined;
206
+ const baseStkTokenAddress = baseStakingTokenKey
207
+ ? baseTokens?.[baseStakingTokenKey]?.address
208
+ : undefined;
209
+ const baseStakingApr = baseStkTokenAddress
210
+ ? await getMerklStakingApr(baseStkTokenAddress)
211
+ : 0;
98
212
 
99
213
  const result = envsWithStaking.flatMap((curr, index) => {
100
- const token =
101
- curr.config.tokens[
102
- curr.config.contracts.governanceToken as keyof TokensType<typeof curr>
103
- ]!;
104
- const stakingToken =
105
- curr.config.tokens[
106
- curr.config.contracts.stakingToken as keyof TokensType<typeof curr>
107
- ]!;
108
-
109
- const envStakingInfoData = envStakingInfo[index]![0]!;
110
- const envGovernanceTokenPriceData = envStakingInfo[index]![1];
111
- const envStakingInfoDataAfterX28Proposal = envStakingInfo[index]![2]!;
214
+ const govKey = curr.config.contracts.governanceToken;
215
+ const stkKey = curr.config.contracts.stakingToken;
216
+ const currTokens = curr.config.tokens as Record<
217
+ string,
218
+ { address: `0x${string}`; decimals: number; name: string; symbol: string }
219
+ >;
220
+ if (!govKey || !stkKey) return [];
221
+ const token = currTokens[govKey];
222
+ const stakingToken = currTokens[stkKey];
223
+ if (!token || !stakingToken) return [];
224
+
225
+ // envStakingInfo is built via Promise.allSettled with an explicit
226
+ // fallback object at the .map below, so entries are always defined here.
227
+ const {
228
+ stakingInfo: envStakingInfoData,
229
+ historicalStaking,
230
+ price,
231
+ } = envStakingInfo[index];
112
232
  const isBase = curr.chainId === base.id;
113
233
 
114
- if (
115
- !envStakingInfoData ||
116
- (isBase && !envStakingInfoDataAfterX28Proposal)
117
- ) {
234
+ if (!envStakingInfoData || (isBase && !historicalStaking)) {
118
235
  return [];
119
236
  }
120
237
 
@@ -124,20 +241,9 @@ export async function getStakingInfo<
124
241
  emissionPerSecond: emissionPerSecondRaw,
125
242
  totalSupply: totalSupplyRaw,
126
243
  unstakeWindow,
127
- } = envStakingInfoData as {
128
- cooldown: bigint;
129
- distributionEnd: bigint;
130
- emissionPerSecond: bigint;
131
- totalSupply: bigint;
132
- unstakeWindow: bigint;
133
- };
134
-
135
- //Quick workaround to get governance token price from some other environment
136
- const governanceTokenPrice = new Amount(
137
- (envGovernanceTokenPriceData ?? 0n) as bigint,
138
- 18,
139
- );
244
+ } = envStakingInfoData;
140
245
 
246
+ const tokenPrice = new Amount(price, 18);
141
247
  const totalSupply = new Amount(totalSupplyRaw, 18);
142
248
  const emissionPerSecond = new Amount(emissionPerSecondRaw, 18);
143
249
 
@@ -145,7 +251,9 @@ export async function getStakingInfo<
145
251
  emissionPerSecond.value * SECONDS_PER_DAY * DAYS_PER_YEAR;
146
252
 
147
253
  const apr =
148
- ((emissionPerYear + totalSupply.value) / totalSupply.value - 1) * 100;
254
+ totalSupply.value > 0
255
+ ? ((emissionPerYear + totalSupply.value) / totalSupply.value - 1) * 100
256
+ : 0;
149
257
 
150
258
  const stakingInfo: StakingInfo = {
151
259
  apr: isBase ? baseStakingApr : apr,
@@ -153,10 +261,10 @@ export async function getStakingInfo<
153
261
  cooldown: Number(cooldown),
154
262
  distributionEnd: Number(distributionEnd),
155
263
  token,
156
- tokenPrice: governanceTokenPrice.value,
264
+ tokenPrice: tokenPrice.value,
157
265
  stakingToken,
158
266
  totalSupply,
159
- totalSupplyUSD: totalSupply.value * governanceTokenPrice.value,
267
+ totalSupplyUSD: totalSupply.value * tokenPrice.value,
160
268
  unstakeWindow: Number(unstakeWindow),
161
269
  };
162
270