000
@@ -113,7 +114,7 @@ const ContractDataGridSkeleton = () => {
<>
-
+
>
);
diff --git a/src/components/proposals-list/proposals-list.component.tsx b/src/components/proposals-list/proposals-list.component.tsx
index b71db5de..8486c5e9 100644
--- a/src/components/proposals-list/proposals-list.component.tsx
+++ b/src/components/proposals-list/proposals-list.component.tsx
@@ -1,13 +1,13 @@
"use client";
+import { Card, ProgressBar, Status } from "@/components/_shared";
+import useProposals from "@/lib/contracts/governor/useProposals";
+import { Proposal } from "@/lib/graphql/subgraph/generated/subgraph";
import NumbersService from "@/lib/helpers/numbers.service";
import StringService from "@/lib/helpers/string.service";
import BaseComponentProps from "@/lib/interfaces/base-component-props.interface";
-import { Card, ProgressBar, Status } from "@/components/_shared";
-import Link from "next/link";
import { stateToStatusColorMap } from "@/lib/interfaces/proposal.interface";
+import Link from "next/link";
import { formatUnits } from "viem";
-import useProposals from "@/lib/contracts/governor/useProposals";
-import { Proposal } from "@/lib/graphql/subgraph/generated/subgraph";
import { EmptyProposals } from "../_icons";
import { MentoIcon } from "../_icons";
diff --git a/src/components/votes-list/votes-list.component.tsx b/src/components/votes-list/votes-list.component.tsx
index 2b22dc91..8adce715 100644
--- a/src/components/votes-list/votes-list.component.tsx
+++ b/src/components/votes-list/votes-list.component.tsx
@@ -61,7 +61,6 @@ const getParticipantPercentage = (
if (totalVotes > 0n) {
const decimals = 8;
const accuracy = 10n ** BigInt(decimals);
-
const weightScaled = participant.weight * 100n;
const valueInRawBN = (weightScaled * accuracy) / totalVotes;
@@ -70,7 +69,7 @@ const getParticipantPercentage = (
if (formatted.includes(".")) {
const [integers, remainingDecimals] = formatted.split(".");
- return `${integers}.${remainingDecimals.substring(0, 2)}%`;
+ return `${integers}.${remainingDecimals.substring(0, 5)}%`;
} else {
return `${formatted}%`;
}
diff --git a/src/config/config.constants.ts b/src/config/config.constants.ts
index b1718ac4..d88179d9 100644
--- a/src/config/config.constants.ts
+++ b/src/config/config.constants.ts
@@ -17,3 +17,5 @@ export const getSubgraphApiName = (chainId: number | undefined) => {
if (!chainId || !isValidChainId(chainId)) return subgraphApiNames[0];
return subgraphApiNames[chainId];
};
+
+export const CELO_BLOCK_TIME = 5000; // 5 seconds
diff --git a/src/lib/contracts/governor/useProposal.ts b/src/lib/contracts/governor/useProposal.ts
index 85768c77..93855ad0 100644
--- a/src/lib/contracts/governor/useProposal.ts
+++ b/src/lib/contracts/governor/useProposal.ts
@@ -13,7 +13,7 @@ import { useEnsureChainId } from "@/lib/hooks/useEnsureChainId";
import { NetworkStatus } from "@apollo/client";
import { useEffect, useMemo } from "react";
import { useBlockNumber, useReadContract } from "wagmi";
-
+import { CELO_BLOCK_TIME } from "@/config/config.constants";
export const ProposalQueryKey = "proposal";
const useProposal = (proposalId: bigint) => {
@@ -50,7 +50,7 @@ const useProposal = (proposalId: bigint) => {
scopeKey: ProposalQueryKey,
chainId: ensuredChainId,
query: {
- refetchInterval: 5000,
+ refetchInterval: CELO_BLOCK_TIME,
enabled:
graphNetworkStatus === NetworkStatus.ready && graphProposals.length > 0,
},
diff --git a/src/lib/contracts/useTokens.ts b/src/lib/contracts/useTokens.ts
index 63655b99..1e91633c 100644
--- a/src/lib/contracts/useTokens.ts
+++ b/src/lib/contracts/useTokens.ts
@@ -6,6 +6,7 @@ import { erc20Abi } from "viem";
import { useQueryClient } from "@tanstack/react-query";
import { formatUnitsWithRadix } from "@/lib/helpers/numbers.service";
import { useEnsureChainId } from "@/lib/hooks/useEnsureChainId";
+import { CELO_BLOCK_TIME } from "@/config/config.constants";
export type TokenBalance = {
decimals: number;
@@ -155,7 +156,7 @@ export const useTokens = () => {
],
scopeKey: "token-hook",
query: {
- refetchInterval: 5000,
+ refetchInterval: CELO_BLOCK_TIME,
enabled: isConnected && !!address,
// initialData: [0n, 0n],
},
diff --git a/src/lib/graphql/subgraph/fragments/proposalFields.graphql b/src/lib/graphql/subgraph/fragments/proposalFields.graphql
index 540243c1..74886dd5 100644
--- a/src/lib/graphql/subgraph/fragments/proposalFields.graphql
+++ b/src/lib/graphql/subgraph/fragments/proposalFields.graphql
@@ -21,16 +21,22 @@ fragment ProposalFields on Proposal {
# Votes
votecast {
- timestamp
- voter {
- id
+ id
+ support{
+ weight
}
- support {
- support
+ receipt {
+ id
+ voter {
+ id
+ }
weight
+ support {
+ id
+ support
+ }
}
}
-
# Start & End Time
startBlock
endBlock
diff --git a/src/lib/graphql/subgraph/generated/subgraph.tsx b/src/lib/graphql/subgraph/generated/subgraph.tsx
index dec65ddc..88ca6125 100644
--- a/src/lib/graphql/subgraph/generated/subgraph.tsx
+++ b/src/lib/graphql/subgraph/generated/subgraph.tsx
@@ -7286,7 +7286,7 @@ export enum _SubgraphErrorPolicy_ {
Deny = 'deny'
}
-export type ProposalFieldsFragment = { __typename?: 'Proposal', proposalId: any, description: string, startBlock: any, endBlock: any, queued: boolean, canceled: boolean, executed: boolean, state: ProposalState, proposer: { __typename?: 'Account', id: any }, proposalCreated: Array<{ __typename?: 'ProposalCreated', timestamp: any }>, proposalQueued: Array<{ __typename?: 'ProposalQueued', eta: any }>, proposalExecuted: Array<{ __typename?: 'ProposalExecuted', transaction: { __typename?: 'Transaction', id: string, timestamp: any } }>, votecast: Array<{ __typename?: 'VoteCast', timestamp: any, voter: { __typename?: 'Account', id: any }, support: { __typename?: 'ProposalSupport', support: number, weight: any } }>, metadata: { __typename?: 'ProposalMetadata', title: string, description: string }, votes: { __typename?: 'ProposalVotes', total: any, for: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, against: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, abstain: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> } } };
+export type ProposalFieldsFragment = { __typename?: 'Proposal', proposalId: any, description: string, startBlock: any, endBlock: any, queued: boolean, canceled: boolean, executed: boolean, state: ProposalState, proposer: { __typename?: 'Account', id: any }, proposalCreated: Array<{ __typename?: 'ProposalCreated', timestamp: any }>, proposalQueued: Array<{ __typename?: 'ProposalQueued', eta: any }>, proposalExecuted: Array<{ __typename?: 'ProposalExecuted', transaction: { __typename?: 'Transaction', id: string, timestamp: any } }>, votecast: Array<{ __typename?: 'VoteCast', id: string, support: { __typename?: 'ProposalSupport', weight: any }, receipt: { __typename?: 'VoteReceipt', id: string, weight: any, voter: { __typename?: 'Account', id: any }, support: { __typename?: 'ProposalSupport', id: string, support: number } } }>, metadata: { __typename?: 'ProposalMetadata', title: string, description: string }, votes: { __typename?: 'ProposalVotes', total: any, for: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, against: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, abstain: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> } } };
export type GetAllLocksQueryVariables = Exact<{ [key: string]: never; }>;
@@ -7313,12 +7313,12 @@ export type GetProposalQueryVariables = Exact<{
}>;
-export type GetProposalQuery = { __typename?: 'Query', proposals: Array<{ __typename?: 'Proposal', proposalId: any, description: string, startBlock: any, endBlock: any, queued: boolean, canceled: boolean, executed: boolean, state: ProposalState, calls: Array<{ __typename?: 'ProposalCall', index: number, value: any, signature: string, calldata: any, target: { __typename?: 'Account', id: any } }>, proposer: { __typename?: 'Account', id: any }, proposalCreated: Array<{ __typename?: 'ProposalCreated', timestamp: any }>, proposalQueued: Array<{ __typename?: 'ProposalQueued', eta: any }>, proposalExecuted: Array<{ __typename?: 'ProposalExecuted', transaction: { __typename?: 'Transaction', id: string, timestamp: any } }>, votecast: Array<{ __typename?: 'VoteCast', timestamp: any, voter: { __typename?: 'Account', id: any }, support: { __typename?: 'ProposalSupport', support: number, weight: any } }>, metadata: { __typename?: 'ProposalMetadata', title: string, description: string }, votes: { __typename?: 'ProposalVotes', total: any, for: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, against: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, abstain: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> } } }> };
+export type GetProposalQuery = { __typename?: 'Query', proposals: Array<{ __typename?: 'Proposal', proposalId: any, description: string, startBlock: any, endBlock: any, queued: boolean, canceled: boolean, executed: boolean, state: ProposalState, calls: Array<{ __typename?: 'ProposalCall', index: number, value: any, signature: string, calldata: any, target: { __typename?: 'Account', id: any } }>, proposer: { __typename?: 'Account', id: any }, proposalCreated: Array<{ __typename?: 'ProposalCreated', timestamp: any }>, proposalQueued: Array<{ __typename?: 'ProposalQueued', eta: any }>, proposalExecuted: Array<{ __typename?: 'ProposalExecuted', transaction: { __typename?: 'Transaction', id: string, timestamp: any } }>, votecast: Array<{ __typename?: 'VoteCast', id: string, support: { __typename?: 'ProposalSupport', weight: any }, receipt: { __typename?: 'VoteReceipt', id: string, weight: any, voter: { __typename?: 'Account', id: any }, support: { __typename?: 'ProposalSupport', id: string, support: number } } }>, metadata: { __typename?: 'ProposalMetadata', title: string, description: string }, votes: { __typename?: 'ProposalVotes', total: any, for: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, against: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, abstain: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> } } }> };
export type GetProposalsQueryVariables = Exact<{ [key: string]: never; }>;
-export type GetProposalsQuery = { __typename?: 'Query', proposals: Array<{ __typename?: 'Proposal', proposalId: any, description: string, startBlock: any, endBlock: any, queued: boolean, canceled: boolean, executed: boolean, state: ProposalState, proposer: { __typename?: 'Account', id: any }, proposalCreated: Array<{ __typename?: 'ProposalCreated', timestamp: any }>, proposalQueued: Array<{ __typename?: 'ProposalQueued', eta: any }>, proposalExecuted: Array<{ __typename?: 'ProposalExecuted', transaction: { __typename?: 'Transaction', id: string, timestamp: any } }>, votecast: Array<{ __typename?: 'VoteCast', timestamp: any, voter: { __typename?: 'Account', id: any }, support: { __typename?: 'ProposalSupport', support: number, weight: any } }>, metadata: { __typename?: 'ProposalMetadata', title: string, description: string }, votes: { __typename?: 'ProposalVotes', total: any, for: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, against: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, abstain: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> } } }> };
+export type GetProposalsQuery = { __typename?: 'Query', proposals: Array<{ __typename?: 'Proposal', proposalId: any, description: string, startBlock: any, endBlock: any, queued: boolean, canceled: boolean, executed: boolean, state: ProposalState, proposer: { __typename?: 'Account', id: any }, proposalCreated: Array<{ __typename?: 'ProposalCreated', timestamp: any }>, proposalQueued: Array<{ __typename?: 'ProposalQueued', eta: any }>, proposalExecuted: Array<{ __typename?: 'ProposalExecuted', transaction: { __typename?: 'Transaction', id: string, timestamp: any } }>, votecast: Array<{ __typename?: 'VoteCast', id: string, support: { __typename?: 'ProposalSupport', weight: any }, receipt: { __typename?: 'VoteReceipt', id: string, weight: any, voter: { __typename?: 'Account', id: any }, support: { __typename?: 'ProposalSupport', id: string, support: number } } }>, metadata: { __typename?: 'ProposalMetadata', title: string, description: string }, votes: { __typename?: 'ProposalVotes', total: any, for: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, against: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> }, abstain: { __typename?: 'VoteType', total: any, participants: Array<{ __typename?: 'Participant', address: string, weight: any }> } } }> };
export const ProposalFieldsFragmentDoc = gql`
fragment ProposalFields on Proposal {
@@ -7340,14 +7340,21 @@ export const ProposalFieldsFragmentDoc = gql`
}
}
votecast {
- timestamp
- voter {
- id
- }
+ id
support {
- support
weight
}
+ receipt {
+ id
+ voter {
+ id
+ }
+ weight
+ support {
+ id
+ support
+ }
+ }
}
startBlock
endBlock
diff --git a/src/lib/graphql/subgraph/policies/Proposal.ts b/src/lib/graphql/subgraph/policies/Proposal.ts
index 6ecb8bd3..cbe1aff4 100644
--- a/src/lib/graphql/subgraph/policies/Proposal.ts
+++ b/src/lib/graphql/subgraph/policies/Proposal.ts
@@ -6,6 +6,7 @@ import {
ProposalVotes,
Scalars,
VoteCast,
+ VoteReceipt,
} from "@/lib/graphql/subgraph/generated/subgraph";
type ProposalID = Scalars["ID"]["output"];
@@ -46,46 +47,28 @@ export const ProposalPolicy: TypePolicy = {
return votecastRefs.reduce(
(acc: ProposalVotes, votecastRef) => {
- const voterRef = readField
("voter", votecastRef);
- const supportRef = readField(
- "support",
- votecastRef,
- );
- const rawWeight = readField("weight", supportRef) || "";
- const weight = BigInt(rawWeight);
+ const receipt = readField("receipt", votecastRef);
+ if (!receipt) return acc;
+ const voterRef = readField("voter", receipt);
+ const supportRef = readField("support", receipt);
+ const weight = BigInt(readField("weight", receipt) || "0");
const address = readField("id", voterRef) as Address;
- const support = readField(
- "support",
- supportRef,
- );
-
+ const support = readField("support", supportRef);
switch (support) {
- // AGAINST
- case 0:
+ case 0: // AGAINST
acc.against.total += weight;
- acc.against.participants.push({
- address,
- weight,
- });
+ acc.against.participants.push({ address, weight });
break;
- // FOR
- case 1:
+ case 1: // FOR
acc.for.total += weight;
- acc.for.participants.push({
- address,
- weight,
- });
+ acc.for.participants.push({ address, weight });
break;
- // ABSTAIN
- case 2:
+ case 2: // ABSTAIN
acc.abstain.total += weight;
- acc.abstain.participants.push({
- address,
- weight,
- });
+ acc.abstain.participants.push({ address, weight });
break;
default:
@@ -96,18 +79,9 @@ export const ProposalPolicy: TypePolicy = {
return acc;
},
{
- for: {
- participants: [],
- total: 0n,
- },
- against: {
- participants: [],
- total: 0n,
- },
- abstain: {
- participants: [],
- total: 0n,
- },
+ for: { participants: [], total: 0n },
+ against: { participants: [], total: 0n },
+ abstain: { participants: [], total: 0n },
total: 0n,
},
);
diff --git a/src/middleware.ts b/src/middleware.ts
index 139c8356..a33d4698 100644
--- a/src/middleware.ts
+++ b/src/middleware.ts
@@ -9,10 +9,12 @@ export const config = {
};
export const IS_PROD = process.env.NEXT_PUBLIC_VERCEL_ENV === "production";
+export const IS_DEV = process.env.NEXT_PUBLIC_VERCEL_ENV === "development";
+export const IS_PREVIEW = process.env.NEXT_PUBLIC_VERCEL_ENV === "preview";
export function middleware(request: NextRequest, event: NextFetchEvent) {
const { pathname } = request.nextUrl;
- if (!IS_PROD) return NextResponse.next();
+ if (!IS_PROD && !IS_DEV && !IS_PREVIEW) return NextResponse.next();
if (pathname.startsWith("/proposals")) {
const [, , id] = pathname.split("/");
@@ -23,33 +25,41 @@ export function middleware(request: NextRequest, event: NextFetchEvent) {
transport: http(),
});
- let valid = false;
- const fetch = async () => {
+ return new Promise((resolve) => {
try {
- const proposal = await publicClient.readContract({
- address: Celo.contracts.MentoGovernor.address,
- abi: GovernorABI,
- functionName: "proposals",
- args: [BigInt(id)],
- });
+ const parsedId = BigInt(id);
- if (proposal) {
- console.log("found");
- valid = true;
- }
+ publicClient
+ .readContract({
+ address: Celo.contracts.MentoGovernor.address,
+ abi: GovernorABI,
+ functionName: "proposals",
+ args: [BigInt(parsedId)],
+ })
+ .then((proposal) => {
+ if (proposal) {
+ resolve(NextResponse.next());
+ } else {
+ const url = new URL("/", request.url);
+ console.log("Proposal not found, redirecting");
+ resolve(NextResponse.redirect(url.origin));
+ }
+ })
+ .catch((error) => {
+ console.log("Proposal not found on Celo chain, redirecting");
+ const url = new URL("/", request.url);
+ resolve(NextResponse.redirect(url.origin));
+ });
} catch (error) {
- console.log("Proposal not found on Celo chain, redirecting");
+ console.log("Proposal ID not found, redirecting");
+ const url = new URL("/", request.url);
+ resolve(NextResponse.redirect(url.origin));
}
- };
- event.waitUntil(fetch());
-
- if (valid) {
- return NextResponse.next();
- } else {
- return NextResponse.redirect(new URL("/", request.url));
- }
+ });
} else {
- return NextResponse.redirect(new URL("/", request.url));
+ console.log("Proposal ID not found, redirecting");
+ const url = new URL("/", request.url);
+ return NextResponse.redirect(url.origin);
}
}
}