From 65a5ef25d6f82ab197fefe9fbf1183918ccf8aa6 Mon Sep 17 00:00:00 2001 From: epiqueras Date: Mon, 14 Sep 2020 21:20:55 -0400 Subject: [PATCH] chore: implement submission funding --- .../[id]/submission-details-card/deadlines.js | 2 +- .../submission-details-card/fund-button.js | 97 +++++++++++++++++++ .../[id]/submission-details-card/index.js | 55 ++++++++--- .../submission-details-card/vouch-button.js | 7 +- components/form.js | 13 ++- components/web3-provider.js | 3 +- 6 files changed, 155 insertions(+), 22 deletions(-) create mode 100644 _pages/profile/[id]/submission-details-card/fund-button.js diff --git a/_pages/profile/[id]/submission-details-card/deadlines.js b/_pages/profile/[id]/submission-details-card/deadlines.js index bd6c3635..665e98f8 100644 --- a/_pages/profile/[id]/submission-details-card/deadlines.js +++ b/_pages/profile/[id]/submission-details-card/deadlines.js @@ -39,7 +39,7 @@ export default function Deadlines({ submission, contract, status }) { return ( <> {status === submissionStatusEnum.PendingRegistration || diff --git a/_pages/profile/[id]/submission-details-card/fund-button.js b/_pages/profile/[id]/submission-details-card/fund-button.js new file mode 100644 index 00000000..923cf78f --- /dev/null +++ b/_pages/profile/[id]/submission-details-card/fund-button.js @@ -0,0 +1,97 @@ +import { + Box, + Button, + Field, + Form, + Popup, + Text, + useContract, + useWeb3, +} from "@kleros/components"; +import { useCallback, useMemo } from "react"; + +export default function FundButton({ + totalCost, + totalContribution, + submissionID, +}) { + const [accounts] = useWeb3("eth", "getAccounts"); + const amountNeeded = useMemo(() => totalCost.sub(totalContribution), [ + totalCost, + totalContribution, + ]); + const { web3 } = useWeb3(); + const amountNeededString = web3.utils.fromWei(amountNeeded); + const { send } = useContract("proofOfHumanity", "fundSubmission"); + return ( + + Fund Submission + + } + modal + > + +
({ + contribution: eth() + .test({ + test(value) { + if (value.lte(_web3.utils.toBN(0))) + return this.createError({ + message: `You need to contribute something.`, + }); + return true; + }, + }) + .test({ + test(value) { + if (value.gt(amountNeeded)) + return this.createError({ + message: `There's no need to contribute this much.`, + }); + return true; + }, + }), + }), + [amountNeeded] + )} + onSubmit={({ contribution }) => + send(submissionID, { value: contribution }) + } + > + {({ isSubmitting }) => ( + <> + ( + + Contribution + field[2].setValue(amountNeededString)} + > + (Needed: {amountNeededString}) + + + )} + type="number" + /> + + + )} + +
+
+ ); +} diff --git a/_pages/profile/[id]/submission-details-card/index.js b/_pages/profile/[id]/submission-details-card/index.js index 2a8c56b4..22175863 100644 --- a/_pages/profile/[id]/submission-details-card/index.js +++ b/_pages/profile/[id]/submission-details-card/index.js @@ -13,6 +13,7 @@ import { useMemo } from "react"; import { graphql, useFragment } from "relay-hooks"; import Deadlines from "./deadlines"; +import FundButton from "./fund-button"; import VouchButton from "./vouch-button"; import { partyEnum, submissionStatusEnum, useEvidenceFile } from "data"; @@ -61,8 +62,12 @@ export default function SubmissionDetailsCard({ submission, contract }) { const request = requests[status.registrationEvidenceFileIndex || 0]; const evidence = useEvidenceFile()(request.evidence[0].URI); - const contributions = request.challenges[0].rounds[0].contributions.map( - (contribution) => partyEnum.parse(contribution) + const contributions = useMemo( + () => + request.challenges[0].rounds[0].contributions.map((contribution) => + partyEnum.parse(contribution) + ), + [request] ); const [arbitrationCost] = useContract( @@ -85,13 +90,25 @@ export default function SubmissionDetailsCard({ submission, contract }) { submissionDetailsCardFragments.contract, contract )); - const totalCost = arbitrationCost - ?.add( + const totalCost = useMemo( + () => arbitrationCost - .mul(web3.utils.toBN(sharedStakeMultiplier)) - .div(web3.utils.toBN(10000)) - ) - .add(web3.utils.toBN(submissionBaseDeposit)); + ?.add( + arbitrationCost + .mul(web3.utils.toBN(sharedStakeMultiplier)) + .div(web3.utils.toBN(10000)) + ) + .add(web3.utils.toBN(submissionBaseDeposit)), + [arbitrationCost, web3.utils, sharedStakeMultiplier, submissionBaseDeposit] + ); + const totalContribution = useMemo( + () => + contributions.reduce( + (acc, { values: { Requester } }) => acc.add(web3.utils.toBN(Requester)), + web3.utils.toBN(0) + ), + [contributions, web3.utils] + ); return ( {evidence?.file?.bio} - + + {status === submissionStatusEnum.Vouching ? ( + <> + {totalCost?.gt(totalContribution) && ( + + )} + + + ) : null} + {totalCost && `${Math.floor( - contributions - .reduce( - (acc, { values: { Requester } }) => - acc.add(web3.utils.toBN(Requester)), - web3.utils.toBN(0) - ) + totalContribution .mul(web3.utils.toBN(100)) .div(totalCost) .toNumber() diff --git a/_pages/profile/[id]/submission-details-card/vouch-button.js b/_pages/profile/[id]/submission-details-card/vouch-button.js index a410d0ab..d694f635 100644 --- a/_pages/profile/[id]/submission-details-card/vouch-button.js +++ b/_pages/profile/[id]/submission-details-card/vouch-button.js @@ -23,7 +23,7 @@ export default function VouchButton({ submissionID }) { "proofOfHumanity", vouched ? "removeVouch" : "addVouch" ); - const text = status !== "pending" && `${vouched ? "Remove " : ""}Vouch`; + const text = `${vouched ? "Remove " : ""}Vouch`; return ( {text} diff --git a/components/form.js b/components/form.js index 0480101f..7995cf38 100644 --- a/components/form.js +++ b/components/form.js @@ -26,7 +26,9 @@ function ETH(...args) { ? prettyNum(value) : value ).split("."); - value = `${units}${decimals ? `.${decimals.slice(0, 18)}` : ""}`; + value = `${units[0] === "-" ? 0 : units}${ + decimals ? `.${decimals.slice(0, 18)}` : "" + }`; const bn = Web3.utils.toBN(Web3.utils.toWei(value)); bn.originalString = value; return bn; @@ -63,6 +65,7 @@ File.prototype._typeCheck = (value) => value?.toString() === "[object File]"; const ValidationSchemaContext = createContext(); export default function Form({ createValidationSchema, + onSubmit, sx, children, ...rest @@ -94,6 +97,9 @@ export default function Form({ + onSubmit(validationSchema.cast(values), formikBag) + } {...rest} > {(props) => ( @@ -108,10 +114,11 @@ export default function Form({ export function Field({ label, as = Input, name, ...rest }) { const validationSchema = useContext(ValidationSchemaContext); - const [{ onChange }] = useField(name); + const field = useField(name); + const [{ onChange }] = field; return (