@moonwell-fi/moonwell-sdk 0.19.1 → 0.20.1

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 (55) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/_cjs/actions/governance/getUserVotingPowers.js +15 -6
  3. package/_cjs/actions/governance/getUserVotingPowers.js.map +1 -1
  4. package/_cjs/actions/governance/proposals/common.js +15 -5
  5. package/_cjs/actions/governance/proposals/common.js.map +1 -1
  6. package/_cjs/actions/governance/proposals/getProposal.js +1 -1
  7. package/_cjs/actions/governance/proposals/getProposal.js.map +1 -1
  8. package/_cjs/actions/governance/proposals/getProposals.js +1 -1
  9. package/_cjs/actions/governance/proposals/getProposals.js.map +1 -1
  10. package/_cjs/actions/morpho/markets/common.js +25 -16
  11. package/_cjs/actions/morpho/markets/common.js.map +1 -1
  12. package/_cjs/actions/morpho/utils/graphql.js +4 -12
  13. package/_cjs/actions/morpho/utils/graphql.js.map +1 -1
  14. package/_cjs/actions/morpho/vaults/common.js +6 -24
  15. package/_cjs/actions/morpho/vaults/common.js.map +1 -1
  16. package/_cjs/common/getBlockNumberAtTimestamp.js +12 -2
  17. package/_cjs/common/getBlockNumberAtTimestamp.js.map +1 -1
  18. package/_cjs/errors/version.js +1 -1
  19. package/_esm/actions/governance/getUserVotingPowers.js +22 -6
  20. package/_esm/actions/governance/getUserVotingPowers.js.map +1 -1
  21. package/_esm/actions/governance/proposals/common.js +59 -19
  22. package/_esm/actions/governance/proposals/common.js.map +1 -1
  23. package/_esm/actions/governance/proposals/getProposal.js +6 -2
  24. package/_esm/actions/governance/proposals/getProposal.js.map +1 -1
  25. package/_esm/actions/governance/proposals/getProposals.js +5 -2
  26. package/_esm/actions/governance/proposals/getProposals.js.map +1 -1
  27. package/_esm/actions/morpho/markets/common.js +31 -19
  28. package/_esm/actions/morpho/markets/common.js.map +1 -1
  29. package/_esm/actions/morpho/utils/graphql.js +4 -12
  30. package/_esm/actions/morpho/utils/graphql.js.map +1 -1
  31. package/_esm/actions/morpho/vaults/common.js +9 -24
  32. package/_esm/actions/morpho/vaults/common.js.map +1 -1
  33. package/_esm/common/getBlockNumberAtTimestamp.js +36 -8
  34. package/_esm/common/getBlockNumberAtTimestamp.js.map +1 -1
  35. package/_esm/errors/version.js +1 -1
  36. package/_types/actions/governance/getUserVotingPowers.d.ts.map +1 -1
  37. package/_types/actions/governance/proposals/common.d.ts +48 -12
  38. package/_types/actions/governance/proposals/common.d.ts.map +1 -1
  39. package/_types/actions/governance/proposals/getProposal.d.ts.map +1 -1
  40. package/_types/actions/governance/proposals/getProposals.d.ts.map +1 -1
  41. package/_types/actions/morpho/utils/graphql.d.ts.map +1 -1
  42. package/_types/actions/morpho/vaults/common.d.ts.map +1 -1
  43. package/_types/common/getBlockNumberAtTimestamp.d.ts +18 -3
  44. package/_types/common/getBlockNumberAtTimestamp.d.ts.map +1 -1
  45. package/_types/errors/version.d.ts +1 -1
  46. package/actions/governance/getUserVotingPowers.ts +30 -15
  47. package/actions/governance/proposals/common.ts +77 -21
  48. package/actions/governance/proposals/getProposal.ts +5 -2
  49. package/actions/governance/proposals/getProposals.ts +4 -2
  50. package/actions/morpho/markets/common.ts +36 -28
  51. package/actions/morpho/utils/graphql.ts +10 -18
  52. package/actions/morpho/vaults/common.ts +11 -38
  53. package/common/getBlockNumberAtTimestamp.ts +36 -8
  54. package/errors/version.ts +1 -1
  55. package/package.json +1 -1
@@ -1,15 +1,31 @@
1
1
  /**
2
- * Safety cap on interpolation iterations. With near-linear `ts(block)` the search
3
- * converges in ~3–5 reads; 8 leaves headroom for chains with variable block times
4
- * (e.g. Moonbeam) without unbounded RPC fan-out on pathological inputs.
2
+ * Cap on interpolation iterations before falling back to binary search. With
3
+ * near-linear `ts(block)` the interpolation phase converges in ~3–5 reads.
4
+ * On chains whose block time changed over their history the projection can
5
+ * fail to converge at all — see the binary completion phase below.
5
6
  */
6
- const MAX_ITERATIONS = 8;
7
+ const MAX_INTERPOLATION_ITERATIONS = 8;
7
8
  /**
8
9
  * Find the block number on a chain whose timestamp is the latest one ≤ the target unix timestamp.
9
10
  *
10
- * Uses interpolation search anchored on the latest block and block 1: each iteration
11
- * narrows the range by reading one block and projecting the target via the slope of the
12
- * remaining range. Converges in ~3–5 RPC calls even on chains with variable block times.
11
+ * Two phases:
12
+ *
13
+ * 1. Interpolation search anchored on the latest block and block 1: each iteration
14
+ * narrows the range by reading one block and projecting the target via the slope
15
+ * of the remaining range. Converges in ~3–5 RPC calls on chains with a roughly
16
+ * constant block time.
17
+ * 2. Binary-search completion: if interpolation hasn't converged after
18
+ * `MAX_INTERPOLATION_ITERATIONS`, finish with plain bisection — guaranteed
19
+ * convergence in ~log2(remaining range) reads.
20
+ *
21
+ * The completion phase is load-bearing, not defensive: on Moonbeam the block time
22
+ * changed ~12s → ~6s (async backing), so the interpolated projection — whose slope
23
+ * is the all-history average — lands after the target on every probe. Only the
24
+ * upper bound moves, the lower bound never leaves block 1, and the previous
25
+ * implementation silently returned that unconverged bound. Voting-power reads then
26
+ * executed against a block years before the views contract existed and reverted
27
+ * (governance proposal 171 incident, June 2026). An unconverged bound must never
28
+ * be returned.
13
29
  *
14
30
  * Assumes block 1 exists on the chain — true for every EVM chain Moonwell supports.
15
31
  *
@@ -25,11 +41,12 @@ export async function getBlockNumberAtTimestamp(publicClient, targetTimestamp) {
25
41
  const first = await publicClient.getBlock({ blockNumber: 1n });
26
42
  if (targetTimestamp <= first.timestamp)
27
43
  return first.number;
44
+ // Invariant throughout: ts(lo) <= targetTimestamp < ts(hi).
28
45
  let lo = first.number;
29
46
  let loTs = first.timestamp;
30
47
  let hi = latest.number;
31
48
  let hiTs = latest.timestamp;
32
- for (let i = 0; i < MAX_ITERATIONS; i += 1) {
49
+ for (let i = 0; i < MAX_INTERPOLATION_ITERATIONS; i += 1) {
33
50
  if (hi - lo <= 1n)
34
51
  break;
35
52
  const tsRange = hiTs - loTs;
@@ -51,6 +68,17 @@ export async function getBlockNumberAtTimestamp(publicClient, targetTimestamp) {
51
68
  hiTs = block.timestamp;
52
69
  }
53
70
  }
71
+ // Binary completion: never return an unconverged bound.
72
+ while (hi - lo > 1n) {
73
+ const mid = (lo + hi) / 2n;
74
+ const block = await publicClient.getBlock({ blockNumber: mid });
75
+ if (block.timestamp <= targetTimestamp) {
76
+ lo = mid;
77
+ }
78
+ else {
79
+ hi = mid;
80
+ }
81
+ }
54
82
  return lo;
55
83
  }
56
84
  //# sourceMappingURL=getBlockNumberAtTimestamp.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getBlockNumberAtTimestamp.js","sourceRoot":"","sources":["../../common/getBlockNumberAtTimestamp.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,YAA0B,EAC1B,eAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnE,IAAI,eAAe,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IAC9D,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IAE/C,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/D,IAAI,eAAe,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAE5D,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;IACtB,IAAI,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;IAC3B,IAAI,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IACvB,IAAI,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;YAAE,MAAM;QACzB,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;QAC5B,IAAI,OAAO,IAAI,EAAE;YAAE,MAAM;QAEzB,MAAM,MAAM,GAAG,CAAC,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC;QAChE,IAAI,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC;QACtB,IAAI,GAAG,IAAI,EAAE;YAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC;QAC7B,IAAI,GAAG,IAAI,EAAE;YAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC;QAE7B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;QAChE,IAAI,KAAK,CAAC,SAAS,IAAI,eAAe,EAAE,CAAC;YACvC,EAAE,GAAG,GAAG,CAAC;YACT,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,GAAG,CAAC;YACT,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
1
+ {"version":3,"file":"getBlockNumberAtTimestamp.js","sourceRoot":"","sources":["../../common/getBlockNumberAtTimestamp.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,YAA0B,EAC1B,eAAuB;IAEvB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnE,IAAI,eAAe,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IAC9D,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IAE/C,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/D,IAAI,eAAe,IAAI,KAAK,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC,MAAM,CAAC;IAE5D,4DAA4D;IAC5D,IAAI,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;IACtB,IAAI,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;IAC3B,IAAI,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IACvB,IAAI,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,4BAA4B,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzD,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;YAAE,MAAM;QACzB,MAAM,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;QAC5B,IAAI,OAAO,IAAI,EAAE;YAAE,MAAM;QAEzB,MAAM,MAAM,GAAG,CAAC,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC;QAChE,IAAI,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC;QACtB,IAAI,GAAG,IAAI,EAAE;YAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC;QAC7B,IAAI,GAAG,IAAI,EAAE;YAAE,GAAG,GAAG,EAAE,GAAG,EAAE,CAAC;QAE7B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;QAChE,IAAI,KAAK,CAAC,SAAS,IAAI,eAAe,EAAE,CAAC;YACvC,EAAE,GAAG,GAAG,CAAC;YACT,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,GAAG,CAAC;YACT,IAAI,GAAG,KAAK,CAAC,SAAS,CAAC;QACzB,CAAC;IACH,CAAC;IAED,wDAAwD;IACxD,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;QAChE,IAAI,KAAK,CAAC,SAAS,IAAI,eAAe,EAAE,CAAC;YACvC,EAAE,GAAG,GAAG,CAAC;QACX,CAAC;aAAM,CAAC;YACN,EAAE,GAAG,GAAG,CAAC;QACX,CAAC;IACH,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -1,2 +1,2 @@
1
- export const version = '0.19.1';
1
+ export const version = '0.20.1';
2
2
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getUserVotingPowers.d.ts","sourceRoot":"","sources":["../../../actions/governance/getUserVotingPowers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAe,MAAM,MAAM,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAM3E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAIxE,MAAM,MAAM,6BAA6B,CACvC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,IAC/B,4BAA4B,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG;IACxD,uBAAuB;IACvB,eAAe,EAAE,eAAe,CAAC;IAEjC,kBAAkB;IAClB,WAAW,EAAE,OAAO,CAAC;IAErB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAExE,wBAAsB,mBAAmB,CACvC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,EAEjC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,6BAA6B,CAAC,YAAY,EAAE,OAAO,CAAC,GACzD,6BAA6B,CAwI/B"}
1
+ {"version":3,"file":"getUserVotingPowers.d.ts","sourceRoot":"","sources":["../../../actions/governance/getUserVotingPowers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAe,MAAM,MAAM,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAM3E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAIxE,MAAM,MAAM,6BAA6B,CACvC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,IAC/B,4BAA4B,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG;IACxD,uBAAuB;IACvB,eAAe,EAAE,eAAe,CAAC;IAEjC,kBAAkB;IAClB,WAAW,EAAE,OAAO,CAAC;IAErB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;AAExE,wBAAsB,mBAAmB,CACvC,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,EAEjC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,6BAA6B,CAAC,YAAY,EAAE,OAAO,CAAC,GACzD,6BAA6B,CAuJ/B"}
@@ -22,22 +22,51 @@ type PonderExtendedProposalData = {
22
22
  */
23
23
  export declare const extractProposalSubtitle: (input: string) => string;
24
24
  /**
25
- * Detects if a proposal is a multichain proposal by checking whether any of
26
- * its targets is a Wormhole Core Bridge on a known multichain-governance hub
27
- * (Moonbeam or Ethereum). Bridges from both hubs are checked, so the result
28
- * is correct regardless of which chain the proposal was created on.
25
+ * Detects whether a proposal SENDS a cross-chain message, by checking whether
26
+ * any of its targets is a Wormhole Core Bridge on a known multichain-governance
27
+ * hub (Moonbeam or Ethereum).
28
+ *
29
+ * WARNING: this is NOT sufficient to classify a proposal as belonging to the
30
+ * multichain governor. Hub-local proposals (created on the Ethereum
31
+ * MultichainGovernor with only same-chain targets) never message a bridge and
32
+ * return `false` here — misclassifying them broke voting on proposal 171
33
+ * (June 2026). Use `classifyProposalMultichain` for governor classification.
29
34
  */
30
35
  export declare const isMultichainProposal: (targets?: string[]) => boolean;
31
36
  /**
32
- * Routes a proposal to the multichain governor when:
33
- * - its targets include the Wormhole bridge (legacy detection), OR
34
- * - its proposalId is past the legacy Artemis governor's `proposalCount`,
35
- * which means it could only have been created on the multichain governor
36
- * (proposals migrated to the multichain governor after the cutoff but
37
- * can have local-only targets, e.g. Moonbeam-internal contract calls).
37
+ * True when `chainId`'s environment is a multichain-governance hub with no
38
+ * legacy governor lineage (Ethereum: `multichainGovernor` only, no Artemis
39
+ * predecessor). On such a chain every proposal belongs to the multichain
40
+ * governor by construction what the proposal targets is irrelevant.
41
+ */
42
+ export declare const isMultichainHomeChain: (chainId: number) => boolean;
43
+ /**
44
+ * Canonical multichain classification for a proposal — the single entry point
45
+ * used by `getProposal`, `getProposals`, and on-chain-data routing so the
46
+ * paths cannot drift. A proposal belongs to the multichain governor when:
47
+ * 1. it is homed on a hub chain with no legacy governor (every Ethereum-hub
48
+ * proposal, including hub-local ones with no bridge target), OR
49
+ * 2. its targets include a Wormhole Core Bridge (legacy detection), OR
50
+ * 3. its proposalId is past the legacy Artemis governor's `proposalCount`
51
+ * (Moonbeam-hub-era proposals with local-only targets), OR
52
+ * 4. the Artemis cutoff is unknown because the read failed (`undefined`) — we
53
+ * bias to multichain rather than risk routing a live proposal to the dead
54
+ * Artemis governor (the proposal-171 root cause, on Moonbeam).
38
55
  *
39
- * `legacyArtemisMaxId === 0` indicates the count read failed; in that case we
40
- * fall back to the targets-only heuristic.
56
+ * `legacyArtemisMaxId` is only meaningful for Moonbeam-homed proposals. Pass 0
57
+ * for chains with no legacy governor — the ID check is N/A and classification
58
+ * falls back to the home/bridge checks. Omit it or pass `undefined` when the
59
+ * count read failed so the unknown-cutoff bias above applies. (No `= 0` default:
60
+ * that would coerce an explicit `undefined` back to 0 and defeat the bias.)
61
+ */
62
+ export declare const classifyProposalMultichain: (proposal: {
63
+ targets?: string[];
64
+ proposalId: number;
65
+ chainId: number;
66
+ }, legacyArtemisMaxId?: number) => boolean;
67
+ /**
68
+ * @deprecated Use `classifyProposalMultichain` — this variant misses hub-homed
69
+ * proposals when the Artemis count is unavailable. Kept for compatibility.
41
70
  */
42
71
  export declare const isMultichainAware: (proposal: {
43
72
  targets?: string[];
@@ -82,6 +111,13 @@ export type ProposalOnChainData = {
82
111
  eta: number;
83
112
  votesCollected: boolean;
84
113
  quorum: bigint;
114
+ /**
115
+ * Canonical multichain classification, computed here with the caller env's
116
+ * Artemis cutoff. Returned so `getProposal`/`getProposals` consume it instead
117
+ * of re-running `classifyProposalMultichain` (which, without the cutoff,
118
+ * misses Moonbeam-homed local-target proposals and drifts from this routing).
119
+ */
120
+ isMultichain: boolean;
85
121
  };
86
122
  /**
87
123
  * Reads the multichain governor's quorum on every chain that holds an active
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../actions/governance/proposals/common.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,OAAO,EAGL,KAAK,QAAQ,EACb,aAAa,EACd,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D,eAAO,MAAM,iBAAiB,+CAA+C,CAAC;AAY9E,KAAK,0BAA0B,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,YAAY,EAAE;QACZ,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAAI,OAAO,MAAM,KAAG,MAoDvD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,MAAM,EAAE,KAAG,OAEnD,CAAC;AAER;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC5B,UAAU;IAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,EACpD,oBAAoB,MAAM,KACzB,OAEmE,CAAC;AAEvE,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,KAAK,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,eAAe,EAAE,MAAM,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,GACrC,WAAW,oBAAoB,EAC/B,aAAa,WAAW,EACxB,KAAK,MAAM,KACV,aAWF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAChC,aAAa,WAAW,KACvB,oBAkDF,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,GAAG,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAoCF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,MAAM,KACd,WAAW,GAAG,SAGd,CAAC;AAEJ,eAAO,MAAM,qBAAqB,GAChC,cAAc,WAAW,EAAE,EAC3B,uBAAuB,WAAW,KACjC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA6B7B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,cAAc,WAAW,EAAE,EAC3B,uBAAuB,WAAW,EAClC,UAAU;IAAE,iBAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KACpD,OAAO,CAAC,mBAAmB,EAAE,CAwK/B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAU,QAAQ;IAC5C,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,wBAoGA,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,GAAU,QAAQ;IACtD,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,wBA2LA,CAAC;AAEF,eAAO,MAAM,0BAA0B,GACrC,WAAW,QAAQ,EAAE,EACrB,eAAe,0BAA0B,EAAE,SAsB5C,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAU,QAAQ;IACpD,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,KAAG,OAAO,CAAC,0BAA0B,EAAE,CA2GvC,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../../actions/governance/proposals/common.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"getProposal.d.ts","sourceRoot":"","sources":["../../../../actions/governance/proposals/getProposal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,KAAK,QAAQ,EAAiB,MAAM,4BAA4B,CAAC;AAmB1E,MAAM,MAAM,qBAAqB,CAC/B,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,IAC/B,oBAAoB,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;AAElE,wBAAsB,WAAW,CAC/B,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,EAEjC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,qBAAqB,CAAC,YAAY,EAAE,OAAO,CAAC,GACjD,qBAAqB,CAuCvB"}
1
+ {"version":3,"file":"getProposal.d.ts","sourceRoot":"","sources":["../../../../actions/governance/proposals/getProposal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAE9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAE,KAAK,EAAe,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,KAAK,QAAQ,EAAiB,MAAM,4BAA4B,CAAC;AAkB1E,MAAM,MAAM,qBAAqB,CAC/B,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,IAC/B,oBAAoB,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;AAElE,wBAAsB,WAAW,CAC/B,YAAY,EACZ,OAAO,SAAS,KAAK,GAAG,SAAS,EAEjC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,qBAAqB,CAAC,YAAY,EAAE,OAAO,CAAC,GACjD,qBAAqB,CAuCvB"}
@@ -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,EAAE,KAAK,QAAQ,EAAiB,MAAM,4BAA4B,CAAC;AAc1E,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
+ {"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;AAa1E,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":"graphql.d.ts","sourceRoot":"","sources":["../../../../actions/morpho/utils/graphql.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAE9E,wBAAsB,UAAU,CAAC,CAAC,EAChC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EACtB,SAAS,CAAC,EAAE,GAAG,0BA8BhB;AAED,wBAAsB,aAAa,CACjC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAoE/C"}
1
+ {"version":3,"file":"graphql.d.ts","sourceRoot":"","sources":["../../../../actions/morpho/utils/graphql.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAE9E,wBAAsB,UAAU,CAAC,CAAC,EAChC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EACtB,SAAS,CAAC,EAAE,GAAG,0BA0BhB;AAED,wBAAsB,aAAa,CACjC,WAAW,EAAE,WAAW,EACxB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAgE/C"}
@@ -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;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
+ {"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,CAmMzC"}
@@ -2,9 +2,24 @@ import type { PublicClient } from "viem";
2
2
  /**
3
3
  * Find the block number on a chain whose timestamp is the latest one ≤ the target unix timestamp.
4
4
  *
5
- * Uses interpolation search anchored on the latest block and block 1: each iteration
6
- * narrows the range by reading one block and projecting the target via the slope of the
7
- * remaining range. Converges in ~3–5 RPC calls even on chains with variable block times.
5
+ * Two phases:
6
+ *
7
+ * 1. Interpolation search anchored on the latest block and block 1: each iteration
8
+ * narrows the range by reading one block and projecting the target via the slope
9
+ * of the remaining range. Converges in ~3–5 RPC calls on chains with a roughly
10
+ * constant block time.
11
+ * 2. Binary-search completion: if interpolation hasn't converged after
12
+ * `MAX_INTERPOLATION_ITERATIONS`, finish with plain bisection — guaranteed
13
+ * convergence in ~log2(remaining range) reads.
14
+ *
15
+ * The completion phase is load-bearing, not defensive: on Moonbeam the block time
16
+ * changed ~12s → ~6s (async backing), so the interpolated projection — whose slope
17
+ * is the all-history average — lands after the target on every probe. Only the
18
+ * upper bound moves, the lower bound never leaves block 1, and the previous
19
+ * implementation silently returned that unconverged bound. Voting-power reads then
20
+ * executed against a block years before the views contract existed and reverted
21
+ * (governance proposal 171 incident, June 2026). An unconverged bound must never
22
+ * be returned.
8
23
  *
9
24
  * Assumes block 1 exists on the chain — true for every EVM chain Moonwell supports.
10
25
  *
@@ -1 +1 @@
1
- {"version":3,"file":"getBlockNumberAtTimestamp.d.ts","sourceRoot":"","sources":["../../common/getBlockNumberAtTimestamp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AASzC;;;;;;;;;;;GAWG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,YAAY,EAC1B,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,CAAC,CAkCjB"}
1
+ {"version":3,"file":"getBlockNumberAtTimestamp.d.ts","sourceRoot":"","sources":["../../common/getBlockNumberAtTimestamp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAUzC;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,YAAY,EAC1B,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
@@ -1,2 +1,2 @@
1
- export declare const version = "0.19.1";
1
+ export declare const version = "0.20.1";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -72,23 +72,22 @@ export async function getUserVotingPowers<
72
72
  return [{ env, views }];
73
73
  });
74
74
 
75
- const perChainBlockNumbers =
76
- snapshotTimestamp !== undefined
77
- ? await Promise.all(
78
- tokenEnvironments.map(({ env }) =>
79
- getBlockNumberAtTimestamp(
75
+ // Per-chain isolation: one chain's failing block resolution or views read
76
+ // must degrade ONLY that chain, never the whole call. The previous
77
+ // implementation wrapped everything in a single Promise.all, so a Moonbeam
78
+ // revert erased voting power on every chain at once — which hid the vote
79
+ // buttons for all users during the proposal-171 incident (June 2026).
80
+ // Failed chains are reported through `env.onError` and omitted from the
81
+ // result; consumers see partial data instead of a rejection.
82
+ const settled = await Promise.allSettled(
83
+ tokenEnvironments.map(async ({ env, views }) => {
84
+ const blockForChain =
85
+ snapshotTimestamp !== undefined
86
+ ? await getBlockNumberAtTimestamp(
80
87
  env.publicClient,
81
88
  BigInt(snapshotTimestamp),
82
- ),
83
- ),
84
- )
85
- : undefined;
86
-
87
- const resolvedVotingPowers = await Promise.all(
88
- tokenEnvironments.map(async ({ env, views }, index) => {
89
- const blockForChain = perChainBlockNumbers
90
- ? perChainBlockNumbers[index]
91
- : blockNumber;
89
+ )
90
+ : blockNumber;
92
91
  const votingPowers = await views.read.getUserVotingPower([userAddress], {
93
92
  blockNumber: blockForChain,
94
93
  });
@@ -96,6 +95,22 @@ export async function getUserVotingPowers<
96
95
  }),
97
96
  );
98
97
 
98
+ const resolvedVotingPowers = settled.flatMap((result, index) => {
99
+ if (result.status === "fulfilled") {
100
+ return [result.value];
101
+ }
102
+ const env = tokenEnvironments[index]?.env;
103
+ console.warn(
104
+ `[moonwell-sdk] getUserVotingPowers: skipping chainId=${env?.chainId} — voting-power read failed; returning remaining chains.`,
105
+ result.reason,
106
+ );
107
+ env?.onError?.(result.reason, {
108
+ source: "getUserVotingPowers",
109
+ chainId: env.chainId,
110
+ });
111
+ return [];
112
+ });
113
+
99
114
  return resolvedVotingPowers.map(({ env: environment, votingPowers }) => {
100
115
  const { tokenVotes } = votingPowers;
101
116
 
@@ -100,25 +100,62 @@ export const extractProposalSubtitle = (input: string): string => {
100
100
  };
101
101
 
102
102
  /**
103
- * Detects if a proposal is a multichain proposal by checking whether any of
104
- * its targets is a Wormhole Core Bridge on a known multichain-governance hub
105
- * (Moonbeam or Ethereum). Bridges from both hubs are checked, so the result
106
- * is correct regardless of which chain the proposal was created on.
103
+ * Detects whether a proposal SENDS a cross-chain message, by checking whether
104
+ * any of its targets is a Wormhole Core Bridge on a known multichain-governance
105
+ * hub (Moonbeam or Ethereum).
106
+ *
107
+ * WARNING: this is NOT sufficient to classify a proposal as belonging to the
108
+ * multichain governor. Hub-local proposals (created on the Ethereum
109
+ * MultichainGovernor with only same-chain targets) never message a bridge and
110
+ * return `false` here — misclassifying them broke voting on proposal 171
111
+ * (June 2026). Use `classifyProposalMultichain` for governor classification.
107
112
  */
108
113
  export const isMultichainProposal = (targets?: string[]): boolean =>
109
114
  targets?.some((t) => MULTICHAIN_WORMHOLE_BRIDGES.has(t.toLowerCase())) ??
110
115
  false;
111
116
 
112
117
  /**
113
- * Routes a proposal to the multichain governor when:
114
- * - its targets include the Wormhole bridge (legacy detection), OR
115
- * - its proposalId is past the legacy Artemis governor's `proposalCount`,
116
- * which means it could only have been created on the multichain governor
117
- * (proposals migrated to the multichain governor after the cutoff but
118
- * can have local-only targets, e.g. Moonbeam-internal contract calls).
118
+ * True when `chainId`'s environment is a multichain-governance hub with no
119
+ * legacy governor lineage (Ethereum: `multichainGovernor` only, no Artemis
120
+ * predecessor). On such a chain every proposal belongs to the multichain
121
+ * governor by construction what the proposal targets is irrelevant.
122
+ */
123
+ export const isMultichainHomeChain = (chainId: number): boolean => {
124
+ const env = getEnvironmentByChainId(chainId);
125
+ return Boolean(env?.contracts.multichainGovernor && !env.contracts.governor);
126
+ };
127
+
128
+ /**
129
+ * Canonical multichain classification for a proposal — the single entry point
130
+ * used by `getProposal`, `getProposals`, and on-chain-data routing so the
131
+ * paths cannot drift. A proposal belongs to the multichain governor when:
132
+ * 1. it is homed on a hub chain with no legacy governor (every Ethereum-hub
133
+ * proposal, including hub-local ones with no bridge target), OR
134
+ * 2. its targets include a Wormhole Core Bridge (legacy detection), OR
135
+ * 3. its proposalId is past the legacy Artemis governor's `proposalCount`
136
+ * (Moonbeam-hub-era proposals with local-only targets), OR
137
+ * 4. the Artemis cutoff is unknown because the read failed (`undefined`) — we
138
+ * bias to multichain rather than risk routing a live proposal to the dead
139
+ * Artemis governor (the proposal-171 root cause, on Moonbeam).
119
140
  *
120
- * `legacyArtemisMaxId === 0` indicates the count read failed; in that case we
121
- * fall back to the targets-only heuristic.
141
+ * `legacyArtemisMaxId` is only meaningful for Moonbeam-homed proposals. Pass 0
142
+ * for chains with no legacy governor — the ID check is N/A and classification
143
+ * falls back to the home/bridge checks. Omit it or pass `undefined` when the
144
+ * count read failed so the unknown-cutoff bias above applies. (No `= 0` default:
145
+ * that would coerce an explicit `undefined` back to 0 and defeat the bias.)
146
+ */
147
+ export const classifyProposalMultichain = (
148
+ proposal: { targets?: string[]; proposalId: number; chainId: number },
149
+ legacyArtemisMaxId?: number,
150
+ ): boolean =>
151
+ isMultichainHomeChain(proposal.chainId) ||
152
+ isMultichainProposal(proposal.targets) ||
153
+ legacyArtemisMaxId === undefined ||
154
+ (legacyArtemisMaxId > 0 && proposal.proposalId > legacyArtemisMaxId);
155
+
156
+ /**
157
+ * @deprecated Use `classifyProposalMultichain` — this variant misses hub-homed
158
+ * proposals when the Artemis count is unavailable. Kept for compatibility.
122
159
  */
123
160
  export const isMultichainAware = (
124
161
  proposal: { targets?: string[]; proposalId: number },
@@ -236,6 +273,13 @@ export type ProposalOnChainData = {
236
273
  eta: number;
237
274
  votesCollected: boolean;
238
275
  quorum: bigint;
276
+ /**
277
+ * Canonical multichain classification, computed here with the caller env's
278
+ * Artemis cutoff. Returned so `getProposal`/`getProposals` consume it instead
279
+ * of re-running `classifyProposalMultichain` (which, without the cutoff,
280
+ * misses Moonbeam-homed local-target proposals and drifts from this routing).
281
+ */
282
+ isMultichain: boolean;
239
283
  };
240
284
 
241
285
  // Cached per chain: highest proposalId held by the legacy Artemis governor.
@@ -250,7 +294,7 @@ const legacyArtemisMaxIdCache = new Map<
250
294
 
251
295
  const getLegacyArtemisMaxId = async (
252
296
  governanceEnvironment: Environment,
253
- ): Promise<number> => {
297
+ ): Promise<number | undefined> => {
254
298
  const governor = governanceEnvironment.contracts.governor;
255
299
  if (!governor) return 0;
256
300
 
@@ -268,7 +312,13 @@ const getLegacyArtemisMaxId = async (
268
312
  return value;
269
313
  } catch (error) {
270
314
  console.warn("Failed to fetch legacy governor proposalCount:", error);
271
- return cached?.value ?? 0;
315
+ // A cold-cache read failure must NOT collapse to 0. On a dual-governor
316
+ // chain (Moonbeam) that would make a live multichain proposal with
317
+ // local-only targets look like a pre-cutoff legacy proposal and route its
318
+ // votes to the dead Artemis governor — the proposal-171 root cause. Return
319
+ // a stale cached cutoff if we have one, otherwise `undefined` (unknown) so
320
+ // `classifyProposalMultichain` biases to the multichain governor instead.
321
+ return cached?.value;
272
322
  }
273
323
  };
274
324
 
@@ -365,6 +415,17 @@ export const getProposalsOnChainData = async (
365
415
  : (options?.crossChainQuorums?.get(p.chainId) ?? 0n);
366
416
  const homeEnv = resolveHomeEnv(p.chainId);
367
417
 
418
+ // legacyArtemisMaxId is meaningful only for the caller's env — it's the
419
+ // Moonbeam Artemis cap; pass 0 for foreign envs. Hub-homed proposals
420
+ // (Ethereum multigov, no Artemis predecessor) classify as multichain
421
+ // regardless of targets via classifyProposalMultichain. Computed once
422
+ // here and returned on ProposalOnChainData so callers don't re-classify
423
+ // and drift (see getProposal/getProposals).
424
+ const isMultichain = classifyProposalMultichain(
425
+ p,
426
+ isLocal ? legacyArtemisMaxId : 0,
427
+ );
428
+
368
429
  if (!homeEnv) {
369
430
  const formatted = formatApiProposalData(p);
370
431
  return {
@@ -373,16 +434,10 @@ export const getProposalsOnChainData = async (
373
434
  eta: 0,
374
435
  votesCollected: false,
375
436
  quorum: proposalQuorum,
437
+ isMultichain,
376
438
  };
377
439
  }
378
440
 
379
- // legacyArtemisMaxId is meaningful only for the caller's env — it's the
380
- // Moonbeam Artemis cap. For foreign envs the targets-only heuristic is
381
- // the right check (Ethereum-hub multigov has no Artemis predecessor).
382
- const isMultichain = isLocal
383
- ? isMultichainAware(p, legacyArtemisMaxId)
384
- : isMultichainProposal(p.targets);
385
-
386
441
  const governorContract = isMultichain
387
442
  ? homeEnv.contracts.multichainGovernor
388
443
  : homeEnv.contracts.governor;
@@ -495,6 +550,7 @@ export const getProposalsOnChainData = async (
495
550
  eta,
496
551
  votesCollected,
497
552
  quorum: proposalQuorum,
553
+ isMultichain,
498
554
  };
499
555
  }),
500
556
  );
@@ -18,7 +18,6 @@ import {
18
18
  getExtendedProposalData,
19
19
  getProposalData,
20
20
  getProposalsOnChainData,
21
- isMultichainProposal,
22
21
  readCrossChainQuorums,
23
22
  } from "./common.js";
24
23
 
@@ -125,7 +124,11 @@ async function getMoonbeamProposal(
125
124
  { crossChainQuorums },
126
125
  );
127
126
  const onChainData = onChainDataList[0]!;
128
- const isMultichain = isMultichainProposal(apiProposal.targets);
127
+ // Single source of truth: getProposalsOnChainData already classified this
128
+ // proposal with the caller env's Artemis cutoff and used it to route the
129
+ // on-chain reads. Reusing it avoids the drift that left Moonbeam-homed
130
+ // local-target proposals (and hub-local Ethereum ones) without `multichain`.
131
+ const isMultichain = onChainData.isMultichain;
129
132
 
130
133
  const now = Math.floor(Date.now() / 1000);
131
134
  let proposalState = onChainData.state;
@@ -14,7 +14,6 @@ import {
14
14
  getExtendedProposalData,
15
15
  getProposalData,
16
16
  getProposalsOnChainData,
17
- isMultichainProposal,
18
17
  readCrossChainQuorums,
19
18
  } from "./common.js";
20
19
 
@@ -125,7 +124,10 @@ async function getMoonbeamProposals(
125
124
  const proposals: Proposal[] = apiProposals.map((apiProposal, index) => {
126
125
  const onChainData = onChainDataList[index]!;
127
126
  const formattedData = formatApiProposalData(apiProposal);
128
- const isMultichain = isMultichainProposal(apiProposal.targets);
127
+ // Single source of truth — see getProposal.ts. getProposalsOnChainData
128
+ // classified with the Artemis cutoff and routed the reads accordingly;
129
+ // re-classifying here without the cutoff would drift and drop `multichain`.
130
+ const isMultichain = onChainData.isMultichain;
129
131
 
130
132
  const now = Math.floor(Date.now() / 1000);
131
133
  let proposalState = onChainData.state;