UNPKG

@moonwell-fi/moonwell-sdk

Version:

TypeScript Interface for Moonwell

176 lines (154 loc) 4.99 kB
import { moonbeam, moonriver } from "viem/chains"; import type { MoonwellClient } from "../../../client/createMoonwellClient.js"; import { Amount, getEnvironmentFromArgs } from "../../../common/index.js"; import type { NetworkParameterType } from "../../../common/types.js"; import type { Chain, Environment } from "../../../environments/index.js"; import type { Proposal } from "../../../types/proposal.js"; import { fetchProposal } from "../governor-api-client.js"; import { appendProposalExtendedData, formatApiProposalData, getCrossChainProposalData, getExtendedProposalData, getProposalData, getProposalsOnChainData, isMultichainProposal, } from "./common.js"; export type GetProposalParameters< environments, network extends Chain | undefined, > = NetworkParameterType<environments, network> & { proposalId: number; }; export type GetProposalReturnType = Promise<Proposal | undefined>; export async function getProposal< environments, Network extends Chain | undefined, >( client: MoonwellClient, args: GetProposalParameters<environments, Network>, ): GetProposalReturnType { const { proposalId } = args; const environment = getEnvironmentFromArgs(client, args); if (!environment) { return undefined; } if ( environment.chainId !== moonbeam.id && environment.chainId !== moonriver.id ) { return undefined; } try { if (environment.chainId === moonbeam.id) { // Moonbeam: Use new Governor API return await getMoonbeamProposal(environment, proposalId); } else { // Moonriver: Use old Ponder approach return await getMoonriverProposal(environment, proposalId); } } catch (error) { console.error( `[getProposal] Error fetching proposal ${proposalId}:`, error, ); return undefined; } } /** * Fetch a single proposal for Moonbeam using the new Governor API */ async function getMoonbeamProposal( governanceEnvironment: Environment, proposalId: number, ): Promise<Proposal | undefined> { const apiProposalId = `${proposalId}`; const apiProposal = await fetchProposal(governanceEnvironment, apiProposalId); const formattedData = formatApiProposalData(apiProposal); const onChainDataList = await getProposalsOnChainData( [apiProposal], governanceEnvironment, ); const onChainData = onChainDataList[0]!; const isMultichain = isMultichainProposal(apiProposal.targets); let proposalState = onChainData.state; const now = Math.floor(Date.now() / 1000); if ( proposalState === 0 && now >= apiProposal.votingStartTime && now <= apiProposal.votingEndTime ) { proposalState = 1; // Active } if (formattedData.executed) { proposalState = 7; // ProposalState.Executed } else if ( isMultichain && onChainData.votesCollected && now > apiProposal.votingEndTime && proposalState < 5 ) { proposalState = 5; // ProposalState.Queued } const proposal: Proposal = { id: apiProposal.proposalId, chainId: apiProposal.chainId, proposalId: apiProposal.proposalId, proposer: apiProposal.proposer as `0x${string}`, eta: onChainData.eta, startTimestamp: apiProposal.votingStartTime, endTimestamp: apiProposal.votingEndTime, startBlock: Number(apiProposal.blockNumber), forVotes: formattedData.forVotes, againstVotes: formattedData.againstVotes, abstainVotes: formattedData.abstainVotes, totalVotes: formattedData.totalVotes, canceled: formattedData.canceled, executed: formattedData.executed, quorum: new Amount(onChainData.quorum, 18), state: proposalState, // Extended data title: formattedData.title, subtitle: formattedData.subtitle, description: apiProposal.description, targets: apiProposal.targets, calldatas: apiProposal.calldatas, signatures: [], stateChanges: formattedData.stateChanges, environment: governanceEnvironment, }; if (isMultichain) { proposal.multichain = { id: apiProposal.proposalId, votesCollected: onChainData.votesCollected, }; } return proposal; } /** * Fetch a single proposal for Moonriver using the old Ponder-based approach */ async function getMoonriverProposal( governanceEnvironment: Environment, proposalId: number, ): Promise<Proposal | undefined> { const [_proposals, _xcProposals, _extendedDatas] = await Promise.all([ getProposalData({ environment: governanceEnvironment, id: proposalId }), getCrossChainProposalData({ environment: governanceEnvironment, id: proposalId, }), getExtendedProposalData({ environment: governanceEnvironment, id: proposalId, }), ]); const proposals = [..._proposals, ..._xcProposals]; proposals.forEach((proposal) => { proposal.environment = governanceEnvironment; }); appendProposalExtendedData(proposals, _extendedDatas); return proposals.find( (p) => p.proposalId === proposalId || p.id === proposalId, ); }