@moonwell-fi/moonwell-sdk 0.20.3 → 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.
- package/CHANGELOG.md +10 -0
- package/_cjs/actions/governance/governor-api-client.js +3 -2
- package/_cjs/actions/governance/governor-api-client.js.map +1 -1
- package/_cjs/actions/governance/proposals/common.js +11 -296
- package/_cjs/actions/governance/proposals/common.js.map +1 -1
- package/_cjs/actions/governance/proposals/getProposal.js +9 -25
- package/_cjs/actions/governance/proposals/getProposal.js.map +1 -1
- package/_cjs/actions/governance/proposals/getProposals.js +23 -14
- package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/types/proposal.js.map +1 -1
- package/_esm/actions/governance/governor-api-client.js +21 -4
- package/_esm/actions/governance/governor-api-client.js.map +1 -1
- package/_esm/actions/governance/ipfs.js +2 -2
- package/_esm/actions/governance/proposals/common.js +28 -302
- package/_esm/actions/governance/proposals/common.js.map +1 -1
- package/_esm/actions/governance/proposals/getProposal.js +23 -35
- package/_esm/actions/governance/proposals/getProposal.js.map +1 -1
- package/_esm/actions/governance/proposals/getProposals.js +48 -20
- package/_esm/actions/governance/proposals/getProposals.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/types/proposal.js.map +1 -1
- package/_types/actions/governance/getUserVoteReceipt.d.ts +4 -4
- package/_types/actions/governance/governor-api-client.d.ts +34 -4
- package/_types/actions/governance/governor-api-client.d.ts.map +1 -1
- package/_types/actions/governance/ipfs.d.ts +2 -2
- package/_types/actions/governance/proposals/common.d.ts +12 -39
- package/_types/actions/governance/proposals/common.d.ts.map +1 -1
- package/_types/actions/governance/proposals/getProposal.d.ts +2 -1
- package/_types/actions/governance/proposals/getProposal.d.ts.map +1 -1
- package/_types/actions/governance/proposals/getProposals.d.ts.map +1 -1
- package/_types/errors/version.d.ts +1 -1
- package/_types/types/proposal.d.ts +11 -0
- package/_types/types/proposal.d.ts.map +1 -1
- package/actions/governance/getUserVoteReceipt.ts +4 -4
- package/actions/governance/governor-api-client.ts +35 -4
- package/actions/governance/ipfs.ts +2 -2
- package/actions/governance/proposals/common.ts +28 -466
- package/actions/governance/proposals/getProposal.ts +25 -49
- package/actions/governance/proposals/getProposals.ts +57 -30
- package/errors/version.ts +1 -1
- package/package.json +1 -1
- package/types/proposal.ts +11 -0
|
@@ -6,17 +6,13 @@ import type { Chain, Environment } from "../../../environments/index.js";
|
|
|
6
6
|
import { type Proposal, ProposalState } from "../../../types/proposal.js";
|
|
7
7
|
import {
|
|
8
8
|
type ApiProposal,
|
|
9
|
-
|
|
9
|
+
MULTIGOV_PROPOSAL_FALLBACK_CHAIN_IDS,
|
|
10
10
|
fetchProposal,
|
|
11
11
|
isNotFoundError,
|
|
12
12
|
} from "../governor-api-client.js";
|
|
13
13
|
import { resolveIpfsDescriptions } from "../ipfs.js";
|
|
14
14
|
import {
|
|
15
|
-
appendProposalExtendedData,
|
|
16
15
|
formatApiProposalData,
|
|
17
|
-
getCrossChainProposalData,
|
|
18
|
-
getExtendedProposalData,
|
|
19
|
-
getProposalData,
|
|
20
16
|
getProposalsOnChainData,
|
|
21
17
|
readCrossChainQuorums,
|
|
22
18
|
} from "./common.js";
|
|
@@ -28,7 +24,8 @@ export type GetProposalParameters<
|
|
|
28
24
|
proposalId: number;
|
|
29
25
|
/**
|
|
30
26
|
* The chain the proposal lives on (1 = Ethereum multigov,
|
|
31
|
-
* 1284 = Moonbeam historical). When omitted,
|
|
27
|
+
* 1284 = Moonbeam historical, 1285 = Moonriver legacy). When omitted, the
|
|
28
|
+
* supported chains are tried in turn.
|
|
32
29
|
*/
|
|
33
30
|
chainId?: number;
|
|
34
31
|
};
|
|
@@ -51,7 +48,7 @@ export async function getProposal<
|
|
|
51
48
|
|
|
52
49
|
// Ethereum-home multigov proposals are served by the same Governor API as
|
|
53
50
|
// historical Moonbeam ones (the lunar indexer fans out both chainIds), so
|
|
54
|
-
// route them through `
|
|
51
|
+
// route them through `getGovernorApiProposal` using the Moonbeam env as the
|
|
55
52
|
// indexer source. Without this, a caller resolving the env by `chainId: 1`
|
|
56
53
|
// would bail out on the `!moonbeam && !moonriver` check below and the page
|
|
57
54
|
// reload path returns undefined.
|
|
@@ -62,7 +59,7 @@ export async function getProposal<
|
|
|
62
59
|
if (!moonbeamEnv) {
|
|
63
60
|
return undefined;
|
|
64
61
|
}
|
|
65
|
-
return
|
|
62
|
+
return getGovernorApiProposal(
|
|
66
63
|
moonbeamEnv,
|
|
67
64
|
proposalId,
|
|
68
65
|
args.chainId ?? mainnet.id,
|
|
@@ -77,25 +74,29 @@ export async function getProposal<
|
|
|
77
74
|
}
|
|
78
75
|
|
|
79
76
|
if (environment.chainId === moonbeam.id) {
|
|
80
|
-
return
|
|
77
|
+
return getGovernorApiProposal(environment, proposalId, args.chainId);
|
|
81
78
|
}
|
|
82
|
-
return
|
|
79
|
+
return getGovernorApiProposal(environment, proposalId, moonriver.id);
|
|
83
80
|
}
|
|
84
81
|
|
|
85
82
|
/**
|
|
86
|
-
* Fetch a single proposal
|
|
83
|
+
* Fetch a single proposal from the Governor API (Moonbeam/Ethereum multigov or
|
|
84
|
+
* Moonriver legacy governor).
|
|
87
85
|
*
|
|
88
86
|
* When `chainId` is provided we hit only that chain. When omitted we try the
|
|
89
|
-
*
|
|
90
|
-
* proposals live) and fall back on `NotFoundError`.
|
|
91
|
-
*
|
|
87
|
+
* multigov chains in order (Ethereum first since that's where active multigov
|
|
88
|
+
* proposals live) and fall back on `NotFoundError`. Moonriver (1285) is
|
|
89
|
+
* deliberately absent from the fallback — it has its own explicit route, and a
|
|
90
|
+
* bare lookup resolving to it through a non-Moonriver env would be degraded.
|
|
91
|
+
* Real outages (5xx, network errors) propagate so callers can distinguish
|
|
92
|
+
* "missing" from "broken".
|
|
92
93
|
*/
|
|
93
|
-
async function
|
|
94
|
+
async function getGovernorApiProposal(
|
|
94
95
|
governanceEnvironment: Environment,
|
|
95
96
|
proposalId: number,
|
|
96
97
|
chainId?: number,
|
|
97
98
|
): Promise<Proposal | undefined> {
|
|
98
|
-
const tryChains = chainId ? [chainId] :
|
|
99
|
+
const tryChains = chainId ? [chainId] : MULTIGOV_PROPOSAL_FALLBACK_CHAIN_IDS;
|
|
99
100
|
|
|
100
101
|
let apiProposal: ApiProposal | undefined;
|
|
101
102
|
for (const cid of tryChains) {
|
|
@@ -180,11 +181,18 @@ async function getMoonbeamProposal(
|
|
|
180
181
|
description: apiProposal.description,
|
|
181
182
|
targets: apiProposal.targets,
|
|
182
183
|
calldatas: apiProposal.calldatas,
|
|
183
|
-
|
|
184
|
+
// Legacy-governor proposals (Moonriver, early Moonbeam) carry the function
|
|
185
|
+
// signature separately from the selector-less calldata; pass it through so
|
|
186
|
+
// consumers can decode the call. Empty for multichain-governor proposals.
|
|
187
|
+
signatures: apiProposal.signatures ?? [],
|
|
184
188
|
stateChanges: formattedData.stateChanges,
|
|
185
189
|
environment: governanceEnvironment,
|
|
186
190
|
};
|
|
187
191
|
|
|
192
|
+
if (apiProposal.snapshotBlocks) {
|
|
193
|
+
proposal.snapshotBlocks = apiProposal.snapshotBlocks;
|
|
194
|
+
}
|
|
195
|
+
|
|
188
196
|
if (isMultichain) {
|
|
189
197
|
proposal.multichain = {
|
|
190
198
|
id: apiProposal.proposalId,
|
|
@@ -194,35 +202,3 @@ async function getMoonbeamProposal(
|
|
|
194
202
|
|
|
195
203
|
return proposal;
|
|
196
204
|
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Fetch a single proposal for Moonriver using the old Ponder-based approach
|
|
200
|
-
*/
|
|
201
|
-
async function getMoonriverProposal(
|
|
202
|
-
governanceEnvironment: Environment,
|
|
203
|
-
proposalId: number,
|
|
204
|
-
): Promise<Proposal | undefined> {
|
|
205
|
-
const [_proposals, _xcProposals, _extendedDatas] = await Promise.all([
|
|
206
|
-
getProposalData({ environment: governanceEnvironment, id: proposalId }),
|
|
207
|
-
getCrossChainProposalData({
|
|
208
|
-
environment: governanceEnvironment,
|
|
209
|
-
id: proposalId,
|
|
210
|
-
}),
|
|
211
|
-
getExtendedProposalData({
|
|
212
|
-
environment: governanceEnvironment,
|
|
213
|
-
id: proposalId,
|
|
214
|
-
}),
|
|
215
|
-
]);
|
|
216
|
-
|
|
217
|
-
const proposals = [..._proposals, ..._xcProposals];
|
|
218
|
-
|
|
219
|
-
proposals.forEach((proposal) => {
|
|
220
|
-
proposal.environment = governanceEnvironment;
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
appendProposalExtendedData(proposals, _extendedDatas);
|
|
224
|
-
|
|
225
|
-
return proposals.find(
|
|
226
|
-
(p) => p.proposalId === proposalId || p.id === proposalId,
|
|
227
|
-
);
|
|
228
|
-
}
|
|
@@ -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
|
|
48
|
+
// Moonbeam + Ethereum: Governor API (chainIds 1 and 1284)
|
|
53
49
|
return getMoonbeamProposals(governanceEnvironment);
|
|
54
50
|
} else {
|
|
55
|
-
// Moonriver:
|
|
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
|
-
|
|
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
|
-
}
|
package/errors/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '0.20.
|
|
1
|
+
export const version = '0.20.4'
|
package/package.json
CHANGED
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;
|