@moonwell-fi/moonwell-sdk 0.20.2 → 0.20.4

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 (98) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/_cjs/actions/governance/common.js +9 -7
  3. package/_cjs/actions/governance/common.js.map +1 -1
  4. package/_cjs/actions/governance/getStakingInfo.js +1 -1
  5. package/_cjs/actions/governance/getStakingInfo.js.map +1 -1
  6. package/_cjs/actions/governance/getUserStakingInfo.js +2 -2
  7. package/_cjs/actions/governance/getUserStakingInfo.js.map +1 -1
  8. package/_cjs/actions/governance/governor-api-client.js +3 -2
  9. package/_cjs/actions/governance/governor-api-client.js.map +1 -1
  10. package/_cjs/actions/governance/proposals/common.js +11 -296
  11. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  12. package/_cjs/actions/governance/proposals/getProposal.js +9 -25
  13. package/_cjs/actions/governance/proposals/getProposal.js.map +1 -1
  14. package/_cjs/actions/governance/proposals/getProposals.js +23 -14
  15. package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
  16. package/_cjs/actions/morpho/user-rewards/common.js +2 -1
  17. package/_cjs/actions/morpho/user-rewards/common.js.map +1 -1
  18. package/_cjs/common/lunar-indexer-helpers.js +6 -0
  19. package/_cjs/common/lunar-indexer-helpers.js.map +1 -1
  20. package/_cjs/environments/definitions/base/environment.js +2 -1
  21. package/_cjs/environments/definitions/base/environment.js.map +1 -1
  22. package/_cjs/environments/definitions/ethereum/environment.js +2 -1
  23. package/_cjs/environments/definitions/ethereum/environment.js.map +1 -1
  24. package/_cjs/environments/definitions/moonbeam/environment.js +2 -1
  25. package/_cjs/environments/definitions/moonbeam/environment.js.map +1 -1
  26. package/_cjs/environments/definitions/optimism/environment.js +2 -1
  27. package/_cjs/environments/definitions/optimism/environment.js.map +1 -1
  28. package/_cjs/errors/version.js +1 -1
  29. package/_cjs/types/proposal.js.map +1 -1
  30. package/_esm/actions/governance/common.js +12 -7
  31. package/_esm/actions/governance/common.js.map +1 -1
  32. package/_esm/actions/governance/getStakingInfo.js +1 -1
  33. package/_esm/actions/governance/getStakingInfo.js.map +1 -1
  34. package/_esm/actions/governance/getUserStakingInfo.js +2 -2
  35. package/_esm/actions/governance/getUserStakingInfo.js.map +1 -1
  36. package/_esm/actions/governance/governor-api-client.js +21 -4
  37. package/_esm/actions/governance/governor-api-client.js.map +1 -1
  38. package/_esm/actions/governance/ipfs.js +2 -2
  39. package/_esm/actions/governance/proposals/common.js +28 -302
  40. package/_esm/actions/governance/proposals/common.js.map +1 -1
  41. package/_esm/actions/governance/proposals/getProposal.js +23 -35
  42. package/_esm/actions/governance/proposals/getProposal.js.map +1 -1
  43. package/_esm/actions/governance/proposals/getProposals.js +48 -20
  44. package/_esm/actions/governance/proposals/getProposals.js.map +1 -1
  45. package/_esm/actions/morpho/user-rewards/common.js +2 -1
  46. package/_esm/actions/morpho/user-rewards/common.js.map +1 -1
  47. package/_esm/common/lunar-indexer-helpers.js +23 -0
  48. package/_esm/common/lunar-indexer-helpers.js.map +1 -1
  49. package/_esm/environments/definitions/base/environment.js +2 -1
  50. package/_esm/environments/definitions/base/environment.js.map +1 -1
  51. package/_esm/environments/definitions/ethereum/environment.js +2 -1
  52. package/_esm/environments/definitions/ethereum/environment.js.map +1 -1
  53. package/_esm/environments/definitions/moonbeam/environment.js +2 -1
  54. package/_esm/environments/definitions/moonbeam/environment.js.map +1 -1
  55. package/_esm/environments/definitions/optimism/environment.js +2 -1
  56. package/_esm/environments/definitions/optimism/environment.js.map +1 -1
  57. package/_esm/errors/version.js +1 -1
  58. package/_esm/types/proposal.js.map +1 -1
  59. package/_types/actions/governance/common.d.ts +3 -3
  60. package/_types/actions/governance/common.d.ts.map +1 -1
  61. package/_types/actions/governance/getUserStakingInfo.d.ts.map +1 -1
  62. package/_types/actions/governance/getUserVoteReceipt.d.ts +4 -4
  63. package/_types/actions/governance/governor-api-client.d.ts +34 -4
  64. package/_types/actions/governance/governor-api-client.d.ts.map +1 -1
  65. package/_types/actions/governance/ipfs.d.ts +2 -2
  66. package/_types/actions/governance/proposals/common.d.ts +12 -39
  67. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  68. package/_types/actions/governance/proposals/getProposal.d.ts +2 -1
  69. package/_types/actions/governance/proposals/getProposal.d.ts.map +1 -1
  70. package/_types/actions/governance/proposals/getProposals.d.ts.map +1 -1
  71. package/_types/actions/morpho/user-rewards/common.d.ts.map +1 -1
  72. package/_types/common/lunar-indexer-helpers.d.ts +19 -0
  73. package/_types/common/lunar-indexer-helpers.d.ts.map +1 -1
  74. package/_types/environments/definitions/base/environment.d.ts.map +1 -1
  75. package/_types/environments/definitions/ethereum/environment.d.ts.map +1 -1
  76. package/_types/environments/definitions/moonbeam/environment.d.ts.map +1 -1
  77. package/_types/environments/definitions/optimism/environment.d.ts.map +1 -1
  78. package/_types/errors/version.d.ts +1 -1
  79. package/_types/types/proposal.d.ts +11 -0
  80. package/_types/types/proposal.d.ts.map +1 -1
  81. package/actions/governance/common.ts +14 -5
  82. package/actions/governance/getStakingInfo.ts +1 -1
  83. package/actions/governance/getUserStakingInfo.ts +4 -1
  84. package/actions/governance/getUserVoteReceipt.ts +4 -4
  85. package/actions/governance/governor-api-client.ts +35 -4
  86. package/actions/governance/ipfs.ts +2 -2
  87. package/actions/governance/proposals/common.ts +28 -466
  88. package/actions/governance/proposals/getProposal.ts +25 -49
  89. package/actions/governance/proposals/getProposals.ts +57 -30
  90. package/actions/morpho/user-rewards/common.ts +2 -1
  91. package/common/lunar-indexer-helpers.ts +26 -0
  92. package/environments/definitions/base/environment.ts +2 -2
  93. package/environments/definitions/ethereum/environment.ts +2 -2
  94. package/environments/definitions/moonbeam/environment.ts +2 -2
  95. package/environments/definitions/optimism/environment.ts +2 -2
  96. package/errors/version.ts +1 -1
  97. package/package.json +1 -1
  98. package/types/proposal.ts +11 -0
@@ -8,11 +8,7 @@ import { type Proposal, ProposalState } from "../../../types/proposal.js";
8
8
  import { type ApiProposal, fetchAllProposals } from "../governor-api-client.js";
9
9
  import { resolveIpfsDescriptions } from "../ipfs.js";
10
10
  import {
11
- appendProposalExtendedData,
12
11
  formatApiProposalData,
13
- getCrossChainProposalData,
14
- getExtendedProposalData,
15
- getProposalData,
16
12
  getProposalsOnChainData,
17
13
  readCrossChainQuorums,
18
14
  } from "./common.js";
@@ -49,10 +45,10 @@ export async function getProposals<
49
45
  const allProposals = await Promise.all(
50
46
  governanceEnvironments.map(async (governanceEnvironment) => {
51
47
  if (governanceEnvironment.chainId === moonbeam.id) {
52
- // Moonbeam: Use new Governor API
48
+ // Moonbeam + Ethereum: Governor API (chainIds 1 and 1284)
53
49
  return getMoonbeamProposals(governanceEnvironment);
54
50
  } else {
55
- // Moonriver: Use old Ponder approach
51
+ // Moonriver: Governor API, single legacy governor (chainId 1285)
56
52
  return getMoonriverProposals(governanceEnvironment);
57
53
  }
58
54
  }),
@@ -109,6 +105,53 @@ async function getMoonbeamProposals(
109
105
  }
110
106
  });
111
107
 
108
+ return buildProposals(apiProposals, governanceEnvironment);
109
+ }
110
+
111
+ /**
112
+ * Fetch proposals for Moonriver using the Governor API.
113
+ *
114
+ * Moonriver runs a single legacy standalone governor (no multichain governor),
115
+ * so we fetch only its chainId from the same lunar indexer and reuse the shared
116
+ * pipeline. `getProposalsOnChainData` classifies these as non-multichain and
117
+ * reads state/quorum from the legacy governor (via `getQuorum`).
118
+ */
119
+ async function getMoonriverProposals(
120
+ governanceEnvironment: Environment,
121
+ ): Promise<Proposal[]> {
122
+ // Moonriver is a single chain, so there's no other chain to "continue with"
123
+ // like the Moonbeam fan-out — but a bare throw would reject the whole
124
+ // `Promise.all` in getProposals and drop Moonbeam/Ethereum results too. Mirror
125
+ // the per-chain handling getMoonbeamProposals uses: report the outage via
126
+ // onError and degrade to an empty Moonriver list instead of rejecting.
127
+ let apiProposals: ApiProposal[] = [];
128
+ try {
129
+ apiProposals = await fetchAllProposals(governanceEnvironment, {
130
+ chainId: moonriver.id,
131
+ });
132
+ } catch (reason) {
133
+ console.warn(
134
+ `[getProposals] Failed to fetch proposals for chainId=${moonriver.id}; continuing with an empty Moonriver list.`,
135
+ reason,
136
+ );
137
+ governanceEnvironment.onError?.(reason, {
138
+ source: "governance-proposals",
139
+ chainId: moonriver.id,
140
+ });
141
+ }
142
+ return buildProposals(apiProposals, governanceEnvironment);
143
+ }
144
+
145
+ /**
146
+ * Shared Governor-API pipeline: resolve IPFS descriptions + cross-chain quorums
147
+ * in parallel, read on-chain data, then map each ApiProposal to a Proposal.
148
+ * Used by both the Moonbeam/Ethereum and Moonriver paths so the mapping stays
149
+ * in one place.
150
+ */
151
+ async function buildProposals(
152
+ apiProposals: ApiProposal[],
153
+ governanceEnvironment: Environment,
154
+ ): Promise<Proposal[]> {
112
155
  // IPFS resolution and cross-chain quorum reads are independent — run them in
113
156
  // parallel to save one network round-trip on the proposal list path.
114
157
  const [, crossChainQuorums] = await Promise.all([
@@ -180,11 +223,18 @@ async function getMoonbeamProposals(
180
223
  description: apiProposal.description,
181
224
  targets: apiProposal.targets,
182
225
  calldatas: apiProposal.calldatas,
183
- signatures: [],
226
+ // Legacy-governor proposals (Moonriver, early Moonbeam) carry the function
227
+ // signature separately from the selector-less calldata; pass it through so
228
+ // consumers can decode the call. Empty for multichain-governor proposals.
229
+ signatures: apiProposal.signatures ?? [],
184
230
  stateChanges: formattedData.stateChanges,
185
231
  environment: governanceEnvironment,
186
232
  };
187
233
 
234
+ if (apiProposal.snapshotBlocks) {
235
+ proposal.snapshotBlocks = apiProposal.snapshotBlocks;
236
+ }
237
+
188
238
  if (isMultichain) {
189
239
  proposal.multichain = {
190
240
  id: apiProposal.proposalId,
@@ -197,26 +247,3 @@ async function getMoonbeamProposals(
197
247
 
198
248
  return proposals;
199
249
  }
200
-
201
- /**
202
- * Fetch proposals for Moonriver using the old Ponder-based approach
203
- */
204
- async function getMoonriverProposals(
205
- governanceEnvironment: Environment,
206
- ): Promise<Proposal[]> {
207
- const [_proposals, _xcProposals, _extendedDatas] = await Promise.all([
208
- getProposalData({ environment: governanceEnvironment }),
209
- getCrossChainProposalData({ environment: governanceEnvironment }),
210
- getExtendedProposalData({ environment: governanceEnvironment }),
211
- ]);
212
-
213
- const proposals = [..._proposals, ..._xcProposals];
214
-
215
- proposals.forEach((proposal) => {
216
- proposal.environment = governanceEnvironment;
217
- });
218
-
219
- appendProposalExtendedData(proposals, _extendedDatas);
220
-
221
- return proposals;
222
- }
@@ -1,6 +1,7 @@
1
1
  import { type Address, getContract, parseAbi, zeroAddress } from "viem";
2
2
  import { Amount } from "../../../common/amount.js";
3
3
  import { MOONWELL_FETCH_JSON_HEADERS } from "../../../common/fetch-headers.js";
4
+ import { getMerklProxyBaseUrl } from "../../../common/lunar-indexer-helpers.js";
4
5
  import {
5
6
  type Environment,
6
7
  type TokenConfig,
@@ -339,7 +340,7 @@ async function getMerklRewardsData(
339
340
  account: Address,
340
341
  options: { throwOnError: boolean } = { throwOnError: false },
341
342
  ): Promise<MerklRewardsResponse[]> {
342
- const url = `https://api.merkl.xyz/v4/users/${account}/rewards?chainId=${environment.chainId}&test=false&breakdownPage=0&reloadChainId=${environment.chainId}`;
343
+ const url = `${getMerklProxyBaseUrl(environment.lunarIndexerUrl)}/users/${account}/rewards?chainId=${environment.chainId}&test=false&breakdownPage=0&reloadChainId=${environment.chainId}`;
343
344
 
344
345
  let response: Response;
345
346
  try {
@@ -2,6 +2,32 @@
2
2
  * Helper functions for working with Lunar Indexer marketId and tokenId formats
3
3
  */
4
4
 
5
+ /**
6
+ * Default lunar-indexer worker URL, used when an environment has no
7
+ * `lunarIndexerUrl` configured. Shared with the environment definitions so the
8
+ * production host has a single source of truth.
9
+ */
10
+ export const DEFAULT_LUNAR_INDEXER_URL =
11
+ "https://lunar-services-worker.moonwell.workers.dev";
12
+
13
+ /**
14
+ * Build the base URL for the Merkl proxy exposed by the lunar-indexer worker.
15
+ *
16
+ * Merkl's v4 API needs a server-side API key for production rate limits, and
17
+ * the SDK runs in the browser where it cannot hold that secret. So all Merkl
18
+ * requests go through the worker's `/api/v1/merkl` proxy, which injects the key
19
+ * and passes the query/response through unchanged.
20
+ *
21
+ * @param lunarIndexerUrl - The environment's lunar-indexer base URL. Falls back
22
+ * to the production worker when missing or empty, so Merkl always resolves.
23
+ * @returns The Merkl proxy base URL, with no trailing slash
24
+ */
25
+ export function getMerklProxyBaseUrl(lunarIndexerUrl?: string): string {
26
+ // `||` (not `??`) so an empty-string misconfig also falls back rather than
27
+ // producing a host-less `/api/v1/merkl/...` URL.
28
+ return `${lunarIndexerUrl || DEFAULT_LUNAR_INDEXER_URL}/api/v1/merkl`;
29
+ }
30
+
5
31
  /**
6
32
  * Build a marketId string from chainId and market address
7
33
  * Format: {chainId}-{marketAddress}
@@ -1,5 +1,6 @@
1
1
  import { http, defineChain, fallback } from "viem";
2
2
  import { base as baseChain } from "viem/chains";
3
+ import { DEFAULT_LUNAR_INDEXER_URL } from "../../../common/lunar-indexer-helpers.js";
3
4
  import {
4
5
  type Environment,
5
6
  createEnvironmentConfig,
@@ -39,8 +40,7 @@ const createEnvironment = (
39
40
  governanceIndexerUrl:
40
41
  governanceIndexerUrl ||
41
42
  "https://lunar-services-worker.moonwell.workers.dev",
42
- lunarIndexerUrl:
43
- lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
43
+ lunarIndexerUrl: lunarIndexerUrl || DEFAULT_LUNAR_INDEXER_URL,
44
44
  tokens,
45
45
  markets,
46
46
  vaults,
@@ -1,5 +1,6 @@
1
1
  import { http, defineChain, fallback } from "viem";
2
2
  import { mainnet } from "viem/chains";
3
+ import { DEFAULT_LUNAR_INDEXER_URL } from "../../../common/lunar-indexer-helpers.js";
3
4
  import {
4
5
  type Environment,
5
6
  createEnvironmentConfig,
@@ -39,8 +40,7 @@ const createEnvironment = (
39
40
  governanceIndexerUrl:
40
41
  governanceIndexerUrl ||
41
42
  "https://lunar-services-worker.moonwell.workers.dev",
42
- lunarIndexerUrl:
43
- lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
43
+ lunarIndexerUrl: lunarIndexerUrl || DEFAULT_LUNAR_INDEXER_URL,
44
44
  tokens,
45
45
  markets,
46
46
  vaults: {},
@@ -1,5 +1,6 @@
1
1
  import { http, fallback } from "viem";
2
2
  import { moonbeam } from "viem/chains";
3
+ import { DEFAULT_LUNAR_INDEXER_URL } from "../../../common/lunar-indexer-helpers.js";
3
4
  import { createEnvironmentConfig } from "../../types/config.js";
4
5
  import { contracts } from "./contracts.js";
5
6
  import { markets } from "./core-markets.js";
@@ -23,8 +24,7 @@ const createEnvironment = (
23
24
  transport: rpcUrls
24
25
  ? fallback(rpcUrls.map((url) => http(url)))
25
26
  : http("https://rpc.moonwell.fi/main/evm/1284"),
26
- lunarIndexerUrl:
27
- lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
27
+ lunarIndexerUrl: lunarIndexerUrl || DEFAULT_LUNAR_INDEXER_URL,
28
28
  governanceIndexerUrl:
29
29
  governanceIndexerUrl ||
30
30
  "https://lunar-services-worker.moonwell.workers.dev",
@@ -1,5 +1,6 @@
1
1
  import { http, defineChain, fallback } from "viem";
2
2
  import { optimism as optimismChain } from "viem/chains";
3
+ import { DEFAULT_LUNAR_INDEXER_URL } from "../../../common/lunar-indexer-helpers.js";
3
4
  import { createEnvironmentConfig } from "../../types/config.js";
4
5
  import { contracts } from "./contracts.js";
5
6
  import { markets } from "./core-markets.js";
@@ -26,8 +27,7 @@ const createEnvironment = (
26
27
  transport: rpcUrls
27
28
  ? fallback(rpcUrls.map((url) => http(url)))
28
29
  : http("https://rpc.moonwell.fi/main/evm/10"),
29
- lunarIndexerUrl:
30
- lunarIndexerUrl || "https://lunar-services-worker.moonwell.workers.dev",
30
+ lunarIndexerUrl: lunarIndexerUrl || DEFAULT_LUNAR_INDEXER_URL,
31
31
  governanceIndexerUrl:
32
32
  governanceIndexerUrl ||
33
33
  "https://lunar-services-worker.moonwell.workers.dev",
package/errors/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '0.20.2'
1
+ export const version = '0.20.4'
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.20.2",
4
+ "version": "0.20.4",
5
5
  "main": "./_cjs/index.js",
6
6
  "module": "./_esm/index.js",
7
7
  "types": "./_types/index.d.ts",
package/types/proposal.ts CHANGED
@@ -23,6 +23,17 @@ export type Proposal = {
23
23
  id: number;
24
24
  votesCollected: boolean;
25
25
  };
26
+ /**
27
+ * Authoritative per-chain voting-power snapshot blocks resolved by the
28
+ * lunar-indexer, keyed by chain name (`mainnet` → 1, `base` → 8453,
29
+ * `optimism` → 10, `moonbeam` → 1284). Block numbers are decimal strings.
30
+ *
31
+ * Present on indexer-sourced multichain proposals; absent for older
32
+ * proposals indexed before the field existed and for on-chain (Moonriver)
33
+ * proposals. Consumers reading voting power should prefer these blocks over
34
+ * resolving the snapshot timestamp to a block client-side.
35
+ */
36
+ snapshotBlocks?: Record<string, string>;
26
37
  //proposal extended data
27
38
  title?: string;
28
39
  subtitle?: string;