diff --git a/garage/src/abis/VotingRegistry.ts b/garage/src/abis/VotingRegistry.ts index 3c71bdbf..050c8be2 100644 --- a/garage/src/abis/VotingRegistry.ts +++ b/garage/src/abis/VotingRegistry.ts @@ -76,4 +76,28 @@ export const abi = [ stateMutability: "nonpayable", type: "function", }, + { + inputs: [ + { + internalType: "bytes32", + name: "role", + type: "bytes32", + }, + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "hasRole", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, ] as const; diff --git a/garage/src/hooks/useIsAdmin.ts b/garage/src/hooks/useIsAdmin.ts new file mode 100644 index 00000000..61ea0b54 --- /dev/null +++ b/garage/src/hooks/useIsAdmin.ts @@ -0,0 +1,44 @@ +import { useContractReads } from "wagmi"; +import { as0xString } from "../utils/types"; +import { secondaryChain, deployment } from "../env"; +import { abi as missionsAbi } from "../abis/MissionsManager"; +import { abi as votingAbi } from "../abis/VotingRegistry"; +import { useAccount } from "./useAccount"; + +const { votingContractAddress, missionContractAddress } = deployment; + +const ZERO_ADDR = "0x0000000000000000000000000000000000000000" as const; + +const MISSIONS_ADMIN_ROLE = + "0x6de1decd3455ea3e945a8b81428c6da1e39da9f747dff73b900c35f95d8d9528" as const; +const VOTING_ADMIN_ROLE = + "0x26e5e0c1d827967646b29471a0f5eef941c85bdbb97c194dc3fa6291a994a148" as const; + +export const useIsAdmin = () => { + const { address } = useAccount(); + + const { isLoading, data } = useContractReads({ + allowFailure: false, + enabled: !!address, + contracts: [ + { + chainId: secondaryChain.id, + address: as0xString(votingContractAddress)!, + abi: votingAbi, + functionName: "hasRole", + args: [VOTING_ADMIN_ROLE, address ?? ZERO_ADDR], + }, + { + chainId: secondaryChain.id, + address: as0xString(missionContractAddress)!, + abi: missionsAbi, + functionName: "hasRole", + args: [MISSIONS_ADMIN_ROLE, address ?? ZERO_ADDR], + }, + ], + }); + + if (!data || isLoading) return { isLoading, data: null }; + + return { isLoading, data: { votingAdmin: data[0], missionsAdin: data[1] } }; +}; diff --git a/garage/src/pages/Admin/index.tsx b/garage/src/pages/Admin/index.tsx index ae337764..97c35b91 100644 --- a/garage/src/pages/Admin/index.tsx +++ b/garage/src/pages/Admin/index.tsx @@ -20,6 +20,8 @@ import { Th, Tbody, HStack, + Spinner, + Text, } from "@chakra-ui/react"; import { Link } from "react-router-dom"; import { Database } from "@tableland/sdk"; @@ -33,6 +35,7 @@ import { CreateProposalModal } from "../../components/CreateProposalModal"; import { useProposals } from "../../hooks/useProposals"; import { useAdminMisisons } from "../../hooks/useMissions"; import { secondaryChain, deployment } from "../../env"; +import { useIsAdmin } from "../../hooks/useIsAdmin"; const { ftRewardsTable } = deployment; @@ -274,7 +277,24 @@ const ListMissionsForm = (props: React.ComponentProps) => { ); }; +const NoPermissionsForm = ({ + title, + body, + ...props +}: { title: string; body: string } & React.ComponentProps) => { + return ( + + {title} + + {body} + + + ); +}; + export const Admin = () => { + const { isLoading, data } = useIsAdmin(); + return ( <> { minHeight={`calc(100vh - ${TOPBAR_HEIGHT})`} > - - - + {isLoading || !data ? ( + + ) : ( + <> + + {data.votingAdmin ? ( + + ) : ( + + )} + {data.missionsAdin ? ( + + ) : ( + + )} + + )}