Commit 5d40648d authored by tom's avatar tom

read contract result (mock)

parent db564d7c
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.038 13.692h6.675l-4.147 4.148.832.832 5.568-5.568-5.568-5.568-.832.832 4.147 4.148H8.038A3.832 3.832 0 0 1 4.21 8.687V1.329H3.033v7.36a5.01 5.01 0 0 0 5.005 5.004Z" fill="currentColor"/>
</svg>
......@@ -171,6 +171,9 @@ export const RESOURCES = {
contract_methods_read: {
path: '/api/v2/smart-contracts/:id/methods-read',
},
contract_method_query: {
path: '/api/v2/smart-contracts/:id/query-read-method',
},
// TOKEN
token: {
......
......@@ -11,10 +11,21 @@ import ContractReadItemOutput from './ContractReadItemOutput';
const ContractRead = () => {
const router = useRouter();
const [ expandedSections, setExpandedSections ] = React.useState<Array<number>>([]);
const [ id, setId ] = React.useState(0);
const addressHash = router.query.id?.toString();
const { data, isLoading, isError } = useApiQuery('contract_methods_read', {
pathParams: { id: router.query.id?.toString() },
pathParams: { id: addressHash },
queryOptions: {
enabled: Boolean(router.query.id),
},
});
const contractInfo = useApiQuery('contract', {
pathParams: { id: addressHash },
queryOptions: {
enabled: Boolean(router.query.id),
},
......@@ -36,6 +47,10 @@ const ContractRead = () => {
}
}, [ data, expandedSections.length ]);
const handleReset = React.useCallback(() => {
setId((id) => id + 1);
}, []);
if (isError) {
return <DataFetchAlert/>;
}
......@@ -63,7 +78,15 @@ const ContractRead = () => {
{ item.outputs.map((output, index) => <ContractReadItemOutput key={ index } data={ output }/>) }
</Flex>
) : (
<ContractReadItemInput key={ index } data={ item.inputs }/>
<ContractReadItemInput
key={ id + '_' + index }
data={ item.inputs }
address={ addressHash }
abi={ contractInfo.data?.abi }
methodName={ item.name }
methodId={ item.method_id }
outputs={ item.outputs }
/>
) }
</AccordionPanel>
</AccordionItem>
......@@ -71,7 +94,7 @@ const ContractRead = () => {
}) }
<Flex columnGap={ 3 } position="absolute" top={ 0 } right={ 0 } py={ 3 } lineHeight="27px">
<Link onClick={ handleExpandAll }>{ expandedSections.length === data.length ? 'Collapse' : 'Expand' } all</Link>
<Link>Reset</Link>
<Link onClick={ handleReset }>Reset</Link>
</Flex>
</Accordion>
);
......
import { Button, chakra } from '@chakra-ui/react';
import { Box, Button, chakra, Flex, Icon, Text, useColorModeValue } from '@chakra-ui/react';
import _fromPairs from 'lodash/fromPairs';
import React from 'react';
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import type { MethodInputFields } from './types';
import type { SmartContractMethodInput } from 'types/api/contract';
import type { SmartContract, SmartContractMethodInput, SmartContractMethodOutput } from 'types/api/contract';
import arrowIcon from 'icons/arrows/down-right.svg';
import useApiFetch from 'lib/api/useApiFetch';
import ContractReadItemInputField from './ContractReadItemInputField';
interface Props {
data: Array<SmartContractMethodInput>;
address?: string;
abi?: SmartContract['abi'];
methodName: string;
methodId: string;
outputs: Array<SmartContractMethodOutput>;
}
const ContractReadItemInput = ({ data }: Props) => {
const { control, handleSubmit } = useForm<MethodInputFields>({
defaultValues: _fromPairs(data.map(({ name }, index) => [ name || index, '' ])),
const getFieldName = (name: string, index: number): string => name || String(index);
const sortFields = (data: Array<SmartContractMethodInput>) => ([ a ]: [string, string], [ b ]: [string, string]): 1 | -1 | 0 => {
const fieldNames = data.map(({ name }, index) => getFieldName(name, index));
const indexA = fieldNames.indexOf(a);
const indexB = fieldNames.indexOf(b);
if (indexA > indexB) {
return 1;
}
if (indexA < indexB) {
return -1;
}
return 0;
};
const ContractReadItemInput = ({ data, address, methodId, methodName, outputs }: Props) => {
const { control, handleSubmit, setValue } = useForm<MethodInputFields>({
defaultValues: _fromPairs(data.map(({ name }, index) => [ getFieldName(name, index), '' ])),
});
const apiFetch = useApiFetch();
const [ result, setResult ] = React.useState<Array<[ string, string ]>>([ ]);
const onSubmit: SubmitHandler<MethodInputFields> = React.useCallback(async(formData) => {
if (!address) {
return;
}
const args = Object.entries(formData)
.sort(sortFields(data))
.map(([ , value ]) => value);
// todo_tom delete mock
setResult(outputs.map(({ type }, index) => ([ type, args[index] ])));
await apiFetch('contract_method_query', {
pathParams: { id: address },
fetchParams: {
method: 'POST',
body: {
args,
method_id: methodId,
},
},
});
}, [ address, apiFetch, data, methodId, outputs ]);
const onSubmit: SubmitHandler<MethodInputFields> = React.useCallback((data) => {
// eslint-disable-next-line no-console
console.log('__>__', data);
}, [ ]);
const resultBgColor = useColorModeValue('blackAlpha.50', 'whiteAlpha.50');
return (
<chakra.form
noValidate
display="flex"
columnGap={ 3 }
flexDir={{ base: 'column', lg: 'row' }}
rowGap={ 2 }
alignItems={{ base: 'flex-start', lg: 'center' }}
onSubmit={ handleSubmit(onSubmit) }
>
{ data.map(({ type, name }, index) => {
return (
<ContractReadItemInputField
key={ name || index }
name={ name }
index={ index }
control={ control }
type={ type }
/>
);
}) }
<Button
variant="outline"
size="sm"
flexShrink={ 0 }
type="submit"
<Box>
<chakra.form
noValidate
display="flex"
columnGap={ 3 }
flexDir={{ base: 'column', lg: 'row' }}
rowGap={ 2 }
alignItems={{ base: 'flex-start', lg: 'center' }}
onSubmit={ handleSubmit(onSubmit) }
>
Query
</Button>
</chakra.form>
{ data.map(({ type, name }, index) => {
const fieldName = getFieldName(name, index);
return (
<ContractReadItemInputField
key={ fieldName }
name={ fieldName }
placeholder={ `${ name }(${ type })` }
control={ control }
setValue={ setValue }
/>
);
}) }
<Button
variant="outline"
size="sm"
flexShrink={ 0 }
type="submit"
>
Query
</Button>
</chakra.form>
<Flex mt={ 3 }>
<Icon as={ arrowIcon } boxSize={ 5 } mr={ 1 }/>
<Text>{ outputs.map(({ type }) => type).join(', ') }</Text>
</Flex>
{ result.length > 0 && (
<Box mt={ 3 } p={ 4 } borderRadius="md" bgColor={ resultBgColor } fontSize="sm">
<p>
[ <chakra.span fontWeight={ 600 }>{ methodName }</chakra.span> method Response ]
</p>
<p>[</p>
{ result.map(([ key, value ], index) => (
<chakra.p key={ index } whiteSpace="break-spaces" wordBreak="break-all"> { key }: { value }</chakra.p>
)) }
<p>]</p>
</Box>
) }
</Box>
);
};
......
import { Button, FormControl, Input, InputGroup, InputRightElement } from '@chakra-ui/react';
import { FormControl, Input, InputGroup, InputRightElement } from '@chakra-ui/react';
import React from 'react';
import type { Control, ControllerRenderProps } from 'react-hook-form';
import type { Control, ControllerRenderProps, UseFormSetValue } from 'react-hook-form';
import { Controller } from 'react-hook-form';
import type { MethodInputFields } from './types';
import InputClearButton from 'ui/shared/InputClearButton';
interface Props {
control: Control<MethodInputFields>;
type: string;
setValue: UseFormSetValue<MethodInputFields>;
placeholder: string;
name: string;
index: number;
}
const ContractReadItemInputField = ({ control, name, type, index }: Props) => {
const fieldName = name || String(index);
const renderInput = React.useCallback(({ field }: {field: ControllerRenderProps<MethodInputFields>}) => {
const ContractReadItemInputField = ({ control, name, placeholder, setValue }: Props) => {
const ref = React.useRef<HTMLInputElement>(null);
const handleClear = React.useCallback(() => {
setValue(name, '');
ref.current?.focus();
}, [ name, setValue ]);
const renderInput = React.useCallback(({ field }: { field: ControllerRenderProps<MethodInputFields> }) => {
return (
<FormControl id={ fieldName }>
<InputGroup key={ fieldName } size="xs">
<FormControl id={ name }>
<InputGroup size="xs">
<Input
{ ...field }
placeholder={ `${ name }(${ type })` }
ref={ ref }
placeholder={ placeholder }
/>
<InputRightElement>
<Button size="xs">clear</Button>
<InputClearButton onClick={ handleClear }/>
</InputRightElement>
</InputGroup>
</FormControl>
);
}, [ fieldName, name, type ]);
}, [ handleClear, name, placeholder ]);
return (
<Controller
name={ fieldName }
name={ name }
control={ control }
render={ renderInput }
/>
......
import { Checkbox, Flex } from '@chakra-ui/react';
import { Checkbox, Flex, chakra } from '@chakra-ui/react';
import BigNumber from 'bignumber.js';
import type { ChangeEvent } from 'react';
import React from 'react';
......@@ -13,7 +13,7 @@ interface Props {
}
const ContractReadItemOutput = ({ data }: Props) => {
const isBigInt = data.type.includes('int256');
const isBigInt = data.type.includes('int256') || data.type.includes('int128');
const [ value, setValue ] = React.useState(isBigInt ? BigNumber(data.value).toFixed() : data.value);
const [ label, setLabel ] = React.useState('WEI');
......@@ -28,16 +28,9 @@ const ContractReadItemOutput = ({ data }: Props) => {
}, [ data.value ]);
return (
<Flex>
<span>({ data.type }): { value }</span>
{ isBigInt && (
<Checkbox
ml={ 2 }
onChange={ handleCheckboxChange }
>
{ label }
</Checkbox>
) }
<Flex flexDir={{ base: 'column', lg: 'row' }} columnGap={ 2 } rowGap={ 2 }>
<chakra.span wordBreak="break-all">({ data.type }): { value }</chakra.span>
{ isBigInt && <Checkbox onChange={ handleCheckboxChange }>{ label }</Checkbox> }
</Flex>
);
};
......
......@@ -2170,10 +2170,10 @@
dependencies:
"@ethersproject/logger" "^5.7.0"
"@ethersproject/providers@5.7.1":
version "5.7.1"
resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.1.tgz#b0799b616d5579cd1067a8ebf1fc1ec74c1e122c"
integrity sha512-vZveG/DLyo+wk4Ga1yx6jSEHrLPgmTt+dFv0dv8URpVCRf0jVhalps1jq/emN/oXnMRsC7cQgAF32DcXLL7BPQ==
"@ethersproject/providers@5.7.2":
version "5.7.2"
resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb"
integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==
dependencies:
"@ethersproject/abstract-provider" "^5.7.0"
"@ethersproject/abstract-signer" "^5.7.0"
......@@ -5685,10 +5685,10 @@ eth-rpc-errors@^4.0.2:
dependencies:
fast-safe-stringify "^2.0.6"
ethers@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.1.tgz#48c83a44900b5f006eb2f65d3ba6277047fd4f33"
integrity sha512-5krze4dRLITX7FpU8J4WscXqADiKmyeNlylmmDLbS95DaZpBhDe2YSwRQwKXWNyXcox7a3gBgm/MkGXV1O1S/Q==
ethers@^5.7.2:
version "5.7.2"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e"
integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==
dependencies:
"@ethersproject/abi" "5.7.0"
"@ethersproject/abstract-provider" "5.7.0"
......@@ -5708,7 +5708,7 @@ ethers@^5.7.1:
"@ethersproject/networks" "5.7.1"
"@ethersproject/pbkdf2" "5.7.0"
"@ethersproject/properties" "5.7.0"
"@ethersproject/providers" "5.7.1"
"@ethersproject/providers" "5.7.2"
"@ethersproject/random" "5.7.0"
"@ethersproject/rlp" "5.7.0"
"@ethersproject/sha2" "5.7.0"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment