Merge pull request #128 from Zil-B/master

Fix AbiMethodView to allow reading/writing to contracts via explorer
pull/138/head
Victa Kwok Wai Phu 3 years ago committed by GitHub
commit 438a737a31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 131
      src/pages/AddressPage/ContractDetails/AbiMethodView.tsx

@ -1,11 +1,11 @@
import { Box, Spinner, Text, TextInput } from "grommet"; import {Box, Spinner, Text, TextInput} from 'grommet';
import React, { useEffect, useState } from "react"; import React, {useEffect, useState} from 'react';
import styled from "styled-components"; import styled from 'styled-components';
import { Button } from "src/components/ui/Button"; import {Button} from 'src/components/ui/Button';
import Web3 from "web3"; import Web3 from 'web3';
import { AbiItem } from "web3-utils"; import {AbiItem} from 'web3-utils';
import { convertInputs } from "./helpers"; import {convertInputs} from './helpers';
import { uniqid } from "src/pages/VerifyContract/VerifyContract"; import {uniqid} from 'src/pages/VerifyContract/VerifyContract';
const Field = styled(Box)``; const Field = styled(Box)``;
@ -36,7 +36,7 @@ export const ActionButton = styled(Button)`
font-weight: 500; font-weight: 500;
`; `;
const GreySpan = styled("span")` const GreySpan = styled('span')`
font-size: 14px; font-size: 14px;
opacity: 0.7; opacity: 0.7;
font-weight: 400; font-weight: 400;
@ -59,21 +59,21 @@ export const AbiMethodsView = (props: {
}) => { }) => {
const {abiMethod, address, index} = props; const {abiMethod, address, index} = props;
const [inputsValue, setInputsValue] = useState<string[]>( const [inputsValue, setInputsValue] = useState<string[]>(
[...new Array(abiMethod.inputs?.length)].map(() => "") [...new Array(abiMethod.inputs?.length)].map(() => '')
); );
const [multipleValue, setMultipleValue] = useState({ const [multipleValue, setMultipleValue] = useState({
write: {}, write: {},
read: {}, read: {},
} as any); } as any);
const [amount, setAmount] = useState(""); const [amount, setAmount] = useState('');
const [error, setError] = useState(""); const [error, setError] = useState('');
const [result, setResult] = useState(""); const [result, setResult] = useState<any[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const query = async () => { const query = async () => {
try { try {
setError(""); setError('');
setResult(""); setResult([]);
setLoading(true); setLoading(true);
// @ts-ignore // @ts-ignore
@ -92,7 +92,7 @@ export const AbiMethodsView = (props: {
if (abiMethod.name) { if (abiMethod.name) {
let res; let res;
if (abiMethod.stateMutability === "view") { if (abiMethod.stateMutability === 'view') {
res = await contract.methods[abiMethod.name] res = await contract.methods[abiMethod.name]
.apply(contract, convertInputs(inputsValue, abiMethod.inputs || [])) .apply(contract, convertInputs(inputsValue, abiMethod.inputs || []))
.call(); .call();
@ -100,7 +100,7 @@ export const AbiMethodsView = (props: {
// @ts-ignore // @ts-ignore
const accounts = await ethereum.enable(); const accounts = await ethereum.enable();
const account = accounts[0] || web3.eth.defaultAccount; const account = accounts[0] || undefined; // if function is not a view method it will require a signer
res = await contract.methods[abiMethod.name] res = await contract.methods[abiMethod.name]
.apply(contract, convertInputs(inputsValue, abiMethod.inputs || [])) .apply(contract, convertInputs(inputsValue, abiMethod.inputs || []))
@ -112,7 +112,13 @@ export const AbiMethodsView = (props: {
}); });
} }
setResult(typeof res === "object" ? res.status.toString() : res); setResult(
Array.isArray(res)
? res
: typeof res === 'object'
? Object.values(res)
: [res.toString()]
);
} }
} catch (e) { } catch (e) {
// @ts-ignore // @ts-ignore
@ -124,7 +130,7 @@ export const AbiMethodsView = (props: {
useEffect(() => { useEffect(() => {
if ( if (
abiMethod.stateMutability !== "payable" && abiMethod.stateMutability !== 'payable' &&
(!abiMethod.inputs || !abiMethod.inputs.length) && (!abiMethod.inputs || !abiMethod.inputs.length) &&
props.isRead props.isRead
) { ) {
@ -138,17 +144,17 @@ export const AbiMethodsView = (props: {
}; };
return ( return (
<ViewWrapper direction="column" margin={{ bottom: "medium" }}> <ViewWrapper direction='column' margin={{bottom: 'medium'}}>
<NameWrapper background={"backgroundBack"}> <NameWrapper background={'backgroundBack'}>
<Text size="small"> <Text size='small'>
{index + 1}. {abiMethod.name} {index + 1}. {abiMethod.name}
</Text> </Text>
</NameWrapper> </NameWrapper>
<Box pad="20px"> <Box pad='20px'>
{abiMethod.stateMutability === "payable" ? ( {abiMethod.stateMutability === 'payable' ? (
<Field gap="5px"> <Field gap='5px'>
<Text size="small"> <Text size='small'>
payableAmount <span>ONE</span> payableAmount <span>ONE</span>
</Text> </Text>
<SmallTextInput <SmallTextInput
@ -161,37 +167,33 @@ export const AbiMethodsView = (props: {
</Field> </Field>
) : null} ) : null}
{abiMethod.inputs && abiMethod.inputs.length ? ( {abiMethod.inputs && abiMethod.inputs.length ? (
<Box gap="12px"> <Box gap='12px'>
{abiMethod.inputs.map((input, idx) => { {abiMethod.inputs.map((input, idx) => {
const name = input.name || "<input>"; const name = input.name || '<input>';
const isArrayValue = input.type.indexOf("[]") >= 0; const isArrayValue = input.type.indexOf('[]') >= 0;
const tabMethod = props.isRead ? "read" : "write"; const tabMethod = props.isRead ? 'read' : 'write';
const itemValue = isArrayValue const itemValue = isArrayValue
? multipleValue[tabMethod][idx] || [{ value: "", id: "1" }] ? multipleValue[tabMethod][idx] || [{value: '', id: '1'}]
: inputsValue[idx]; : inputsValue[idx];
const itemType = input.type.slice(0, input.type.indexOf("[]")); const itemType = input.type.slice(0, input.type.indexOf('[]'));
return ( return (
<Field gap="5px"> <Field gap='5px'>
<Text size="small"> <Text size='small'>
{name} <span>({input.type})</span> {name} <span>({input.type})</span>
</Text> </Text>
{isArrayValue ? ( {isArrayValue ? (
<Box direction={"column"}> <Box direction={'column'}>
{itemValue.map( {itemValue.map(
( (item: {id: string; value: string}, itemId: number) => {
item: { id: string; value: string },
itemId: number
) => {
return ( return (
<Box <Box
direction={"row"} direction={'row'}
align={"center"} align={'center'}
margin={"small"} margin={'small'}>
> <Text style={{marginRight: '10px'}}>
<Text style={{ marginRight: "10px" }}>
{itemId}. {itemId}.
</Text> </Text>
<SmallTextInput <SmallTextInput
@ -220,7 +222,7 @@ export const AbiMethodsView = (props: {
/> />
{itemValue.length === 1 ? null : ( {itemValue.length === 1 ? null : (
<ActionButton <ActionButton
style={{ marginLeft: "10px" }} style={{marginLeft: '10px'}}
onClick={() => { onClick={() => {
setMultipleValue({ setMultipleValue({
...multipleValue, ...multipleValue,
@ -232,8 +234,7 @@ export const AbiMethodsView = (props: {
), ),
}, },
}); });
}} }}>
>
remove remove
</ActionButton> </ActionButton>
)} )}
@ -242,9 +243,9 @@ export const AbiMethodsView = (props: {
} }
)} )}
<ActionButton <ActionButton
style={{ marginTop: "10px" }} style={{marginTop: '10px'}}
onClick={() => { onClick={() => {
itemValue.push({ value: "", id: uniqid() }); itemValue.push({value: '', id: uniqid()});
setMultipleValue({ setMultipleValue({
...multipleValue, ...multipleValue,
@ -253,8 +254,7 @@ export const AbiMethodsView = (props: {
[idx]: itemValue, [idx]: itemValue,
}, },
}); });
}} }}>
>
+ add one more + add one more
</ActionButton> </ActionButton>
</Box> </Box>
@ -274,16 +274,15 @@ export const AbiMethodsView = (props: {
) : null} ) : null}
{!result || abiMethod.inputs?.length ? ( {!result || abiMethod.inputs?.length ? (
<Box width="100px" margin={{ top: "20px", bottom: "18px" }}> <Box width='100px' margin={{top: '20px', bottom: '18px'}}>
{loading ? ( {loading ? (
<Spinner /> <Spinner />
) : abiMethod.stateMutability === "view" ? ( ) : abiMethod.stateMutability === 'view' ? (
<ActionButton onClick={query}>Query</ActionButton> <ActionButton onClick={query}>Query</ActionButton>
) : ( ) : (
<ActionButton <ActionButton
disabled={!props.metamaskAddress || !props.validChainId} disabled={!props.metamaskAddress || !props.validChainId}
onClick={query} onClick={query}>
>
Write Write
</ActionButton> </ActionButton>
)} )}
@ -294,14 +293,22 @@ export const AbiMethodsView = (props: {
? abiMethod.outputs.map((input) => { ? abiMethod.outputs.map((input) => {
return ( return (
<Box> <Box>
{result ? ( {result.length ? (
<Text size="small"> <Text size='small'>
{result} <GreySpan>{input.type}</GreySpan> <GreySpan>
{input.name}
{` (${input.type})`}
</GreySpan>{' '}
{'-> '}
{result.length === 1 ? [result] : result.toString()}
</Text> </Text>
) : ( ) : (
<Text size="small"> <Text size='small'>
{"-> "} <GreySpan>
{input.type} {input.name}
{` (${input.type})`}
</GreySpan>{' '}
{'-> '}
</Text> </Text>
)} )}
</Box> </Box>
@ -310,7 +317,7 @@ export const AbiMethodsView = (props: {
: null} : null}
{error && ( {error && (
<Text color="red" size="small" style={{ marginTop: 5 }}> <Text color='red' size='small' style={{marginTop: 5}}>
{error} {error}
</Text> </Text>
)} )}

Loading…
Cancel
Save