diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 17b059ede..6a1c4fb68 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,6 +17,7 @@ jobs: SCORER_ID: ${{ secrets.SCORER_ID }} GITCOIN_PASSPORT_API_KEY: ${{ secrets.GITCOIN_PASSPORT_API_KEY }} LIST_MANAGER_PRIVATE_KEY: ${{ secrets.LIST_MANAGER_PRIVATE_KEY }} + FOUNDRY_OUT: pkg/contracts/out steps: - name: Check out code diff --git a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx index cb0ed915d..08b19ca04 100644 --- a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx +++ b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/[poolId]/[proposalId]/page.tsx @@ -1,23 +1,27 @@ "use client"; - import { useEffect, useState } from "react"; +import { Hashicon } from "@emeraldpay/hashicon-react"; import { InformationCircleIcon, UserIcon } from "@heroicons/react/24/outline"; -import Image from "next/image"; -import { Address, formatUnits } from "viem"; -import { useContractRead } from "wagmi"; +import { toast } from "react-toastify"; +import { Address, encodeAbiParameters, formatUnits } from "viem"; import { getProposalDataDocument, getProposalDataQuery, } from "#/subgraph/.graphclient"; -import { proposalImg } from "@/assets"; -import { Badge, DisplayNumber, EthAddress, Statistic } from "@/components"; +import { Badge, Button, DisplayNumber, EthAddress, Statistic } from "@/components"; import { ConvictionBarChart } from "@/components/Charts/ConvictionBarChart"; import { LoadingSpinner } from "@/components/LoadingSpinner"; +import { usePubSubContext } from "@/contexts/pubsub.context"; +import { useChainIdFromPath } from "@/hooks/useChainIdFromPath"; +import { useContractWriteWithConfirmations } from "@/hooks/useContractWriteWithConfirmations"; +import { useConvictionRead } from "@/hooks/useConvictionRead"; import { useSubgraphQuery } from "@/hooks/useSubgraphQuery"; -import { cvStrategyABI } from "@/src/generated"; +import { alloABI } from "@/src/generated"; import { poolTypes, proposalStatus } from "@/types"; +import { abiWithErrors } from "@/utils/abiWithErrors"; +import { useErrorDetails } from "@/utils/getErrorName"; import { getIpfsMetadata } from "@/utils/ipfsUtils"; -import { calculatePercentageBigInt } from "@/utils/numbers"; +import { logOnce } from "@/utils/log"; const prettyTimestamp = (timestamp: number) => { const date = new Date(timestamp * 1000); @@ -30,7 +34,7 @@ const prettyTimestamp = (timestamp: number) => { }; export default function Page({ - params: { proposalId, garden }, + params: { proposalId, garden, poolId }, }: { params: { proposalId: string; @@ -39,7 +43,6 @@ export default function Page({ garden: string; }; }) { - // TODO: fetch garden decimals in query const { data } = useSubgraphQuery({ query: getProposalDataDocument, variables: { @@ -57,6 +60,11 @@ export default function Page({ const metadata = proposalData?.metadata; + const proposalIdNumber = proposalData?.proposalNumber as number; + + const { publish } = usePubSubContext(); + const chainId = useChainIdFromPath(); + const [ipfsResult, setIpfsResult] = useState>>(); @@ -68,85 +76,76 @@ export default function Page({ } }, [metadata]); - const cvStrategyContract = { - address: proposalData?.strategy.id as Address, - abi: cvStrategyABI, - }; - - const proposalIdNumber = proposalData?.proposalNumber; - - const { data: thFromContract } = useContractRead({ - ...cvStrategyContract, - functionName: "calculateThreshold", - args: [proposalIdNumber], - enabled: !!proposalIdNumber, - }); - - const { data: totalEffectiveActivePoints } = useContractRead({ - ...cvStrategyContract, - functionName: "totalEffectiveActivePoints", - }); - - const { data: stakeAmountFromContract } = useContractRead({ - ...cvStrategyContract, - functionName: "getProposalStakedAmount", - args: [proposalIdNumber], - enabled: !!proposalIdNumber, - }); - const isProposalEnded = !!proposalData && - (proposalStatus[proposalData.proposalStatus] !== "executed" || - proposalStatus[proposalData.proposalStatus] !== "cancelled"); - - const { data: updateConvictionLast } = useContractRead({ - ...cvStrategyContract, - functionName: "updateProposalConviction" as any, // TODO: fix CVStrategy.updateProposalConviction to view in contract - args: [proposalIdNumber], - enabled: !!proposalIdNumber, - }) as { data: bigint | undefined }; + (proposalStatus[proposalData.proposalStatus] === "executed" || + proposalStatus[proposalData.proposalStatus] === "cancelled"); + logOnce("debug", { isProposalEnded, proposalStatus: proposalStatus[proposalData?.proposalStatus] }); - const { data: maxCVSupply } = useContractRead({ - ...cvStrategyContract, - functionName: "getMaxConviction", - args: [totalEffectiveActivePoints ?? 0n], - enabled: !!totalEffectiveActivePoints, + const { currentConvictionPct, thresholdPct, totalSupportPct, updateConvictionLast } = useConvictionRead({ + proposalData, + tokenData: data?.tokenGarden, }); const tokenSymbol = data?.tokenGarden?.symbol; - const tokenDecimals = data?.tokenGarden?.decimals; - const convictionLast = proposalData?.convictionLast; - const threshold = proposalData?.threshold; const proposalType = proposalData?.strategy.config?.proposalType; const requestedAmount = proposalData?.requestedAmount; const beneficiary = proposalData?.beneficiary as Address | undefined; const submitter = proposalData?.submitter as Address | undefined; const status = proposalData?.proposalStatus; - const stakedAmount = proposalData?.stakedAmount; - useEffect(() => { - if (!proposalData) { + const isSignalingType = poolTypes[proposalType] === "signaling"; + + //encode proposal id to pass as argument to distribute function + const encodedDataProposalId = (proposalId_: number) => { + if (!proposalId_) { return; } + const encodedProposalId = encodeAbiParameters( + [{ name: "proposalId", type: "uint" }], + [BigInt(proposalId_)], + ); + return encodedProposalId; + }; - console.debug({ - requestedAmount, - maxCVSupply, - threshold, - thFromContract, - stakedAmount, - stakeAmountFromContract: stakeAmountFromContract, - totalEffectiveActivePoints, - updateConvictionLast, - convictionLast, - }); - }, [proposalData]); + //distribution function from Allo contract + //args: poolId, strategyId, encoded proposalId + const { + write: writeDistribute, + error: errorDistribute, + isError: isErrorDistribute, + } = useContractWriteWithConfirmations({ + address: data?.allos[0]?.id as Address, + abi: abiWithErrors(alloABI), + functionName: "distribute", + contractName: "Allo", + fallbackErrorMessage: "Error executing proposal. Please try again.", + onConfirmations: () => { + publish({ + topic: "proposal", + type: "update", + function: "distribute", + id:proposalId, + containerId: data?.cvproposal?.strategy?.id, + chainId, + }); + }, + }); + + const distributeErrorName = useErrorDetails(errorDistribute); + useEffect(() => { + if (isErrorDistribute && distributeErrorName.errorName !== undefined) { + toast.error("NOT EXECUTABLE:" + " " + distributeErrorName.errorName); + } + }, [isErrorDistribute]); if ( !proposalData || !ipfsResult || - !maxCVSupply || - !totalEffectiveActivePoints || + currentConvictionPct == null || + thresholdPct == null || + totalSupportPct == null || + !proposalIdNumber || (updateConvictionLast == null && !isProposalEnded) ) { return ( @@ -156,43 +155,11 @@ export default function Page({ ); } - const isSignalingType = poolTypes[proposalType] === "signaling"; - - let thresholdPct = calculatePercentageBigInt( - threshold, - maxCVSupply, - tokenDecimals, - ); - - let totalSupportPct = calculatePercentageBigInt( - stakedAmount, - totalEffectiveActivePoints, - tokenDecimals, - ); - - let currentConvictionPct = calculatePercentageBigInt( - BigInt(updateConvictionLast ?? 0), - maxCVSupply, - tokenDecimals, - ); - - console.debug({ - thresholdPct, - totalSupportPct, - currentConvictionPct, - }); - return (
- {`proposal +
@@ -244,15 +211,21 @@ export default function Page({ Proposal passed and executed successfully
- : - } + : ( + + )} +
+ {proposalStatus[status] !== "executed" && !isSignalingType && ( )} + +
); } + diff --git a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/page.tsx b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/page.tsx index 3c6018884..bf55fdcee 100644 --- a/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/page.tsx +++ b/apps/web/app/(app)/gardens/[chain]/[garden]/[community]/page.tsx @@ -3,7 +3,6 @@ import React, { useEffect, useState } from "react"; import { CurrencyDollarIcon, - ExclamationCircleIcon, PlusIcon, RectangleGroupIcon, } from "@heroicons/react/24/outline"; @@ -24,6 +23,7 @@ import { PoolCard, RegisterMember, Statistic, + InfoIcon, } from "@/components"; import { LoadingSpinner } from "@/components/LoadingSpinner"; import { TokenGardenFaucet } from "@/components/TokenGardenFaucet"; @@ -214,23 +214,18 @@ export default function Page({

Registration cost:

-
+ - -
+
diff --git a/apps/web/app/api/passport-oracle/writeScore/route.ts b/apps/web/app/api/passport-oracle/writeScore/route.ts index e5a8bb880..229ea2acf 100644 --- a/apps/web/app/api/passport-oracle/writeScore/route.ts +++ b/apps/web/app/api/passport-oracle/writeScore/route.ts @@ -15,7 +15,6 @@ import { CV_PERCENTAGE_SCALE } from "@/utils/numbers"; import { getViemChain } from "@/utils/viem"; const LIST_MANAGER_PRIVATE_KEY = process.env.LIST_MANAGER_PRIVATE_KEY; - const CHAIN_ID = process.env.CHAIN_ID ? parseInt(process.env.CHAIN_ID) : 1337; const LOCAL_RPC = "http://127.0.0.1:8545"; diff --git a/apps/web/app/favicon.ico b/apps/web/app/favicon.ico new file mode 100644 index 000000000..edbe550c1 Binary files /dev/null and b/apps/web/app/favicon.ico differ diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index c6ab3a32e..ef4d0a9ee 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -1,6 +1,485 @@ -import _ from "react"; -import { redirect } from "next/navigation"; +"use client"; +import { JSX, SVGProps, useState } from "react"; +import { Dialog } from "@headlessui/react"; +import { CheckIcon } from "@heroicons/react/20/solid"; +import { + Bars3Icon, + XMarkIcon, + ArrowPathIcon, + FingerPrintIcon, + LockClosedIcon, + ArrowLongRightIcon, + Battery50Icon, +} from "@heroicons/react/24/outline"; +import Image from "next/image"; +import { newLogo, commF } from "@/assets"; +import { ChainIcon } from "@/configs/chainServer"; export default function Page() { - redirect("/gardens"); + return ( + <> + + + + + +