= (props) => {
+ return (
+
+ theme.zIndex.drawer + 1 }}
+ open={props.show}
+ onClick={() => props.toggleClose}
+ >
+
+
+
+ );
+};
+
+export interface ICommonBackdrop {
+ show: boolean,
+ toggleClose: () => void
+}
+
+export default CommonBackdrop;
diff --git a/submissions/CorGit/code/webapp/src/ui/atmos/Project.SingleDetailCard/Project.SingleDetailCard.tsx b/submissions/CorGit/code/webapp/src/ui/atmos/Project.SingleDetailCard/Project.SingleDetailCard.tsx
new file mode 100644
index 0000000..6fa6d12
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/atmos/Project.SingleDetailCard/Project.SingleDetailCard.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import {Paper, Typography} from "@mui/material";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const ProjectSingleDetailCard: React.FC = (props) => {
+ return (
+
+ {props.name}
+ {props.value}
+
+ );
+};
+
+export interface IProjectSingleDetailCard {
+ name: string,
+ value: string
+}
+
+export default ProjectSingleDetailCard;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Common.Header/Common.Header.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Common.Header/Common.Header.tsx
new file mode 100644
index 0000000..0a4e12c
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Common.Header/Common.Header.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import {Box, Typography} from "@mui/material";
+import {useNavigate} from "react-router-dom";
+import {RouteKey} from "../../../App.Routes";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const CommonHeader: React.FC = (props) => {
+ const navigate = useNavigate();
+ return (
+
+ {navigate(RouteKey.Home)}}
+ color="primary">
+ CorGit
+
+
+ );
+};
+
+export interface ICommonHeader {
+
+}
+
+export default CommonHeader;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Common.PageWrapper/Common.PageWrapper.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Common.PageWrapper/Common.PageWrapper.tsx
new file mode 100644
index 0000000..ce53ab9
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Common.PageWrapper/Common.PageWrapper.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import CommonHeader from "../Common.Header/Common.Header";
+import {Box} from "@mui/material";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const CommonPageWrapper: React.FC = (props) => {
+ return (
+
+
+
+
+ {props.children}
+
+
+
+ );
+};
+
+export interface ICommonPageWrapper {
+ children?: JSX.Element | JSX.Element[];
+ customWidth?: string | number
+}
+
+export default CommonPageWrapper;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Common.PageWrapper/SingleCreateElement.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Common.PageWrapper/SingleCreateElement.tsx
new file mode 100644
index 0000000..e0aa772
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Common.PageWrapper/SingleCreateElement.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import {Grid, TextField, Typography} from "@mui/material";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const SingleCreateElement: React.FC = (props) => {
+ return (
+
+
+ {props.name}
+ {props.description}
+
+
+
+
+
+ );
+};
+
+export interface ISingleCreateElement {
+ name: string;
+ description: string;
+ value: string;
+ onChange: (event) => void;
+ isNumber?: boolean
+}
+
+export default SingleCreateElement;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Project.AddCollateralDialog/Project.AddCollateralDialog.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Project.AddCollateralDialog/Project.AddCollateralDialog.tsx
new file mode 100644
index 0000000..6cef58d
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Project.AddCollateralDialog/Project.AddCollateralDialog.tsx
@@ -0,0 +1,143 @@
+import {
+ Box,
+ Button,
+ CircularProgress,
+ Dialog,
+ DialogActions,
+ DialogContent,
+ DialogContentText,
+ DialogTitle,
+ Grid,
+ Slide,
+ TextField,
+ Typography
+} from '@mui/material';
+import React, {useEffect, useState} from 'react';
+import {TransitionProps} from "@mui/material/transitions";
+import {useAddCollateral} from "../../../hooks/useAddCollateral";
+import {useAccount, useSigner} from "wagmi";
+import {useParams} from "react-router";
+import {useLoadProjectUserContributions} from "../../../hooks/useLoadProjectUserContributions";
+import {useAppSelector} from "../../../hooks/reduxHooks";
+
+const Transition = React.forwardRef(function Transition(
+ props: TransitionProps & {
+ children: React.ReactElement;
+ },
+ ref: React.Ref,
+) {
+ return ;
+});
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const ProjectAddCollateralDialog: React.FC = (props) => {
+
+ const [valueEth, setValueEth] = useState("0");
+ const tokenSymbol = useAppSelector(state => state.cgProject?.tokenSymbol);
+
+ const { address, isConnected } = useAccount();
+ let { tokenAddress } = useParams();
+ const {data: signer} = useSigner({chainId: 5});
+ const {completed, transactionHash, error, checkNow} = useAddCollateral({cgTokenAddress: tokenAddress});
+ let { loading: loadingCgProjectContributions,
+ error: errorLoadCjProjectContributions,
+ projectUserContributions, checkNow: checkProjectContributions } = useLoadProjectUserContributions(tokenAddress);
+
+ useEffect(() => {
+ if (completed) {
+ checkProjectContributions({
+ signer: signer,
+ address: address
+ });
+ props.close();
+ }
+ }, [completed]);
+
+ return (
+
+ );
+};
+
+export interface IProjectAddCollateralDialog {
+ show: boolean,
+ close: () => void
+}
+
+export default ProjectAddCollateralDialog;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Project.UserRewardsList/Project.UserRewardsList.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Project.UserRewardsList/Project.UserRewardsList.tsx
new file mode 100644
index 0000000..97d2381
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Project.UserRewardsList/Project.UserRewardsList.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import {Box} from "@mui/material";
+import RewardLine from "./RewardLine";
+import {ProjectUserContributionInterface} from "../../../hooks/useLoadProjectUserContributions";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const ProjectUserRewardsList: React.FC = (props) => {
+ return (
+
+ {
+ props.contributionList.length === 0 ?
+ "You don't have any paid contribution yet in this project"
+ :
+ props.contributionList.map((contribution) =>
+
+ )
+ }
+
+ );
+};
+
+export interface IProjectUserRewardsList {
+ contributionList: ProjectUserContributionInterface[]
+
+}
+
+export default ProjectUserRewardsList;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Project.UserRewardsList/RewardLine.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Project.UserRewardsList/RewardLine.tsx
new file mode 100644
index 0000000..8d29697
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Project.UserRewardsList/RewardLine.tsx
@@ -0,0 +1,90 @@
+import React, {useEffect} from 'react';
+import {Box, Button, CircularProgress, Grid, Typography} from "@mui/material";
+import {Check} from "@mui/icons-material";
+import {
+ ProjectUserContributionInterface,
+ useLoadProjectUserContributions
+} from "../../../hooks/useLoadProjectUserContributions";
+import {useClaimRewards} from "../../../hooks/useClaimRewards";
+import {useAccount, useProvider, useSigner} from 'wagmi';
+import {useParams} from "react-router";
+import {format} from 'date-fns';
+import {useAppSelector} from "../../../hooks/reduxHooks";
+import {useLoadCgProject} from "../../../hooks/useLoadCgProject";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const RewardLine: React.FC = (props) => {
+
+ const { address, isConnected } = useAccount();
+ let { tokenAddress } = useParams();
+ const {data: signer} = useSigner({chainId: 5});
+ const {completed, transactionHash, error, checkNow} = useClaimRewards({cgTokenAddress: tokenAddress});
+ const provider = useProvider();
+ let { loading: loadingCgProject,
+ error: errorLoadCjProject,
+ checkNow: loadProjectData } = useLoadCgProject(tokenAddress);
+ let { loading: loadingCgProjectContributions,
+ error: errorLoadCjProjectContributions,
+ projectUserContributions, checkNow: checkProjectContributions } = useLoadProjectUserContributions(tokenAddress);
+
+ const tokenSymbol = useAppSelector(state => state.cgProject?.tokenSymbol);
+
+ useEffect(() => {
+ if (completed) {
+ loadProjectData(signer, provider, address);
+ checkProjectContributions({
+ signer: signer,
+ address: address
+ });
+ }
+
+ }, [completed])
+
+ return (
+
+
+ {props.contribution.name}
+ {
+ format(new Date(props.contribution.creation * 1000), "d LLL yyyy @ h:mm aaa")
+ }
+
+
+ {props.contribution.amount} ${tokenSymbol}
+
+
+ {
+ props.contribution.paid ?
+
+ Claimed
+
+
+ :
+ transactionHash ?
+
+ :
+
+ }
+
+
+ );
+};
+
+export interface IRewardLine {
+ contribution: ProjectUserContributionInterface
+}
+
+export default RewardLine;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Reward.PullRequestViewer/Reward.PullRequestViewer.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Reward.PullRequestViewer/Reward.PullRequestViewer.tsx
new file mode 100644
index 0000000..7992159
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Reward.PullRequestViewer/Reward.PullRequestViewer.tsx
@@ -0,0 +1,129 @@
+import React, {useEffect, useMemo, useState} from 'react';
+import {Box, Button, CircularProgress, Typography} from "@mui/material";
+import {PullRequest, PullRequestContributor} from "../../../utils/ProjectTypes/Project.types";
+import SingleContributorLine from "./SingleContributorLine";
+import {theme} from "../../../GlobalStyles";
+import {useParams} from "react-router";
+import {useCreateRewardContributions} from "../../../hooks/useCreateRewardContributions";
+import {useNavigate} from "react-router-dom";
+import {useSigner} from "wagmi";
+import {BigNumber} from "@ethersproject/bignumber";
+import {format} from "date-fns";
+import {useAppSelector} from "../../../hooks/reduxHooks";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const RewardPullRequestViewer: React.FC = (props) => {
+
+ const [contributorRewards, setContributorRewards] = useState<{ c: PullRequestContributor, amount: string }[]>([]);
+ let { tokenAddress } = useParams();
+ const navigate = useNavigate();
+ const { data: signer, isError, isLoading } = useSigner();
+ const tokenSymbol = useAppSelector(state => state.cgProject?.tokenSymbol);
+
+ const {completed, transactionHash, error: createContributionError, checkNow: createContribution}
+ = useCreateRewardContributions({cgTokenAddress: tokenAddress});
+
+ useEffect(() => {
+ if (completed)
+ navigate(`/project/${tokenAddress}`);
+ }, [completed]);
+
+ useEffect(() => {
+ let newContributorsRewards = props.pullRequest.contributors.map((c) => ({
+ c, amount: "0"
+ }));
+ setContributorRewards(newContributorsRewards);
+ }, [props.pullRequest]);
+
+ const editContributorReward = (pos: number, amount: string) => {
+ let cr = contributorRewards;
+ cr[pos].amount = amount;
+ setContributorRewards(JSON.parse(JSON.stringify(cr)));
+ }
+
+ const totalAmount = useMemo(() => {
+ return contributorRewards.reduce((a,b) => a+parseInt(b.amount ? b.amount : "0"), 0);
+ }, [contributorRewards]);
+
+ return (
+
+ {props.pullRequest.title}
+ Closed {
+ format(new Date(props.pullRequest.closedAt * 1000), "d LLL yyyy @ h:mm aaa")
+ }
+
+ Total of {props.pullRequest.contributors.length} contributors
+
+ {
+ contributorRewards.map((c, i) =>
+ {editContributorReward(i, newAmount)}}/>
+ )
+ }
+
+ {/* TOTAL */}
+ {
+ props.pullRequest.contributors.length > 0 ?
+
+
+ TOTAL
+
+ {totalAmount}
+ ${tokenSymbol}
+
+ :
+ ""
+ }
+
+ {/* REWARD BUTTON */}
+ {
+ props.pullRequest.contributors.length > 0 ?
+ transactionHash ?
+
+
+
+ :
+
+
+
+
+ :
+ ""
+ }
+
+ );
+};
+
+export interface IRewardPullRequestViewer {
+ pullRequest: PullRequest
+}
+
+export default RewardPullRequestViewer;
diff --git a/submissions/CorGit/code/webapp/src/ui/organisms/Reward.PullRequestViewer/SingleContributorLine.tsx b/submissions/CorGit/code/webapp/src/ui/organisms/Reward.PullRequestViewer/SingleContributorLine.tsx
new file mode 100644
index 0000000..f5969b9
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/organisms/Reward.PullRequestViewer/SingleContributorLine.tsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import {Avatar, Box, TextField, Typography} from "@mui/material";
+import {PullRequestContributor} from "../../../utils/ProjectTypes/Project.types";
+import {useAppSelector} from "../../../hooks/reduxHooks";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const SingleContributorLine: React.FC = (props) => {
+
+ const tokenSymbol = useAppSelector(state => state.cgProject?.tokenSymbol);
+
+ const handleChange = (e) => {
+ props.editReward(e.target.value);
+ }
+
+ return (
+
+
+
+ {props.contributor.username}
+ {props.contributor.commits.length} commit{props.contributor.commits.length > 1 ? "s" : ""}
+
+
+ ${tokenSymbol}
+
+ );
+};
+
+export interface ISingleContributorLine {
+ contributor: PullRequestContributor,
+ contributorReward: string,
+ editReward: (string) => void
+}
+
+export default SingleContributorLine;
diff --git a/submissions/CorGit/code/webapp/src/ui/pages/Create/Create.tsx b/submissions/CorGit/code/webapp/src/ui/pages/Create/Create.tsx
new file mode 100644
index 0000000..f2403e2
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/pages/Create/Create.tsx
@@ -0,0 +1,84 @@
+import React, {useEffect, useState} from 'react';
+import {Box, Button, CircularProgress, Typography} from "@mui/material";
+import CommonPageWrapper from "../../organisms/Common.PageWrapper/Common.PageWrapper";
+import SingleCreateElement from "../../organisms/Common.PageWrapper/SingleCreateElement";
+import {RocketLaunch} from "@mui/icons-material";
+import {useCreateCgProject} from "../../../hooks/useCreateCgProject";
+import {useAccount, useSigner} from "wagmi";
+import {useNavigate} from "react-router-dom";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const Create: React.FC = (props) => {
+
+ const [projectName, setProjectName, ] = useState("");
+ const [projectSymbol, setProjectSymbol, ] = useState("");
+ const [projectPrevContRew, setProjectPrevContRew, ] = useState("");
+ const {data} = useSigner({chainId: 5});
+ const {transactionHash, error, tokenAddress, checkNow} = useCreateCgProject();
+ const { address, isConnected } = useAccount();
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ if (tokenAddress)
+ navigate(`/project/${tokenAddress}`);
+ }, [tokenAddress]);
+
+ return (
+
+
+
+ Create a new cgToken
+
+
+ Enter the details of your cgToken, then add a .cgToken.json file on your repository main root.
+
+ setProjectName(e.target.value)}/>
+ setProjectSymbol(e.target.value)}/>
+ setProjectPrevContRew(e.target.value)}/>
+
+ {
+ transactionHash ?
+
+ :
+ }
+ onClick={() => {checkNow({
+ tokenName: projectName,
+ fromAddress: address,
+ prevContrRewards: parseInt(projectPrevContRew),
+ tokenSymbol: projectSymbol,
+ signer: data
+ })}}
+ sx={{color: "white", textTransform: "none", mt: 4}}>
+ Create your cgToken
+
+ }
+
+
+
+
+
+ );
+};
+
+export interface ICreate {
+
+}
+
+export default Create;
diff --git a/submissions/CorGit/code/webapp/src/ui/pages/Home/Home.tsx b/submissions/CorGit/code/webapp/src/ui/pages/Home/Home.tsx
new file mode 100644
index 0000000..0fc03a8
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/pages/Home/Home.tsx
@@ -0,0 +1,96 @@
+import React, {useEffect, useState} from 'react';
+import {Box, Button, CircularProgress, TextField} from "@mui/material";
+import {theme} from "../../../GlobalStyles";
+import {RocketLaunch} from "@mui/icons-material";
+import {useSearchCgProject} from "../../../hooks/useSearchCgProject";
+import {useDebounce} from "use-debounce";
+import {RouteKey} from "../../../App.Routes";
+import {useNavigate} from 'react-router-dom';
+import {useAccount, useConnect} from "wagmi";
+import {InjectedConnector} from 'wagmi/connectors/injected';
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const Home: React.FC = (props) => {
+ const { loading, address, error, checkNow } = useSearchCgProject();
+ const [tokenSearchValue, setTokenSearchValue] = useState("");
+ const [searchCgProjectValue] = useDebounce(tokenSearchValue, 500);
+ const navigate = useNavigate();
+ const account = useAccount();
+ const { connect } = useConnect({
+ connector: new InjectedConnector(),
+ chainId: 5
+ })
+
+ useEffect(() => {
+ if (searchCgProjectValue)
+ checkNow(searchCgProjectValue);
+ }, [searchCgProjectValue]);
+
+ // redirect on address found
+ useEffect(() => {
+ if (address)
+ navigate(`/project/${address}`);
+ }, [address]);
+
+ const onInputChange = (e) => {
+ setTokenSearchValue(e.target.value);
+ }
+
+ return (
+
+
+ CorGit
+
+
+ Open Source project tokenization
+
+
+ }: {} )
+ }}
+ placeholder={"Search by Github Repo URL or Token Address"} />
+
+
+ }
+ sx={{color: "white", textTransform: "none", mt: 4}}
+ onClick={() => {navigate(RouteKey.Create)}}
+ >
+ Create a New cgToken
+
+
+ {
+ account.address ?
+ ""
+ :
+
+ }
+
+
+
+
+
+ );
+};
+
+export interface IHome {
+
+}
+
+export default Home;
diff --git a/submissions/CorGit/code/webapp/src/ui/pages/ProjectPage/ProjectPage.tsx b/submissions/CorGit/code/webapp/src/ui/pages/ProjectPage/ProjectPage.tsx
new file mode 100644
index 0000000..d5b1312
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/pages/ProjectPage/ProjectPage.tsx
@@ -0,0 +1,135 @@
+import React, {useEffect, useState} from 'react';
+import CommonPageWrapper from "../../organisms/Common.PageWrapper/Common.PageWrapper";
+import {Box, Button, Grid, Typography} from "@mui/material";
+import ProjectSingleDetailCard from "../../atmos/Project.SingleDetailCard/Project.SingleDetailCard";
+import ProjectUserRewardsList from "../../organisms/Project.UserRewardsList/Project.UserRewardsList";
+import {useNavigate} from "react-router-dom";
+import {useParams} from "react-router";
+import ProjectAddCollateralDialog from "../../organisms/Project.AddCollateralDialog/Project.AddCollateralDialog";
+import CommonBackdrop from "../../atmos/Common.Backdrop/Common.Backdrop";
+import {useLoadCgProject} from "../../../hooks/useLoadCgProject";
+import {useLoadProjectUserContributions} from "../../../hooks/useLoadProjectUserContributions";
+import {useAppSelector} from "../../../hooks/reduxHooks";
+import {useAccount, useProvider, useSigner} from "wagmi";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const ProjectPage: React.FC = (props) => {
+
+ const [showAddCollateral, setShowAddCollateral] = useState(false);
+ const [showLoader, setShowLoader] = useState(false);
+ const navigate = useNavigate();
+ let { tokenAddress } = useParams();
+ const tokenSymbol = useAppSelector(state => state.cgProject?.tokenSymbol);
+ let { loading: loadingCgProject,
+ error: errorLoadCjProject,
+ checkNow: loadProjectData } = useLoadCgProject(tokenAddress);
+ let { loading: loadingCgProjectContributions,
+ error: errorLoadCjProjectContributions,
+ projectUserContributions, checkNow: checkProjectContributions } = useLoadProjectUserContributions(tokenAddress);
+ const { data: signer, error: errorSigner, isLoading: isLoadingSigner } = useSigner();
+
+ const provider = useProvider();
+ const { address, isConnected } = useAccount();
+
+ const project = useAppSelector(state => state.cgProject);
+ const contributions = useAppSelector(state => state.contributions.userContributions);
+
+ useEffect(() => {
+ // if (tokenAddress && isConnected && !isLoadingSigner && signer
+ // && provider.network.chainId === 280) {
+ if (tokenAddress && isConnected && !isLoadingSigner) {
+ loadProjectData(signer, provider, address);
+ checkProjectContributions({
+ signer: signer,
+ address: address
+ });
+ }
+ }, [tokenAddress, isConnected, isLoadingSigner, signer, provider]);
+
+ useEffect(() => {
+ setShowLoader(loadingCgProject || loadingCgProjectContributions);
+ }, [loadingCgProject, loadingCgProjectContributions]);
+
+ return (
+
+
+
+ {project.tokenName}
+ ${project.tokenSymbol}
+ {
+ tokenAddress.substring(0,6) + "..." + tokenAddress.substring(38)
+ }
+
+
+
+ {
+ project.isPayer ?
+
+ :
+ ""
+ }
+
+
+
+ {/* Section of details */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* Section of unclaimed rewards*/}
+
+ Your unclaimed rewards
+
+
+
+
+
+ {/* Dialog to add collateral */}
+ {setShowAddCollateral(false)}}/>
+
+ {/* Show a Backdrop loader */}
+ setShowLoader(false)}/>
+
+
+ );
+};
+
+export interface IProjectPage {
+
+}
+
+export default ProjectPage;
diff --git a/submissions/CorGit/code/webapp/src/ui/pages/Reward/Reward.tsx b/submissions/CorGit/code/webapp/src/ui/pages/Reward/Reward.tsx
new file mode 100644
index 0000000..c8d0c18
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/ui/pages/Reward/Reward.tsx
@@ -0,0 +1,65 @@
+import React, {useEffect, useState} from 'react';
+import CommonPageWrapper from "../../organisms/Common.PageWrapper/Common.PageWrapper";
+import {Box, CircularProgress, TextField, Typography} from "@mui/material";
+import {useGetPullRequestDetails} from "../../../hooks/useGetPullRequestDetails";
+import {useDebounce} from "use-debounce";
+import {useAppSelector} from "../../../hooks/reduxHooks";
+import {PullRequest} from "../../../utils/ProjectTypes/Project.types";
+import RewardPullRequestViewer from "../../organisms/Reward.PullRequestViewer/Reward.PullRequestViewer";
+
+/**
+ *
+ * @param {React.PropsWithChildren} props
+ * @return {JSX.Element}
+ * @constructor
+ */
+const Reward: React.FC = (props) => {
+
+ const [urlSearchValue, setUrlSearchValue] = useState("");
+ const tokenName = useAppSelector(state => state.cgProject?.tokenName);
+ const [searchCgProjectValue] = useDebounce(urlSearchValue, 500);
+ const {loading, error, pullRequestUrl, checkNow} = useGetPullRequestDetails();
+
+ const pullRequest: PullRequest = useAppSelector(state => state.github.pullRequest);
+
+ useEffect(() => {
+ if (searchCgProjectValue)
+ checkNow(searchCgProjectValue);
+ }, [searchCgProjectValue]);
+
+ return (
+
+
+ {tokenName}
+ - Reward Page -
+
+
+ {setUrlSearchValue(e.target.value)}}
+ InputProps={{
+ ...( loading ? {endAdornment: }: {} )
+ }}
+ placeholder={"Enter the Github Pull Request URL"} />
+
+
+ {
+ pullRequest ?
+
+
+
+ :
+ ""
+ }
+
+
+
+ );
+};
+
+export interface IReward {
+
+}
+
+export default Reward;
diff --git a/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Errors.enum.ts b/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Errors.enum.ts
new file mode 100644
index 0000000..85d9c51
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Errors.enum.ts
@@ -0,0 +1,8 @@
+export enum ErrorsEnum {
+ PROOF_0001 = "Cannot correctly load all the proofs",
+ PROOF_0002 = "Cannot eval hashes of selected files",
+ PROOF_0003 = "Error uploading files to temporary S3",
+ PROOF_0004 = "Error minting the transaction",
+ PROOF_0005 = "Failed reading the prices",
+ PROOF_0006 = "Failed updating the title",
+}
diff --git a/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Project.enum.ts b/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Project.enum.ts
new file mode 100644
index 0000000..977c4b3
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Project.enum.ts
@@ -0,0 +1,20 @@
+export enum ProofVerificationStatus {
+ NotVerified,
+ Pending,
+ Verified,
+ Failed
+}
+
+export enum StorageType {
+ ArweaveV1
+}
+
+export enum Chain {
+ Goerli=5,
+ PolygonMainnet=137
+}
+
+export enum FileMIMEType {
+ "-"= "-",
+ "text/html"= "text/html"
+}
diff --git a/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Project.types.ts b/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Project.types.ts
new file mode 100644
index 0000000..d91ff71
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/utils/ProjectTypes/Project.types.ts
@@ -0,0 +1,143 @@
+import {Chain, FileMIMEType, ProofVerificationStatus, StorageType} from "./Project.enum";
+import Web3 from "web3";
+import {AbiItem} from "web3-utils";
+
+export type address = string;
+
+export type GithubCommit = {
+ sha: string,
+ url: string,
+ message: string
+};
+
+export enum PullRequestState {
+ CLOSED = "closed",
+ OPEN = "open"
+};
+
+export type PullRequest = {
+ id: number,
+ title: string,
+ state: PullRequestState,
+ closedAt: number,
+ contributors: PullRequestContributor[]
+};
+
+export type PullRequestContributor = {
+ id: number,
+ avatarUrl: string,
+ username: string,
+ profileUrl: string,
+ commits: GithubCommit[]
+};
+
+/**
+ * Object of a proof already minted
+ *
+ * @param {string} id - the full tokenId represented by a string
+ * @param {Chain} chain
+ * @param {number} nftNum - the number of NFT on that chain
+ * @param {string} title
+ * @param {string} description
+ * @param {string} hash
+ * @param {ProofVerificationStatus} verificationStatus
+ * @param {number} createdAt
+ * @param {StorageType?} storageType
+ * @param {string?} fileUrl
+ * @param {FileMIMEType?} MIMEType
+ */
+export type Proof = {
+ id: string,
+ chain: Chain,
+ nftNum: number,
+ title: string,
+ description: string,
+ hash: string,
+ verificationStatus: ProofVerificationStatus,
+ createdAt: number,
+ storageType?: StorageType,
+ fileUrl?: string,
+ MIMEType?: FileMIMEType,
+ verificationFailed: boolean
+};
+
+/**
+ * Object of a proof the user is creating and will be minted
+ *
+ * @param {string} id - the id of the file
+ * @param {string} title - the title of Proof (empty by default)
+ * @param {string} fileName - name of the file on the machine host
+ * @param {number} size - size in byte of the file
+ * @param {string} hash - hash of the file
+ * @param {boolean} toBeVerified - true if the file has to be verified, false otherwise
+ * @param {number} uploadPerc - in case of upload, the perc of upload
+ */
+export type ProofToMint = {
+ id: string,
+ title: string,
+ fileName: string,
+ size: number,
+ hash: string,
+ toBeVerified: boolean,
+ uploadPerc: number
+};
+
+/**
+ * Params for the redux action to generate the params (aka, make the mint transaction)
+ *
+ * @param {address} address - who's making the transaction (and will receive the NFT too)
+ * @param {Web3} web3 - web3 instance
+ * @param {ProofToMint[]} proofs - list of the proofs to mint
+ * @param {AbiItem} routerAbi - ABI of the router
+ * @param {address} routerAddress - address of the router
+ * @param {AbiItem} nftAbi - ABI of the NFT Factory
+ * @param {address} nftAddress - address of the NFT factory
+ */
+export type GenerateProofActionParams = {
+ address: address,
+ web3: Web3,
+ proofs: ProofToMint[],
+ delegatorAddress: address,
+ routerAbi: AbiItem,
+ routerAddress: address,
+ nftAbi: AbiItem,
+ nftAddress: address,
+ price: Prices
+};
+
+/**
+ * Represents the prices of the service in wei
+ *
+ * @param {number} mint - price for just minting (in ETH or equivalent)
+ * @param {number} verification - price to publish and certify the file (in ETH or equivalent)
+ */
+export type Prices = {
+ mint: number,
+ verification: number
+};
+
+/**
+ * Represent the core details for a given deployment, and all its contracts we have to interact
+ */
+export type DeploymentContractsDetails = {
+ CG_FACTORY: address,
+ GITHUB_ADDRESS_REGISTER: address,
+ CG_FACTORY_ABI: any,
+ GITHUB_ADDRESS_REGISTER_ABI: any,
+ CG_PROJECT_ABI: any
+};
+
+/**
+ * Core details of each chain we're on
+ *
+ * @param {number} ID - the ID of the chain
+ * @param {string} EXPLORER_URL - the initial part of the explorer url (ex. "https://etherscan.io")
+ * @param {string} OPENSEA_CHAIN_NAME - the name of the chain in the URL of opensea
+ * @param {boolean} IS_TESTNET - true if it's a testnet, false otherwise
+ */
+export type ChainDetails = {
+ ID: number,
+ EXPLORER_URL: string,
+ OPENSEA_CHAIN_NAME: string,
+ IS_TESTNET: boolean
+};
diff --git a/submissions/CorGit/code/webapp/src/utils/Tools/FileManagement.ts b/submissions/CorGit/code/webapp/src/utils/Tools/FileManagement.ts
new file mode 100644
index 0000000..f0d5ca0
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/utils/Tools/FileManagement.ts
@@ -0,0 +1,46 @@
+/**
+ * Generates the sha-256 hash of a given File
+ *
+ * @param {File} file - the file you want the hash
+ */
+export const fileToHash = async (file: File): Promise => {
+ // get byte array of file
+ let buffer = await file.arrayBuffer();
+ // hash the message
+ const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
+ // convert ArrayBuffer to Array
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ // convert bytes to hex string
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
+}
+
+/**
+ * Merges two FileList objects and returns a new FileList object
+ * @param {FileList} fileListA The first FileList object
+ * @param {FileList} fileListB The second FileList object
+ */
+export const mergeFileLists = (fileListA: FileList, fileListB: FileList): FileList => {
+ const dataTransfer = new DataTransfer();
+ for (let i = 0; i < fileListA.length; i++) {
+ dataTransfer.items.add(fileListA[i]);
+ }
+ for (let i = 0; i < fileListB.length; i++) {
+ dataTransfer.items.add(fileListB[i]);
+ }
+ return dataTransfer.files;
+}
+
+
+/**
+ * Merges two FileList objects and returns a new FileList object
+ * @param {FileList} fileList The FileList object
+ * @param {number} idItem The id of the item to remove (position)
+ */
+export const removeFromFileList = (fileList: FileList, idItem: number): FileList => {
+ const dataTransfer = new DataTransfer();
+ for (let i = 0; i < fileList.length; i++) {
+ if (i !== idItem) dataTransfer.items.add(fileList[i]);
+ }
+ return dataTransfer.files;
+}
+
diff --git a/submissions/CorGit/code/webapp/src/utils/Tools/Web3Management.ts b/submissions/CorGit/code/webapp/src/utils/Tools/Web3Management.ts
new file mode 100644
index 0000000..96170ee
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/utils/Tools/Web3Management.ts
@@ -0,0 +1,18 @@
+import {Chain} from "../ProjectTypes/Project.enum";
+import {BigNumber} from "@ethersproject/bignumber";
+
+
+/**
+ * Transforms a full tokenId of an NFT, into it's ID number, and the chain where it is on.
+ * @param {string} tokenId - the token id as it's written on the chain
+ * @return {chain: Chain, nftNum: number} - the combination of chain number and the number of NFT on that chain
+ */
+export const fromTokenIdToChain = (tokenId: string): { chain: Chain, nftNum: number } => {
+ let tkId = BigNumber.from(tokenId);
+ let chainNum = tkId.div(BigNumber.from(10).pow(50)).toNumber();
+ let tokenIdNum = tkId.sub(BigNumber.from(10).pow(50).mul(chainNum)).toNumber();
+ return {
+ chain: chainNum,
+ nftNum: tokenIdNum
+ }
+}
diff --git a/submissions/CorGit/code/webapp/src/utils/constants.ts b/submissions/CorGit/code/webapp/src/utils/constants.ts
new file mode 100644
index 0000000..4a3e0d4
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/utils/constants.ts
@@ -0,0 +1,19 @@
+import {DeploymentContractsDetails} from "./ProjectTypes/Project.types";
+
+export const CONTRACTS_DETAILS: {5: DeploymentContractsDetails, 280: DeploymentContractsDetails} = {
+ 5: {
+ CG_FACTORY: "0x7c31AD652FdAC7955CD81287343846873B558453",
+ GITHUB_ADDRESS_REGISTER: "0xd5F210aAe5330308ebc2B015Bfb0e70839251811",
+ CG_FACTORY_ABI: [{"inputs":[{"internalType":"address","name":"_githubAddressRegister","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_addr","type":"address"},{"indexed":false,"internalType":"string","name":"_name","type":"string"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint16","name":"_percFundingDistribute","type":"uint16"}],"name":"NewCgTokenCreated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"cgTokenList","outputs":[{"internalType":"contract cgToken","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint16","name":"_percFundingDistribute","type":"uint16"}],"name":"generate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"githubAddressRegister","outputs":[{"internalType":"contract GithubAddressRegister","name":"","type":"address"}],"stateMutability":"view","type":"function"}],
+ GITHUB_ADDRESS_REGISTER_ABI: [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"uint256","name":"_githubID","type":"uint256"},{"internalType":"address","name":"_wallet","type":"address"}],"name":"addAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressToGithubID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"githubIDToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_githubID","type":"uint256"},{"internalType":"address","name":"_addressToRemove","type":"address"}],"name":"removeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],
+ CG_PROJECT_ABI: [{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_initialSupply","type":"uint256"},{"internalType":"uint16","name":"_percFundingDistribute","type":"uint16"},{"internalType":"address","name":"_githubAddressRegister","type":"address"},{"internalType":"address","name":"creator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_numOfUsers","type":"uint256"}],"name":"NewGroupPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_githubID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_paymentId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"PaymentClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_githubID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"PaymentPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_paymentId","type":"uint256"}],"name":"collectPayment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contribute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"convert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"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"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockedTokensForPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPaymentId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_githubID","type":"uint256[]"},{"internalType":"uint256[]","name":"_amount","type":"uint256[]"},{"internalType":"string","name":"_name","type":"string"}],"name":"pay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"paymentAmounts","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"paid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"payments","outputs":[{"internalType":"uint256","name":"creation","type":"uint256"},{"internalType":"uint256","name":"totalTokenAmount","type":"uint256"},{"internalType":"uint256","name":"totalTokenClaimed","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"numOfUsers","type":"uint256"},{"internalType":"bool","name":"claimCompleted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"percFundingDistributed","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"percFundingForNewTokens","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
+ },
+ 280: {
+ CG_FACTORY: "0x84360Fc81b1be9860A37859Be3b48e505D494F38",
+ GITHUB_ADDRESS_REGISTER: "0xa5B07286eA9a9f7deC44104Cb621f1cf55AA9634",
+ CG_FACTORY_ABI: [{"inputs":[{"internalType":"address","name":"_githubAddressRegister","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_addr","type":"address"},{"indexed":false,"internalType":"string","name":"_name","type":"string"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint16","name":"_percFundingDistribute","type":"uint16"}],"name":"NewCgTokenCreated","type":"event"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"cgTokenList","outputs":[{"internalType":"contract cgToken","name":"tokenContract","type":"address"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint16","name":"_percFundingDistribute","type":"uint16"}],"name":"generate","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"githubAddressRegister","outputs":[{"internalType":"contract GithubAddressRegister","name":"","type":"address"}],"stateMutability":"view","type":"function"}],
+ GITHUB_ADDRESS_REGISTER_ABI: [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"uint256","name":"_githubID","type":"uint256"},{"internalType":"address","name":"_wallet","type":"address"}],"name":"addAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addressToGithubID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"githubIDToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_githubID","type":"uint256"},{"internalType":"address","name":"_addressToRemove","type":"address"}],"name":"removeAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}],
+ CG_PROJECT_ABI: [{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_initialSupply","type":"uint256"},{"internalType":"uint16","name":"_percFundingDistribute","type":"uint16"},{"internalType":"address","name":"_githubAddressRegister","type":"address"},{"internalType":"address","name":"creator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_numOfUsers","type":"uint256"}],"name":"NewGroupPayment","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_githubID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_paymentId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"PaymentClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_githubID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"PaymentPending","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAYER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_paymentId","type":"uint256"}],"name":"collectPayment","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contribute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"convert","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"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"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockedTokensForPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextPaymentId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_githubID","type":"uint256[]"},{"internalType":"uint256[]","name":"_amount","type":"uint256[]"},{"internalType":"string","name":"_name","type":"string"}],"name":"pay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"paymentAmounts","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"paid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"payments","outputs":[{"internalType":"uint256","name":"creation","type":"uint256"},{"internalType":"uint256","name":"totalTokenAmount","type":"uint256"},{"internalType":"uint256","name":"totalTokenClaimed","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"numOfUsers","type":"uint256"},{"internalType":"bool","name":"claimCompleted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"percFundingDistributed","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"percFundingForNewTokens","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
+ }
+};
+
diff --git a/submissions/CorGit/code/webapp/src/utils/localStorage/LocalStorageKeys.ts b/submissions/CorGit/code/webapp/src/utils/localStorage/LocalStorageKeys.ts
new file mode 100644
index 0000000..eeb9dc5
--- /dev/null
+++ b/submissions/CorGit/code/webapp/src/utils/localStorage/LocalStorageKeys.ts
@@ -0,0 +1,8 @@
+
+/**
+ * Enumeration of key values for local storage
+ * @property {LocalStorageKeys.AuthData} AuthToken - Stores a JSON of type ....
+ */
+export enum LocalStorageKeys {
+ AuthData = "authData"
+}
diff --git a/submissions/CorGit/code/webapp/tsconfig.json b/submissions/CorGit/code/webapp/tsconfig.json
new file mode 100644
index 0000000..b958231
--- /dev/null
+++ b/submissions/CorGit/code/webapp/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": false,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": [
+ "src"
+ ]
+}