Skip to content

Commit

Permalink
chore: implement transaction sender
Browse files Browse the repository at this point in the history
  • Loading branch information
epiqueras committed Sep 6, 2020
1 parent 4cc1006 commit 1bab6c5
Show file tree
Hide file tree
Showing 10 changed files with 434 additions and 35 deletions.
34 changes: 34 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ module.exports = {
// Import Plugin
"plugin:import/errors",

// Unicorn Plugin
"plugin:unicorn/recommended",

// React Plugin
"plugin:react/recommended",

Expand Down Expand Up @@ -144,6 +147,37 @@ module.exports = {
],
"import/newline-after-import": "error",

// Unicorn Plugin
"unicorn/prevent-abbreviations": [
"error",
{
replacements: {
acc: false,
args: false,
arr: false,
err: false,
props: false,
ref: false,
res: false,
},
},
],
"unicorn/no-nested-ternary": "off",
"unicorn/no-null": "off",
"unicorn/no-reduce": "off",
"unicorn/catch-error-name": [
"error",
{
name: "err",
},
],
"unicorn/custom-error-definition": "error",
"unicorn/no-unsafe-regex": "error",
"unicorn/no-unused-properties": "error",
"unicorn/prefer-flat-map": "error",
"unicorn/prefer-replace-all": "error",
"unicorn/string-content": "error",

// React Plugin
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
Expand Down
16 changes: 13 additions & 3 deletions _pages/profile/[id]/submit-profile-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
FileUpload,
Form,
Textarea,
useContract,
useWeb3,
} from "@kleros/components";

Expand All @@ -21,8 +22,15 @@ const createValidationSchema = ({ string, file }) => ({
video: file().required("Required"),
});
export default function SubmitProfileCard() {
const { web3, connect } = useWeb3();
const [accounts] = useWeb3("eth", "getAccounts");
const { connect } = useWeb3();
const { loading, send } = useContract(
"proofOfHumanity",
"changeRequiredNumberOfVouches",
{
type: "send",
}
);
return (
<Card
header="Submit Profile"
Expand Down Expand Up @@ -61,10 +69,12 @@ export default function SubmitProfileCard() {
maxSize={2}
video
/>
{!web3.contracts?.proofOfHumanity || !accounts?.[0] ? (
{!accounts?.[0] ? (
<Button onClick={connect}>Connect Account</Button>
) : (
<Button type="submit">Submit</Button>
<Button type="submit" loading={loading} onClick={() => send(1)}>
Submit
</Button>
)}
</Form>
</Card>
Expand Down
13 changes: 10 additions & 3 deletions components/button.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { forwardRef } from "react";
import { Button as _Button } from "theme-ui";
import { MoonLoader } from "react-spinners";
import { Box, Button as _Button } from "theme-ui";

import Text from "./text";

const Button = forwardRef(
({ id, sx, type = "button", disabled, children, ...rest }, ref) => (
({ id, sx, type = "button", disabled, children, loading, ...rest }, ref) => (
<_Button
ref={ref}
id={id}
Expand All @@ -15,7 +16,8 @@ const Button = forwardRef(
...sx,
}}
type={type}
disabled={disabled || !children}
disabled={disabled || !children || loading}
data-loading={loading}
{...rest}
>
<Text
Expand All @@ -28,6 +30,11 @@ const Button = forwardRef(
}}
>
{children}
{loading && (
<Box variant="buttons.primary.spinner">
<MoonLoader size={16} />
</Box>
)}
</Text>
</_Button>
)
Expand Down
2 changes: 1 addition & 1 deletion components/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default function Grid({ children, ...rest }) {
return (
<_Grid {...rest}>
{children ||
[...Array(rest.columns)].map((_, i) => (
[...new Array(rest.columns)].map((_, i) => (
<ReactLoadingSkeleton key={i} />
))}
</_Grid>
Expand Down
2 changes: 1 addition & 1 deletion components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export { default as Text } from "./text";
export { default as Textarea } from "./textarea";
export { default as ThemeProvider, typographyTheme } from "./theme-provider";
export { default as Video } from "./video";
export { default as Web3Provider, useWeb3 } from "./web3-provider";
export { default as Web3Provider, useWeb3, useContract } from "./web3-provider";

export { NextLink, createWrapConnection } from "./next-router";
2 changes: 1 addition & 1 deletion components/next-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const createWrapConnection = (queries, queryEnums) => {
(acc, [key, value]) => {
const queryEnumQuery = queryEnums[key]?.[value]?.query;
if (queryEnumQuery) acc = { ...acc, ...queryEnumQuery };
else acc[key] = isNaN(value) ? value : Number(value);
else acc[key] = Number.isNaN(Number(value)) ? value : Number(value);
return acc;
},
{}
Expand Down
8 changes: 7 additions & 1 deletion components/theme-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,16 @@ const theme = merge(merge(base, toTheme(typographyTheme)), {
fill: "background",
fontSize: 1,
padding: 2,
"&:disabled": {
"&:disabled:not([data-loading=true])": {
backgroundColor: "skeleton",
backgroundImage: "none !important",
},
spinner: {
"div > div": {
backgroundColor: "background",
borderColor: "background",
},
},
},
secondary: {
backgroundColor: "secondary",
Expand Down
102 changes: 95 additions & 7 deletions components/web3-provider.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import UniLoginProvider from "@unilogin/provider";
import WalletConnectWeb3Provider from "@walletconnect/web3-provider";
import Authereum from "authereum";
import { createContext, useContext, useEffect, useMemo, useState } from "react";
import {
createContext,
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import { useStorageReducer } from "react-storage-hooks";
import usePromise from "react-use-promise";
import Web3 from "web3";
import Web3Modal from "web3modal";
Expand Down Expand Up @@ -51,15 +59,17 @@ export default function Web3Provider({ infuraURL, contracts, children }) {
let cancelled = false;
(async () => {
if (contracts !== web3._contracts) {
const ETHNetID = await web3.eth.net.getId();
const [ETHNetID, accounts] = await Promise.all([
web3.eth.net.getId(),
web3.eth.getAccounts(),
]);
if (!cancelled) {
web3.contracts = contracts.reduce(
(acc, { name, abi, address, options }) => {
acc[name] = new web3.eth.Contract(
abi,
address[ETHNetID],
options
);
acc[name] = new web3.eth.Contract(abi, address[ETHNetID], {
from: accounts[0],
...options,
});
return acc;
},
{}
Expand Down Expand Up @@ -105,3 +115,81 @@ export function useWeb3(namespace, method, args) {

return isNotCall ? web3Context : data;
}

const sendStateReducer = (
state,
{ type, transactionHash, confirmation, receipt, error }
) => {
switch (type) {
case "transactionHash":
return { transactionHash };
case "confirmation":
return { ...state, confirmation };
case "receipt":
return { ...state, receipt };
case "error":
return { ...state, error };
}
};
export function useContract(
contract,
method,
{ args, type = "call", options }
) {
const { web3 } = useWeb3();
const run = useCallback(
(_args) =>
web3.contracts[contract].methods[method](...(args || []), ..._args)[type](
...(options || [])
),
[web3.contracts, contract, method, args, type, options]
);
const isSend = type === "send";

const [sendState, dispatch] = useStorageReducer(
localStorage,
JSON.stringify({ contract, method, type }),
sendStateReducer,
{}
);
const send = useCallback(
(..._args) => {
run(_args)
.on("transactionHash", (transactionHash) =>
dispatch({ type: "transactionHash", transactionHash })
)
.on("confirmation", (confirmation) =>
dispatch({ type: "confirmation", confirmation })
)
.on("receipt", (receipt) => dispatch({ type: "receipt", receipt }))
.on("error", (error) => dispatch({ type: "error", error }));
},
[run, dispatch]
);
const [receipt] = usePromise(
() =>
sendState.transactionHash &&
!sendState.receipt &&
new Promise((resolve) => {
const poll = async () => {
const _receipt = await web3.eth.getTransactionReceipt(
sendState.transactionHash
);
if (_receipt) resolve(_receipt);
else setTimeout(poll, 2000);
};
poll();
}),
[sendState.transactionHash, sendState.receipt, web3]
);
const data = usePromise(() => !isSend && run(), [isSend, run]);

return isSend
? {
receipt,
...sendState,
send,
loading: sendState.transactionHash && !sendState.receipt && !receipt,
}
: data;
}

0 comments on commit 1bab6c5

Please sign in to comment.