@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.
- package/CHANGELOG.md +18 -0
- package/_cjs/actions/governance/common.js +9 -7
- package/_cjs/actions/governance/common.js.map +1 -1
- package/_cjs/actions/governance/getStakingInfo.js +1 -1
- package/_cjs/actions/governance/getStakingInfo.js.map +1 -1
- package/_cjs/actions/governance/getUserStakingInfo.js +2 -2
- package/_cjs/actions/governance/getUserStakingInfo.js.map +1 -1
- 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/actions/morpho/user-rewards/common.js +2 -1
- package/_cjs/actions/morpho/user-rewards/common.js.map +1 -1
- package/_cjs/common/lunar-indexer-helpers.js +6 -0
- package/_cjs/common/lunar-indexer-helpers.js.map +1 -1
- package/_cjs/environments/definitions/base/environment.js +2 -1
- package/_cjs/environments/definitions/base/environment.js.map +1 -1
- package/_cjs/environments/definitions/ethereum/environment.js +2 -1
- package/_cjs/environments/definitions/ethereum/environment.js.map +1 -1
- package/_cjs/environments/definitions/moonbeam/environment.js +2 -1
- package/_cjs/environments/definitions/moonbeam/environment.js.map +1 -1
- package/_cjs/environments/definitions/optimism/environment.js +2 -1
- package/_cjs/environments/definitions/optimism/environment.js.map +1 -1
- package/_cjs/errors/version.js +1 -1
- package/_cjs/types/proposal.js.map +1 -1
- package/_esm/actions/governance/common.js +12 -7
- package/_esm/actions/governance/common.js.map +1 -1
- package/_esm/actions/governance/getStakingInfo.js +1 -1
- package/_esm/actions/governance/getStakingInfo.js.map +1 -1
- package/_esm/actions/governance/getUserStakingInfo.js +2 -2
- package/_esm/actions/governance/getUserStakingInfo.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/actions/morpho/user-rewards/common.js +2 -1
- package/_esm/actions/morpho/user-rewards/common.js.map +1 -1
- package/_esm/common/lunar-indexer-helpers.js +23 -0
- package/_esm/common/lunar-indexer-helpers.js.map +1 -1
- package/_esm/environments/definitions/base/environment.js +2 -1
- package/_esm/environments/definitions/base/environment.js.map +1 -1
- package/_esm/environments/definitions/ethereum/environment.js +2 -1
- package/_esm/environments/definitions/ethereum/environment.js.map +1 -1
- package/_esm/environments/definitions/moonbeam/environment.js +2 -1
- package/_esm/environments/definitions/moonbeam/environment.js.map +1 -1
- package/_esm/environments/definitions/optimism/environment.js +2 -1
- package/_esm/environments/definitions/optimism/environment.js.map +1 -1
- package/_esm/errors/version.js +1 -1
- package/_esm/types/proposal.js.map +1 -1
- package/_types/actions/governance/common.d.ts +3 -3
- package/_types/actions/governance/common.d.ts.map +1 -1
- package/_types/actions/governance/getUserStakingInfo.d.ts.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/actions/morpho/user-rewards/common.d.ts.map +1 -1
- package/_types/common/lunar-indexer-helpers.d.ts +19 -0
- package/_types/common/lunar-indexer-helpers.d.ts.map +1 -1
- package/_types/environments/definitions/base/environment.d.ts.map +1 -1
- package/_types/environments/definitions/ethereum/environment.d.ts.map +1 -1
- package/_types/environments/definitions/moonbeam/environment.d.ts.map +1 -1
- package/_types/environments/definitions/optimism/environment.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/common.ts +14 -5
- package/actions/governance/getStakingInfo.ts +1 -1
- package/actions/governance/getUserStakingInfo.ts +4 -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/actions/morpho/user-rewards/common.ts +2 -1
- package/common/lunar-indexer-helpers.ts +26 -0
- package/environments/definitions/base/environment.ts +2 -2
- package/environments/definitions/ethereum/environment.ts +2 -2
- package/environments/definitions/moonbeam/environment.ts +2 -2
- package/environments/definitions/optimism/environment.ts +2 -2
- package/errors/version.ts +1 -1
- package/package.json +1 -1
- package/types/proposal.ts +11 -0
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
-
import last from "lodash/last.js";
|
|
3
|
-
import { moonriver } from "viem/chains";
|
|
4
2
|
import { Amount } from "../../../common/index.js";
|
|
5
3
|
import type { Environment } from "../../../environments/index.js";
|
|
6
4
|
import { publicEnvironments } from "../../../environments/index.js";
|
|
7
5
|
import {
|
|
8
6
|
MultichainProposalState,
|
|
9
7
|
MultichainProposalStateMapping,
|
|
10
|
-
type Proposal,
|
|
11
8
|
ProposalState,
|
|
12
9
|
} from "../../../types/proposal.js";
|
|
13
|
-
import { postWithRetry } from "../../axiosWithRetry.js";
|
|
14
10
|
import type { ApiProposal } from "../governor-api-client.js";
|
|
15
11
|
|
|
16
12
|
export const WORMHOLE_CONTRACT = "0xc8e2b0cd52cf01b0ce87d389daa3d414d4ce29f3"; // Moonbeam
|
|
@@ -25,21 +21,6 @@ const MULTICHAIN_WORMHOLE_BRIDGES: ReadonlySet<string> = new Set([
|
|
|
25
21
|
"0x98f3c9e6e3face36baad05fe09d375ef1464288b", // Ethereum
|
|
26
22
|
]);
|
|
27
23
|
|
|
28
|
-
type PonderExtendedProposalData = {
|
|
29
|
-
id: number;
|
|
30
|
-
title: string;
|
|
31
|
-
subtitle: string;
|
|
32
|
-
description: string;
|
|
33
|
-
targets: string[];
|
|
34
|
-
calldatas: string[];
|
|
35
|
-
signatures: string[];
|
|
36
|
-
stateChanges: {
|
|
37
|
-
blockNumber: number;
|
|
38
|
-
transactionHash: string;
|
|
39
|
-
state: string;
|
|
40
|
-
}[];
|
|
41
|
-
};
|
|
42
|
-
|
|
43
24
|
axios.defaults.timeout = 5_000;
|
|
44
25
|
|
|
45
26
|
/**
|
|
@@ -143,15 +124,26 @@ export const isMultichainHomeChain = (chainId: number): boolean => {
|
|
|
143
124
|
* falls back to the home/bridge checks. Omit it or pass `undefined` when the
|
|
144
125
|
* count read failed so the unknown-cutoff bias above applies. (No `= 0` default:
|
|
145
126
|
* that would coerce an explicit `undefined` back to 0 and defeat the bias.)
|
|
127
|
+
*
|
|
128
|
+
* `hasMultichainGovernor` gates rule 4: the unknown-cutoff bias only makes sense
|
|
129
|
+
* on a chain that actually has a multichain governor to route to. On a
|
|
130
|
+
* legacy-only chain (Moonriver — legacy `governor`, no `multichainGovernor`) a
|
|
131
|
+
* failed Artemis count must NOT flip the proposal to multichain, which would
|
|
132
|
+
* route reads to a null contract and surface a spurious `multichain` field.
|
|
133
|
+
* Defaults to `true` so callers that don't supply it keep the dual-governor
|
|
134
|
+
* (Moonbeam) bias behavior.
|
|
146
135
|
*/
|
|
147
136
|
export const classifyProposalMultichain = (
|
|
148
137
|
proposal: { targets?: string[]; proposalId: number; chainId: number },
|
|
149
138
|
legacyArtemisMaxId?: number,
|
|
139
|
+
hasMultichainGovernor = true,
|
|
150
140
|
): boolean =>
|
|
151
141
|
isMultichainHomeChain(proposal.chainId) ||
|
|
152
142
|
isMultichainProposal(proposal.targets) ||
|
|
153
|
-
legacyArtemisMaxId === undefined ||
|
|
154
|
-
(legacyArtemisMaxId
|
|
143
|
+
(legacyArtemisMaxId === undefined && hasMultichainGovernor) ||
|
|
144
|
+
(legacyArtemisMaxId !== undefined &&
|
|
145
|
+
legacyArtemisMaxId > 0 &&
|
|
146
|
+
proposal.proposalId > legacyArtemisMaxId);
|
|
155
147
|
|
|
156
148
|
/**
|
|
157
149
|
* @deprecated Use `classifyProposalMultichain` — this variant misses hub-homed
|
|
@@ -330,9 +322,8 @@ const getLegacyArtemisMaxId = async (
|
|
|
330
322
|
* the `options.crossChainQuorums?.get(...) ?? 0n` pattern.
|
|
331
323
|
*
|
|
332
324
|
* Read failures are routed through `onError` so Sentry-wired consumers see
|
|
333
|
-
* them — matching `
|
|
334
|
-
* `
|
|
335
|
-
* `onError` since we don't have one per foreign chain in scope.
|
|
325
|
+
* them — matching `getProposalsOnChainData`. The caller's `governanceEnvironment`
|
|
326
|
+
* carries `onError` since we don't have one per foreign chain in scope.
|
|
336
327
|
*/
|
|
337
328
|
export const getEnvironmentByChainId = (
|
|
338
329
|
chainId: number,
|
|
@@ -393,6 +384,15 @@ export const getProposalsOnChainData = async (
|
|
|
393
384
|
: await governanceEnvironment.contracts.governor.read.getQuorum();
|
|
394
385
|
} catch (error) {
|
|
395
386
|
console.warn("Failed to fetch quorum:", error);
|
|
387
|
+
// Report so a swallowed quorum failure (which leaves quorum at 0n) is
|
|
388
|
+
// still observable to onError-wired consumers — the legacy Moonriver path
|
|
389
|
+
// surfaced this too. Uses a distinct `source` from the state/proposals
|
|
390
|
+
// reads (and from readCrossChainQuorums' "governance-cross-chain-quorum")
|
|
391
|
+
// so a local quorum-read failure is attributable on its own.
|
|
392
|
+
governanceEnvironment.onError?.(error, {
|
|
393
|
+
source: "governance-quorum",
|
|
394
|
+
chainId: governanceEnvironment.chainId,
|
|
395
|
+
});
|
|
396
396
|
}
|
|
397
397
|
}
|
|
398
398
|
|
|
@@ -420,10 +420,13 @@ export const getProposalsOnChainData = async (
|
|
|
420
420
|
// (Ethereum multigov, no Artemis predecessor) classify as multichain
|
|
421
421
|
// regardless of targets via classifyProposalMultichain. Computed once
|
|
422
422
|
// here and returned on ProposalOnChainData so callers don't re-classify
|
|
423
|
-
// and drift (see getProposal/getProposals).
|
|
423
|
+
// and drift (see getProposal/getProposals). `hasMultichainGovernor` keeps
|
|
424
|
+
// the unknown-cutoff bias from misrouting legacy-only chains (Moonriver)
|
|
425
|
+
// to a nonexistent multichain governor when the Artemis count read fails.
|
|
424
426
|
const isMultichain = classifyProposalMultichain(
|
|
425
427
|
p,
|
|
426
428
|
isLocal ? legacyArtemisMaxId : 0,
|
|
429
|
+
Boolean(homeEnv?.contracts.multichainGovernor),
|
|
427
430
|
);
|
|
428
431
|
|
|
429
432
|
if (!homeEnv) {
|
|
@@ -557,444 +560,3 @@ export const getProposalsOnChainData = async (
|
|
|
557
560
|
|
|
558
561
|
return onChainDataList;
|
|
559
562
|
};
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* Get proposal data from on-chain (Ponder-based, for Moonriver)
|
|
563
|
-
*/
|
|
564
|
-
export const getProposalData = async (params: {
|
|
565
|
-
environment: Environment;
|
|
566
|
-
id?: number;
|
|
567
|
-
}) => {
|
|
568
|
-
try {
|
|
569
|
-
if (params.environment.contracts.governor) {
|
|
570
|
-
let count = 0n;
|
|
571
|
-
let quorum = 0n;
|
|
572
|
-
|
|
573
|
-
if (params.environment.chainId === moonriver.id) {
|
|
574
|
-
[count, quorum] = await Promise.all([
|
|
575
|
-
params.environment.contracts.governor.read.proposalCount(),
|
|
576
|
-
params.environment.contracts.governor.read.getQuorum(),
|
|
577
|
-
]);
|
|
578
|
-
} else {
|
|
579
|
-
[count, quorum] = await Promise.all([
|
|
580
|
-
params.environment.contracts.governor.read.proposalCount(),
|
|
581
|
-
params.environment.contracts.governor.read.quorumVotes(),
|
|
582
|
-
]);
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (params.id) {
|
|
586
|
-
if (BigInt(params.id) > count) {
|
|
587
|
-
return [];
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
const ids = params.id
|
|
592
|
-
? [BigInt(params.id)]
|
|
593
|
-
: Array.from({ length: Number(count) }, (_, i) => count - BigInt(i));
|
|
594
|
-
|
|
595
|
-
const proposalDataCall = Promise.all(
|
|
596
|
-
ids.map((id) =>
|
|
597
|
-
params.environment.contracts.governor?.read.proposals([id]),
|
|
598
|
-
),
|
|
599
|
-
);
|
|
600
|
-
|
|
601
|
-
const proposalStateCall = Promise.all(
|
|
602
|
-
ids.map((id) =>
|
|
603
|
-
params.environment.contracts.governor?.read.state([id]),
|
|
604
|
-
),
|
|
605
|
-
);
|
|
606
|
-
|
|
607
|
-
const [proposalsData, proposalsState] = await Promise.all([
|
|
608
|
-
proposalDataCall,
|
|
609
|
-
proposalStateCall,
|
|
610
|
-
]);
|
|
611
|
-
|
|
612
|
-
const proposals = proposalsData?.map((item, index: number) => {
|
|
613
|
-
const state = proposalsState?.[index]!;
|
|
614
|
-
|
|
615
|
-
const [
|
|
616
|
-
id,
|
|
617
|
-
proposer,
|
|
618
|
-
eta,
|
|
619
|
-
startTimestamp,
|
|
620
|
-
endTimestamp,
|
|
621
|
-
startBlock,
|
|
622
|
-
forVotes,
|
|
623
|
-
againstVotes,
|
|
624
|
-
abstainVotes,
|
|
625
|
-
totalVotes,
|
|
626
|
-
canceled,
|
|
627
|
-
executed,
|
|
628
|
-
] = item!;
|
|
629
|
-
|
|
630
|
-
const proposal: Proposal = {
|
|
631
|
-
chainId: params.environment.chainId,
|
|
632
|
-
id: Number(id),
|
|
633
|
-
proposalId: Number(id),
|
|
634
|
-
proposer,
|
|
635
|
-
eta: Number(eta),
|
|
636
|
-
startTimestamp: Number(startTimestamp),
|
|
637
|
-
endTimestamp: Number(endTimestamp),
|
|
638
|
-
startBlock: Number(startBlock),
|
|
639
|
-
forVotes: new Amount(forVotes, 18),
|
|
640
|
-
againstVotes: new Amount(againstVotes, 18),
|
|
641
|
-
abstainVotes: new Amount(abstainVotes, 18),
|
|
642
|
-
totalVotes: new Amount(totalVotes, 18),
|
|
643
|
-
canceled,
|
|
644
|
-
executed,
|
|
645
|
-
quorum: new Amount(quorum, 18),
|
|
646
|
-
state,
|
|
647
|
-
};
|
|
648
|
-
|
|
649
|
-
return proposal;
|
|
650
|
-
});
|
|
651
|
-
|
|
652
|
-
return proposals;
|
|
653
|
-
} else {
|
|
654
|
-
return [];
|
|
655
|
-
}
|
|
656
|
-
} catch (error) {
|
|
657
|
-
console.warn(
|
|
658
|
-
`[getProposalData] RPC failed for chain ${params.environment.chainId}:`,
|
|
659
|
-
error,
|
|
660
|
-
);
|
|
661
|
-
params.environment.onError?.(error, {
|
|
662
|
-
source: "governance-proposals",
|
|
663
|
-
chainId: params.environment.chainId,
|
|
664
|
-
});
|
|
665
|
-
return [];
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
* Get cross-chain proposal data (Ponder-based, for Moonriver)
|
|
671
|
-
*/
|
|
672
|
-
export const getCrossChainProposalData = async (params: {
|
|
673
|
-
environment: Environment;
|
|
674
|
-
id?: number;
|
|
675
|
-
}) => {
|
|
676
|
-
try {
|
|
677
|
-
if (params.environment.contracts.governor) {
|
|
678
|
-
const xcGovernanceSettings = params.environment.custom.governance;
|
|
679
|
-
if (
|
|
680
|
-
params.environment.contracts.multichainGovernor &&
|
|
681
|
-
xcGovernanceSettings &&
|
|
682
|
-
xcGovernanceSettings.chainIds.length > 0
|
|
683
|
-
) {
|
|
684
|
-
const xcEnvironments = xcGovernanceSettings.chainIds
|
|
685
|
-
.map((chainId) =>
|
|
686
|
-
(Object.values(publicEnvironments) as Environment[]).find(
|
|
687
|
-
(env) => env.chainId === chainId,
|
|
688
|
-
),
|
|
689
|
-
)
|
|
690
|
-
.filter((xcEnvironment) => !!xcEnvironment)
|
|
691
|
-
.filter(
|
|
692
|
-
(xcEnvironment) =>
|
|
693
|
-
xcEnvironment!.custom?.wormhole?.chainId &&
|
|
694
|
-
xcEnvironment!.contracts.voteCollector,
|
|
695
|
-
);
|
|
696
|
-
|
|
697
|
-
const [xcCount, xcQuorum] = await Promise.all([
|
|
698
|
-
params.environment.contracts.multichainGovernor.read.proposalCount(),
|
|
699
|
-
params.environment.contracts.multichainGovernor.read.quorum(),
|
|
700
|
-
]);
|
|
701
|
-
|
|
702
|
-
if (params.id) {
|
|
703
|
-
params.id =
|
|
704
|
-
Number(params.id) -
|
|
705
|
-
(params.environment.custom?.governance?.proposalIdOffset || 0);
|
|
706
|
-
|
|
707
|
-
if (params.id < 0) return [];
|
|
708
|
-
if (BigInt(params.id) > xcCount) return [];
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
const ids = params.id
|
|
712
|
-
? [BigInt(params.id)]
|
|
713
|
-
: Array.from(
|
|
714
|
-
{ length: Number(xcCount) },
|
|
715
|
-
(_, i) => xcCount - BigInt(i),
|
|
716
|
-
);
|
|
717
|
-
|
|
718
|
-
const xcProposalsDataCall = Promise.all(
|
|
719
|
-
ids.map((id) =>
|
|
720
|
-
params.environment.contracts.multichainGovernor?.read.proposals([
|
|
721
|
-
id,
|
|
722
|
-
]),
|
|
723
|
-
),
|
|
724
|
-
);
|
|
725
|
-
|
|
726
|
-
const xcProposalsStateCall = Promise.all(
|
|
727
|
-
ids.map((id) =>
|
|
728
|
-
params.environment.contracts.multichainGovernor?.read.state([id]),
|
|
729
|
-
),
|
|
730
|
-
);
|
|
731
|
-
|
|
732
|
-
const xcVotesCall = Promise.all(
|
|
733
|
-
xcEnvironments.map((xcEnvironment) =>
|
|
734
|
-
Promise.all(
|
|
735
|
-
ids.map((id) =>
|
|
736
|
-
params.environment.contracts.multichainGovernor?.read.chainVoteCollectorVotes(
|
|
737
|
-
[(xcEnvironment!.custom as any).wormhole.chainId, id],
|
|
738
|
-
),
|
|
739
|
-
),
|
|
740
|
-
),
|
|
741
|
-
),
|
|
742
|
-
);
|
|
743
|
-
|
|
744
|
-
const [xcProposalsData, xcProposalsState, xcVotes] = await Promise.all([
|
|
745
|
-
xcProposalsDataCall,
|
|
746
|
-
xcProposalsStateCall,
|
|
747
|
-
xcVotesCall,
|
|
748
|
-
]);
|
|
749
|
-
|
|
750
|
-
const proposals = ids.map((xcId, proposalIndex: number) => {
|
|
751
|
-
const state = xcProposalsState?.[proposalIndex]!;
|
|
752
|
-
const id =
|
|
753
|
-
Number(xcId) +
|
|
754
|
-
(params.environment.custom?.governance?.proposalIdOffset || 0);
|
|
755
|
-
|
|
756
|
-
const votesCollected = false;
|
|
757
|
-
|
|
758
|
-
const votes = xcVotes.reduce(
|
|
759
|
-
(prevVotes, currVotes) => {
|
|
760
|
-
const voteData = currVotes[proposalIndex];
|
|
761
|
-
if (!voteData) {
|
|
762
|
-
return prevVotes;
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
// chainVoteCollectorVotes returns [forVotes, againstVotes, abstainVotes]
|
|
766
|
-
const forVotes = voteData[0] || 0n;
|
|
767
|
-
const againstVotes = voteData[1] || 0n;
|
|
768
|
-
const abstainVotes = voteData[2] || 0n;
|
|
769
|
-
const totalVotes = forVotes + againstVotes + abstainVotes;
|
|
770
|
-
|
|
771
|
-
return {
|
|
772
|
-
totalVotes: prevVotes.totalVotes + totalVotes,
|
|
773
|
-
forVotes: prevVotes.forVotes + forVotes,
|
|
774
|
-
againstVotes: prevVotes.againstVotes + againstVotes,
|
|
775
|
-
abstainVotes: prevVotes.abstainVotes + abstainVotes,
|
|
776
|
-
};
|
|
777
|
-
},
|
|
778
|
-
{
|
|
779
|
-
totalVotes: 0n,
|
|
780
|
-
forVotes: 0n,
|
|
781
|
-
againstVotes: 0n,
|
|
782
|
-
abstainVotes: 0n,
|
|
783
|
-
},
|
|
784
|
-
);
|
|
785
|
-
|
|
786
|
-
const proposalData = xcProposalsData?.[proposalIndex];
|
|
787
|
-
if (!proposalData) {
|
|
788
|
-
throw new Error(
|
|
789
|
-
`Proposal data not found for index ${proposalIndex}`,
|
|
790
|
-
);
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
const [
|
|
794
|
-
proposer,
|
|
795
|
-
_voteSnapshotTimestamp,
|
|
796
|
-
votingStartTime,
|
|
797
|
-
votingEndTime,
|
|
798
|
-
crossChainVoteCollectionEndTimestamp,
|
|
799
|
-
voteSnapshotBlock,
|
|
800
|
-
proposalForVotes,
|
|
801
|
-
proposalAgainstVotes,
|
|
802
|
-
proposalAbstainVotes,
|
|
803
|
-
proposalTotalVotes,
|
|
804
|
-
canceled,
|
|
805
|
-
executed,
|
|
806
|
-
] = proposalData;
|
|
807
|
-
|
|
808
|
-
const multichainState = (
|
|
809
|
-
MultichainProposalStateMapping as { [key: number]: ProposalState }
|
|
810
|
-
)[state]!;
|
|
811
|
-
|
|
812
|
-
const proposal: Proposal = {
|
|
813
|
-
chainId: params.environment.chainId,
|
|
814
|
-
id,
|
|
815
|
-
proposalId: Number(xcId),
|
|
816
|
-
proposer,
|
|
817
|
-
eta: Number(crossChainVoteCollectionEndTimestamp),
|
|
818
|
-
startTimestamp: Number(votingStartTime),
|
|
819
|
-
endTimestamp: Number(votingEndTime),
|
|
820
|
-
startBlock: Number(voteSnapshotBlock),
|
|
821
|
-
forVotes: new Amount(proposalForVotes + votes.forVotes, 18),
|
|
822
|
-
againstVotes: new Amount(
|
|
823
|
-
proposalAgainstVotes + votes.againstVotes,
|
|
824
|
-
18,
|
|
825
|
-
),
|
|
826
|
-
abstainVotes: new Amount(
|
|
827
|
-
proposalAbstainVotes + votes.abstainVotes,
|
|
828
|
-
18,
|
|
829
|
-
),
|
|
830
|
-
totalVotes: new Amount(proposalTotalVotes + votes.totalVotes, 18),
|
|
831
|
-
canceled,
|
|
832
|
-
executed,
|
|
833
|
-
quorum: new Amount(xcQuorum, 18),
|
|
834
|
-
state: multichainState,
|
|
835
|
-
multichain: {
|
|
836
|
-
id: Number(xcId),
|
|
837
|
-
votesCollected,
|
|
838
|
-
},
|
|
839
|
-
};
|
|
840
|
-
|
|
841
|
-
return proposal;
|
|
842
|
-
});
|
|
843
|
-
|
|
844
|
-
return proposals;
|
|
845
|
-
} else {
|
|
846
|
-
return [];
|
|
847
|
-
}
|
|
848
|
-
} else {
|
|
849
|
-
return [];
|
|
850
|
-
}
|
|
851
|
-
} catch (error) {
|
|
852
|
-
console.warn(
|
|
853
|
-
`[getCrossChainProposalData] RPC failed for chain ${params.environment.chainId}:`,
|
|
854
|
-
error,
|
|
855
|
-
);
|
|
856
|
-
params.environment.onError?.(error, {
|
|
857
|
-
source: "governance-proposals",
|
|
858
|
-
chainId: params.environment.chainId,
|
|
859
|
-
});
|
|
860
|
-
return [];
|
|
861
|
-
}
|
|
862
|
-
};
|
|
863
|
-
|
|
864
|
-
export const appendProposalExtendedData = (
|
|
865
|
-
proposals: Proposal[],
|
|
866
|
-
extendedDatas: PonderExtendedProposalData[],
|
|
867
|
-
) => {
|
|
868
|
-
proposals.forEach((proposal) => {
|
|
869
|
-
const extendedData = extendedDatas.find(
|
|
870
|
-
(item) => item.id === proposal.proposalId,
|
|
871
|
-
);
|
|
872
|
-
|
|
873
|
-
if (extendedData) {
|
|
874
|
-
proposal.title = extendedData.title;
|
|
875
|
-
proposal.calldatas = extendedData.calldatas;
|
|
876
|
-
proposal.description = extendedData.description;
|
|
877
|
-
proposal.signatures = extendedData.signatures;
|
|
878
|
-
proposal.stateChanges = extendedData.stateChanges.map((change) => ({
|
|
879
|
-
blockNumber: change.blockNumber,
|
|
880
|
-
transactionHash: change.transactionHash,
|
|
881
|
-
state: change.state,
|
|
882
|
-
chainId: proposal.chainId,
|
|
883
|
-
}));
|
|
884
|
-
proposal.subtitle = extendedData.subtitle;
|
|
885
|
-
proposal.targets = extendedData.targets;
|
|
886
|
-
}
|
|
887
|
-
});
|
|
888
|
-
};
|
|
889
|
-
|
|
890
|
-
export const getExtendedProposalData = async (params: {
|
|
891
|
-
environment: Environment;
|
|
892
|
-
id?: number;
|
|
893
|
-
}): Promise<PonderExtendedProposalData[]> => {
|
|
894
|
-
const result: PonderExtendedProposalData[] = [];
|
|
895
|
-
let lastId = -1;
|
|
896
|
-
let shouldContinue = true;
|
|
897
|
-
const MAX_PAGES = 100;
|
|
898
|
-
let page = 0;
|
|
899
|
-
|
|
900
|
-
try {
|
|
901
|
-
while (shouldContinue && page < MAX_PAGES) {
|
|
902
|
-
page++;
|
|
903
|
-
const response = await postWithRetry<{
|
|
904
|
-
data: {
|
|
905
|
-
proposals: {
|
|
906
|
-
items: {
|
|
907
|
-
proposalId: number;
|
|
908
|
-
description: string;
|
|
909
|
-
targets: string[];
|
|
910
|
-
calldatas: string[];
|
|
911
|
-
signatures: string[];
|
|
912
|
-
stateChanges: {
|
|
913
|
-
items: {
|
|
914
|
-
txnHash: string;
|
|
915
|
-
blockNumber: number;
|
|
916
|
-
newState: string;
|
|
917
|
-
}[];
|
|
918
|
-
};
|
|
919
|
-
}[];
|
|
920
|
-
};
|
|
921
|
-
};
|
|
922
|
-
}>("https://ponder-eu2.moonwell.fi", {
|
|
923
|
-
query: `
|
|
924
|
-
query {
|
|
925
|
-
proposals(
|
|
926
|
-
limit: 1000,
|
|
927
|
-
orderDirection: "desc",
|
|
928
|
-
orderBy: "proposalId",
|
|
929
|
-
where: {
|
|
930
|
-
chainId: ${params.environment.chainId}
|
|
931
|
-
${params.id ? `, proposalId: ${params.id}` : lastId >= 0 ? `, proposalId_lt: ${lastId}` : ""}
|
|
932
|
-
}
|
|
933
|
-
) {
|
|
934
|
-
items {
|
|
935
|
-
id
|
|
936
|
-
proposalId
|
|
937
|
-
description
|
|
938
|
-
targets
|
|
939
|
-
calldatas
|
|
940
|
-
signatures
|
|
941
|
-
stateChanges(orderBy: "blockNumber") {
|
|
942
|
-
items {
|
|
943
|
-
txnHash
|
|
944
|
-
blockNumber
|
|
945
|
-
newState
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
`,
|
|
952
|
-
});
|
|
953
|
-
|
|
954
|
-
if (response.status === 200 && response.data?.data?.proposals) {
|
|
955
|
-
const proposals = response.data.data.proposals.items.map((item) => {
|
|
956
|
-
const extendedProposalData: PonderExtendedProposalData = {
|
|
957
|
-
id: item.proposalId,
|
|
958
|
-
title: `Proposal #${item.proposalId}`,
|
|
959
|
-
subtitle: extractProposalSubtitle(item.description),
|
|
960
|
-
description: item.description,
|
|
961
|
-
calldatas: item.calldatas,
|
|
962
|
-
signatures: item.signatures,
|
|
963
|
-
stateChanges: item.stateChanges.items.map((change) => {
|
|
964
|
-
return {
|
|
965
|
-
blockNumber: change.blockNumber,
|
|
966
|
-
state: change.newState,
|
|
967
|
-
transactionHash: change.txnHash,
|
|
968
|
-
};
|
|
969
|
-
}),
|
|
970
|
-
targets: item.targets,
|
|
971
|
-
};
|
|
972
|
-
|
|
973
|
-
return extendedProposalData;
|
|
974
|
-
});
|
|
975
|
-
|
|
976
|
-
if (proposals.length < 1000 || proposals.length === 0) {
|
|
977
|
-
shouldContinue = false;
|
|
978
|
-
} else {
|
|
979
|
-
lastId = last(proposals)!.id;
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
result.push(...proposals);
|
|
983
|
-
} else {
|
|
984
|
-
shouldContinue = false;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
} catch (error) {
|
|
988
|
-
console.warn(
|
|
989
|
-
`[getExtendedProposalData] Ponder failed for chain ${params.environment.chainId}:`,
|
|
990
|
-
error,
|
|
991
|
-
);
|
|
992
|
-
params.environment.onError?.(error, {
|
|
993
|
-
source: "governance-proposals",
|
|
994
|
-
chainId: params.environment.chainId,
|
|
995
|
-
});
|
|
996
|
-
return result;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
return result;
|
|
1000
|
-
};
|
|
@@ -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
|
-
}
|