From e4c382c8f707999a6b8f0c16cfa53cffce4f2056 Mon Sep 17 00:00:00 2001 From: tom Date: Wed, 6 Dec 2023 18:28:30 +0400 Subject: [PATCH 01/16] update form layout and button styling --- .../contract/ContractMethodCallable.tsx | 14 +++++----- ui/address/contract/ContractMethodField.tsx | 28 +++++++++++++------ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/ui/address/contract/ContractMethodCallable.tsx b/ui/address/contract/ContractMethodCallable.tsx index f08a908088..5235437340 100644 --- a/ui/address/contract/ContractMethodCallable.tsx +++ b/ui/address/contract/ContractMethodCallable.tsx @@ -119,13 +119,11 @@ const ContractMethodCallable = ({ data, onSubmit, { inputs.map(({ type, name }, index) => { @@ -146,13 +144,15 @@ const ContractMethodCallable = ({ data, onSubmit, }) } { 'outputs' in data && !isWrite && data.outputs.length > 0 && ( diff --git a/ui/address/contract/ContractMethodField.tsx b/ui/address/contract/ContractMethodField.tsx index d85deeaebb..ab93abef70 100644 --- a/ui/address/contract/ContractMethodField.tsx +++ b/ui/address/contract/ContractMethodField.tsx @@ -1,4 +1,5 @@ import { + Box, FormControl, Input, InputGroup, @@ -50,9 +51,8 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, return ( @@ -61,6 +61,7 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, ref={ ref } placeholder={ placeholder } paddingRight={ hasZerosControl ? '120px' : '40px' } + autoComplete="off" /> { field.value && } @@ -72,12 +73,21 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, }, [ name, isDisabled, placeholder, hasZerosControl, handleClear, handleAddZeroesClick ]); return ( - - + <> + + { name } ({ valueType }) + + + ); }; From 7b5101dfed0304f68fb10caec748abb78460c29c Mon Sep 17 00:00:00 2001 From: tom Date: Wed, 6 Dec 2023 19:12:26 +0400 Subject: [PATCH 02/16] address type validation --- .../contract/ContractMethodCallable.tsx | 1 + ui/address/contract/ContractMethodField.tsx | 66 ++++++++++++------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/ui/address/contract/ContractMethodCallable.tsx b/ui/address/contract/ContractMethodCallable.tsx index 5235437340..0b9a8e6842 100644 --- a/ui/address/contract/ContractMethodCallable.tsx +++ b/ui/address/contract/ContractMethodCallable.tsx @@ -80,6 +80,7 @@ const ContractMethodCallable = ({ data, onSubmit, const { control, handleSubmit, setValue, getValues } = useForm({ defaultValues: _fromPairs(inputs.map(({ name }, index) => [ getFieldName(name, index), '' ])), + mode: 'onBlur', }); const handleTxSettle = React.useCallback(() => { diff --git a/ui/address/contract/ContractMethodField.tsx b/ui/address/contract/ContractMethodField.tsx index ab93abef70..15cc89d3b4 100644 --- a/ui/address/contract/ContractMethodField.tsx +++ b/ui/address/contract/ContractMethodField.tsx @@ -6,8 +6,9 @@ import { InputRightElement, } from '@chakra-ui/react'; import React from 'react'; -import type { Control, ControllerRenderProps, UseFormGetValues, UseFormSetValue } from 'react-hook-form'; +import type { Control, ControllerRenderProps, UseFormGetValues, UseFormSetValue, UseFormStateReturn } from 'react-hook-form'; import { Controller } from 'react-hook-form'; +import { isAddress } from 'viem'; import type { MethodFormFields } from './types'; import type { SmartContractMethodArgType } from 'types/api/contract'; @@ -47,31 +48,51 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, const hasZerosControl = addZeroesAllowed(valueType); - const renderInput = React.useCallback(({ field }: { field: ControllerRenderProps }) => { + const renderInput = React.useCallback(( + { field, formState }: { field: ControllerRenderProps; formState: UseFormStateReturn }, + ) => { + const error = formState.errors[name]; + return ( - - - - - { field.value && } - { hasZerosControl && } - - - + + + + + + { field.value && } + { hasZerosControl && } + + + + { error && { error.message } } + ); }, [ name, isDisabled, placeholder, hasZerosControl, handleClear, handleAddZeroesClick ]); + const validate = React.useCallback((value: string) => { + switch (valueType) { + case 'address': { + return !isAddress(value) ? 'Invalid address format' : true; + } + + default: + return; + } + }, [ valueType ]); + return ( <> ); From 88abf61305299ddd7c917172356f51c7de043b69 Mon Sep 17 00:00:00 2001 From: tom Date: Thu, 7 Dec 2023 16:11:04 +0400 Subject: [PATCH 03/16] int validation --- package.json | 1 + .../contract/ContractMethodCallable.tsx | 4 +- ui/address/contract/ContractMethodField.tsx | 50 +++++++++++++++---- ui/address/contract/utils.ts | 27 ++++------ yarn.lock | 7 +++ 5 files changed, 61 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index 918c4419f3..de7acecfc4 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "react-identicons": "^1.2.5", "react-intersection-observer": "^9.5.2", "react-jazzicon": "^1.0.4", + "react-number-format": "^5.3.1", "react-scroll": "^1.8.7", "swagger-ui-react": "^5.9.0", "use-font-face-observer": "^1.2.1", diff --git a/ui/address/contract/ContractMethodCallable.tsx b/ui/address/contract/ContractMethodCallable.tsx index 0b9a8e6842..5d47763470 100644 --- a/ui/address/contract/ContractMethodCallable.tsx +++ b/ui/address/contract/ContractMethodCallable.tsx @@ -97,6 +97,8 @@ const ContractMethodCallable = ({ data, onSubmit, .map(castFieldValue(inputs)) .map(([ , value ]) => value); + return; + setResult(undefined); setLoading(true); @@ -131,7 +133,7 @@ const ContractMethodCallable = ({ data, onSubmit, const fieldName = getFieldName(name, index); return ( ; @@ -46,12 +47,24 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, onChange(); }, [ getValues, name, onChange, setValue ]); - const hasZerosControl = addZeroesAllowed(valueType); + const intMatch = React.useMemo(() => { + const match = valueType.match(INT_REGEXP); + if (!match) { + return null; + } + + const [ , isUnsigned, power = '256' ] = match; + const [ min, max ] = getIntBoundaries(Number(power), Boolean(isUnsigned)); + + return { isUnsigned, power, min, max }; + }, [ valueType ]); const renderInput = React.useCallback(( { field, formState }: { field: ControllerRenderProps; formState: UseFormStateReturn }, ) => { const error = formState.errors[name]; + // show control for all inputs which allows to insert 10^18 or greater numbers + const hasZerosControl = intMatch && Number(intMatch.power) >= 64; return ( @@ -64,6 +77,12 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, { error.message } } ); - }, [ name, isDisabled, placeholder, hasZerosControl, handleClear, handleAddZeroesClick ]); + }, [ name, intMatch, isDisabled, placeholder, handleClear, handleAddZeroesClick ]); const validate = React.useCallback((value: string) => { - switch (valueType) { - case 'address': { - return !isAddress(value) ? 'Invalid address format' : true; + if (valueType === 'address') { + return !isAddress(value) ? 'Invalid address format' : true; + } + + if (intMatch) { + const formattedValue = Number(value.replace(/\s/g, '')); + + if (Object.is(formattedValue, NaN)) { + return 'Invalid integer format'; + } + + if (formattedValue > intMatch.max || formattedValue < intMatch.min) { + const lowerBoundary = intMatch.isUnsigned ? '0' : `-1 * 2 ^ ${ Number(intMatch.power) / 2 }`; + const upperBoundary = intMatch.isUnsigned ? `2 ^ ${ intMatch.power } - 1` : `2^${ Number(intMatch.power) / 2 } - 1`; + return `Value should be in range from "${ lowerBoundary }" to "${ upperBoundary }" inclusively`; } - default: - return; + return true; } - }, [ valueType ]); + + return true; + }, [ intMatch, valueType ]); return ( <> diff --git a/ui/address/contract/utils.ts b/ui/address/contract/utils.ts index c0b01b6c94..998951956a 100644 --- a/ui/address/contract/utils.ts +++ b/ui/address/contract/utils.ts @@ -2,6 +2,15 @@ import type { Abi } from 'abitype'; import type { SmartContractWriteMethod } from 'types/api/contract'; +export const INT_REGEXP = /^(u)?int(\d+)?$/i; + +export const getIntBoundaries = (power: number, isUnsigned: boolean) => { + const maxUnsigned = 2 ** power; + const max = isUnsigned ? maxUnsigned - 1 : maxUnsigned / 2 - 1; + const min = isUnsigned ? 0 : -maxUnsigned / 2; + return [ min, max ]; +}; + export const getNativeCoinValue = (value: string | Array) => { const _value = Array.isArray(value) ? value[0] : value; @@ -12,24 +21,6 @@ export const getNativeCoinValue = (value: string | Array) => { return BigInt(_value); }; -export const addZeroesAllowed = (valueType: string) => { - if (valueType.includes('[')) { - return false; - } - - const REGEXP = /^u?int(\d+)/i; - - const match = valueType.match(REGEXP); - const power = match?.[1]; - - if (power) { - // show control for all inputs which allows to insert 10^18 or greater numbers - return Number(power) >= 64; - } - - return false; -}; - interface ExtendedError extends Error { detectedNetwork?: { chain: number; diff --git a/yarn.lock b/yarn.lock index d6fc51bce7..b441261c1b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12704,6 +12704,13 @@ react-jazzicon@^1.0.4: dependencies: mersenne-twister "^1.1.0" +react-number-format@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.3.1.tgz#840c257da9cb4b248990d8db46e4d23e8bac67ff" + integrity sha512-qpYcQLauIeEhCZUZY9jXZnnroOtdy3jYaS1zQ3M1Sr6r/KMOBEIGNIb7eKT19g2N1wbYgFgvDzs19hw5TrB8XQ== + dependencies: + prop-types "^15.7.2" + react-redux@^8.1.2: version "8.1.3" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.3.tgz#4fdc0462d0acb59af29a13c27ffef6f49ab4df46" From 4f799da127587b87f52d59aac12b58a11ab6dd23 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 8 Dec 2023 08:33:13 +0400 Subject: [PATCH 04/16] bool validation --- ui/address/contract/ContractMethodField.tsx | 9 ++++++++- ui/address/contract/utils.ts | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/ui/address/contract/ContractMethodField.tsx b/ui/address/contract/ContractMethodField.tsx index 7deb69e6c3..5001979b94 100644 --- a/ui/address/contract/ContractMethodField.tsx +++ b/ui/address/contract/ContractMethodField.tsx @@ -17,7 +17,7 @@ import type { SmartContractMethodArgType } from 'types/api/contract'; import ClearButton from 'ui/shared/ClearButton'; import ContractMethodFieldZeroes from './ContractMethodFieldZeroes'; -import { INT_REGEXP, getIntBoundaries } from './utils'; +import { INT_REGEXP, getIntBoundaries, formatBooleanValue } from './utils'; interface Props { control: Control; @@ -122,6 +122,13 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, return true; } + if (valueType === 'bool') { + const formattedValue = formatBooleanValue(value); + if (formattedValue === undefined) { + return 'Invalid boolean format. Allowed values: 0, 1, true, false'; + } + } + return true; }, [ intMatch, valueType ]); diff --git a/ui/address/contract/utils.ts b/ui/address/contract/utils.ts index 998951956a..5b71eb2d96 100644 --- a/ui/address/contract/utils.ts +++ b/ui/address/contract/utils.ts @@ -11,6 +11,25 @@ export const getIntBoundaries = (power: number, isUnsigned: boolean) => { return [ min, max ]; }; +export const formatBooleanValue = (value: string) => { + const formattedValue = value.toLowerCase(); + + switch (formattedValue) { + case 'true': + case '1': { + return 'true'; + } + + case 'false': + case '0': { + return 'false'; + } + + default: + return; + } +}; + export const getNativeCoinValue = (value: string | Array) => { const _value = Array.isArray(value) ? value[0] : value; From 5ffd2a62a983c85fca994e6a82d4264ab955d1c4 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 8 Dec 2023 09:11:52 +0400 Subject: [PATCH 05/16] bytes validation --- lib/stringToBytes.tsx | 4 ++++ ui/address/contract/ContractMethodField.tsx | 26 +++++++++++++++++++-- ui/address/contract/utils.ts | 2 ++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 lib/stringToBytes.tsx diff --git a/lib/stringToBytes.tsx b/lib/stringToBytes.tsx new file mode 100644 index 0000000000..6491b3b0d7 --- /dev/null +++ b/lib/stringToBytes.tsx @@ -0,0 +1,4 @@ +export default function stringToBytes(str: string) { + const utf8Encode = new TextEncoder(); + return utf8Encode.encode(str); +} diff --git a/ui/address/contract/ContractMethodField.tsx b/ui/address/contract/ContractMethodField.tsx index 5001979b94..cdfaa9a0d0 100644 --- a/ui/address/contract/ContractMethodField.tsx +++ b/ui/address/contract/ContractMethodField.tsx @@ -14,10 +14,11 @@ import { isAddress } from 'viem'; import type { MethodFormFields } from './types'; import type { SmartContractMethodArgType } from 'types/api/contract'; +import stringToBytes from 'lib/stringToBytes'; import ClearButton from 'ui/shared/ClearButton'; import ContractMethodFieldZeroes from './ContractMethodFieldZeroes'; -import { INT_REGEXP, getIntBoundaries, formatBooleanValue } from './utils'; +import { INT_REGEXP, BYTES_REGEXP, getIntBoundaries, formatBooleanValue } from './utils'; interface Props { control: Control; @@ -59,6 +60,10 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, return { isUnsigned, power, min, max }; }, [ valueType ]); + const bytesMatch = React.useMemo(() => { + return valueType.match(BYTES_REGEXP); + }, [ valueType ]); + const renderInput = React.useCallback(( { field, formState }: { field: ControllerRenderProps; formState: UseFormStateReturn }, ) => { @@ -129,8 +134,25 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue, } } + if (bytesMatch) { + const [ , length ] = bytesMatch; + + if (value.startsWith('0x')) { + if (value.replace('0x', '').length % 2 !== 0) { + return 'Invalid bytes format'; + } + } + + if (length) { + const valueLengthInBytes = value.startsWith('0x') ? value.replace('0x', '').length / 2 : stringToBytes(value).length; + return valueLengthInBytes > Number(length) ? `Value should be a maximum of ${ length } bytes` : true; + } + + return true; + } + return true; - }, [ intMatch, valueType ]); + }, [ bytesMatch, intMatch, valueType ]); return ( <> diff --git a/ui/address/contract/utils.ts b/ui/address/contract/utils.ts index 5b71eb2d96..bc46a55a18 100644 --- a/ui/address/contract/utils.ts +++ b/ui/address/contract/utils.ts @@ -4,6 +4,8 @@ import type { SmartContractWriteMethod } from 'types/api/contract'; export const INT_REGEXP = /^(u)?int(\d+)?$/i; +export const BYTES_REGEXP = /^bytes(\d+)?$/i; + export const getIntBoundaries = (power: number, isUnsigned: boolean) => { const maxUnsigned = 2 ** power; const max = isUnsigned ? maxUnsigned - 1 : maxUnsigned / 2 - 1; From a8448fefed06ba1d1914b1f841be6428123fc39d Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 8 Dec 2023 13:43:58 +0400 Subject: [PATCH 06/16] array fields, first iteration --- .../contract/ContractMethodCallable.tsx | 48 ++++++++-- ui/address/contract/ContractMethodField.tsx | 54 +++++------ .../contract/ContractMethodFieldArray.tsx | 96 +++++++++++++++++++ ui/address/contract/types.ts | 2 +- ui/address/contract/utils.ts | 2 + 5 files changed, 165 insertions(+), 37 deletions(-) create mode 100644 ui/address/contract/ContractMethodFieldArray.tsx diff --git a/ui/address/contract/ContractMethodCallable.tsx b/ui/address/contract/ContractMethodCallable.tsx index 5d47763470..48a5593ee7 100644 --- a/ui/address/contract/ContractMethodCallable.tsx +++ b/ui/address/contract/ContractMethodCallable.tsx @@ -5,12 +5,14 @@ import type { SubmitHandler } from 'react-hook-form'; import { useForm } from 'react-hook-form'; import type { MethodFormFields, ContractMethodCallResult } from './types'; -import type { SmartContractMethodInput, SmartContractMethod } from 'types/api/contract'; +import type { SmartContractMethodInput, SmartContractMethod, SmartContractMethodArgType } from 'types/api/contract'; import arrowIcon from 'icons/arrows/down-right.svg'; import * as mixpanel from 'lib/mixpanel/index'; import ContractMethodField from './ContractMethodField'; +import ContractMethodFieldArray from './ContractMethodFieldArray'; +import { ARRAY_REGEXP } from './utils'; interface ResultComponentProps { item: T; @@ -27,7 +29,10 @@ interface Props { const getFieldName = (name: string | undefined, index: number): string => name || String(index); -const sortFields = (data: Array) => ([ a ]: [string, string], [ b ]: [string, string]): 1 | -1 | 0 => { +const sortFields = (data: Array) => ( + [ a ]: [string, string | Array], + [ b ]: [string, string | Array], +): 1 | -1 | 0 => { const fieldNames = data.map(({ name }, index) => getFieldName(name, index)); const indexA = fieldNames.indexOf(a); const indexB = fieldNames.indexOf(b); @@ -43,15 +48,19 @@ const sortFields = (data: Array) => ([ a ]: [string, s return 0; }; -const castFieldValue = (data: Array) => ([ key, value ]: [ string, string ], index: number) => { +const castFieldValue = (data: Array) => ([ key, value ]: [ string, string | Array ], index: number) => { if (data[index].type.includes('[')) { return [ key, parseArrayValue(value) ]; } return [ key, value ]; }; -const parseArrayValue = (value: string) => { +const parseArrayValue = (value: string | Array) => { try { + if (Array.isArray(value)) { + return value; + } + const parsedResult = JSON.parse(value); if (Array.isArray(parsedResult)) { return parsedResult; @@ -97,8 +106,6 @@ const ContractMethodCallable = ({ data, onSubmit, .map(castFieldValue(inputs)) .map(([ , value ]) => value); - return; - setResult(undefined); setLoading(true); @@ -131,9 +138,20 @@ const ContractMethodCallable = ({ data, onSubmit, > { inputs.map(({ type, name }, index) => { const fieldName = getFieldName(name, index); - return ( + const arrayTypeMatch = type.match(ARRAY_REGEXP); + const content = arrayTypeMatch ? ( + + ) : ( ({ data, onSubmit, onChange={ handleFormChange } /> ); + + return ( + + + { name } ({ type }) + + { content } + + ); }) } - + { inputs.map((input, index) => { + const fieldName = getFormFieldName(input.name, index); + + if (input.type === 'tuple' && input.components) { + return ( + + { index !== 0 && <>
} + + { input.name } ({ input.type }) + +
+ { input.components.map((component, componentIndex) => { + const fieldName = getFormFieldName(component.name, componentIndex, input.name); + + return ( + + ); + }) } + { index !== inputs.length - 1 && <>
} + + ); + } + + return ( + + ); + }) } +
+ + + { 'outputs' in data && !isWrite && data.outputs.length > 0 && ( diff --git a/ui/address/contract/ContractMethodCallableRow.tsx b/ui/address/contract/ContractMethodCallableRow.tsx new file mode 100644 index 0000000000..f88f63ed1d --- /dev/null +++ b/ui/address/contract/ContractMethodCallableRow.tsx @@ -0,0 +1,66 @@ +import { Box } from '@chakra-ui/react'; +import React from 'react'; +import { useFormContext } from 'react-hook-form'; + +import type { MethodFormFields } from './types'; +import type { SmartContractMethodArgType } from 'types/api/contract'; + +import ContractMethodField from './ContractMethodField'; +import ContractMethodFieldArray from './ContractMethodFieldArray'; +import { ARRAY_REGEXP } from './utils'; + +interface Props { + fieldName: string; + argName: string; + argType: SmartContractMethodArgType; + onChange: () => void; + isDisabled: boolean; + isGrouped?: boolean; +} + +const ContractMethodCallableRow = ({ argName, fieldName, argType, onChange, isDisabled, isGrouped }: Props) => { + const { control, getValues, setValue } = useFormContext(); + const arrayTypeMatch = argType.match(ARRAY_REGEXP); + + const content = arrayTypeMatch ? ( + + ) : ( + + ); + + return ( + <> + + { argName } ({ argType }) + + { content } + + ); +}; + +export default React.memo(ContractMethodCallableRow); diff --git a/ui/address/contract/ContractMethodField.tsx b/ui/address/contract/ContractMethodField.tsx index 6f13e99417..19c2d6bd8a 100644 --- a/ui/address/contract/ContractMethodField.tsx +++ b/ui/address/contract/ContractMethodField.tsx @@ -25,7 +25,7 @@ interface Props { index?: number; groupName?: string; placeholder: string; - valueType: SmartContractMethodArgType; + argType: SmartContractMethodArgType; control: Control; setValue: UseFormSetValue; getValues: UseFormGetValues; @@ -33,7 +33,7 @@ interface Props { onChange: () => void; } -const ContractMethodField = ({ control, name, groupName, index, valueType, placeholder, setValue, getValues, isDisabled, onChange }: Props) => { +const ContractMethodField = ({ control, name, groupName, index, argType, placeholder, setValue, getValues, isDisabled, onChange }: Props) => { const ref = React.useRef(null); const handleClear = React.useCallback(() => { @@ -51,7 +51,7 @@ const ContractMethodField = ({ control, name, groupName, index, valueType, place }, [ getValues, groupName, index, name, onChange, setValue ]); const intMatch = React.useMemo(() => { - const match = valueType.match(INT_REGEXP); + const match = argType.match(INT_REGEXP); if (!match) { return null; } @@ -60,11 +60,11 @@ const ContractMethodField = ({ control, name, groupName, index, valueType, place const [ min, max ] = getIntBoundaries(Number(power), Boolean(isUnsigned)); return { isUnsigned, power, min, max }; - }, [ valueType ]); + }, [ argType ]); const bytesMatch = React.useMemo(() => { - return valueType.match(BYTES_REGEXP); - }, [ valueType ]); + return argType.match(BYTES_REGEXP); + }, [ argType ]); const renderInput = React.useCallback(( { field, formState }: { field: ControllerRenderProps; formState: UseFormStateReturn }, @@ -111,11 +111,11 @@ const ContractMethodField = ({ control, name, groupName, index, valueType, place }, [ index, groupName, name, intMatch, isDisabled, placeholder, handleClear, handleAddZeroesClick ]); const validate = React.useCallback((value: string | Array) => { - if (typeof value === 'object') { + if (typeof value === 'object' || !value) { return; } - if (valueType === 'address') { + if (argType === 'address') { return !isAddress(value) ? 'Invalid address format' : true; } @@ -135,7 +135,7 @@ const ContractMethodField = ({ control, name, groupName, index, valueType, place return true; } - if (valueType === 'bool') { + if (argType === 'bool') { const formattedValue = formatBooleanValue(value); if (formattedValue === undefined) { return 'Invalid boolean format. Allowed values: 0, 1, true, false'; @@ -160,7 +160,7 @@ const ContractMethodField = ({ control, name, groupName, index, valueType, place } return true; - }, [ bytesMatch, intMatch, valueType ]); + }, [ bytesMatch, intMatch, argType ]); return ( ; setValue: UseFormSetValue; getValues: UseFormGetValues; @@ -22,7 +22,7 @@ interface Props { onChange: () => void; } -const ContractMethodFieldArray = ({ control, name, setValue, getValues, isDisabled, valueType, onChange }: Props) => { +const ContractMethodFieldArray = ({ control, name, setValue, getValues, isDisabled, argType, onChange }: Props) => { const { fields, append, remove } = useFieldArray({ name: name as never, control, @@ -52,8 +52,8 @@ const ContractMethodFieldArray = ({ control, name, setValue, getValues, isDisabl name={ `${ name }[${ index }]` } groupName={ name } index={ index } - valueType={ valueType } - placeholder={ valueType } + argType={ argType } + placeholder={ argType } control={ control } setValue={ setValue } getValues={ getValues } From 01e266dff36592758c887f99f1896940bcb797f8 Mon Sep 17 00:00:00 2001 From: tom Date: Tue, 12 Dec 2023 14:45:03 +0400 Subject: [PATCH 08/16] update format for call output --- theme/components/Alert/Alert.ts | 2 +- .../contract/ContractMethodCallable.tsx | 109 +++++++++--------- .../contract/ContractMethodsAccordionItem.tsx | 2 +- .../contract/ContractWriteResultDumb.tsx | 1 - 4 files changed, 58 insertions(+), 56 deletions(-) diff --git a/theme/components/Alert/Alert.ts b/theme/components/Alert/Alert.ts index 2360b71a52..c8dfa125b1 100644 --- a/theme/components/Alert/Alert.ts +++ b/theme/components/Alert/Alert.ts @@ -13,7 +13,7 @@ function getBg(props: StyleFunctionProps) { const { theme, colorScheme: c } = props; const darkBg = transparentize(`${ c }.200`, 0.16)(theme); return { - light: `colors.${ c }.100`, + light: `colors.${ c }.${ c === 'red' ? '50' : '100' }`, dark: darkBg, }; } diff --git a/ui/address/contract/ContractMethodCallable.tsx b/ui/address/contract/ContractMethodCallable.tsx index e422c2b010..b54f6da803 100644 --- a/ui/address/contract/ContractMethodCallable.tsx +++ b/ui/address/contract/ContractMethodCallable.tsx @@ -1,4 +1,4 @@ -import { Box, Button, chakra, Flex, Icon, Text } from '@chakra-ui/react'; +import { Box, Button, chakra, Flex, Grid, Icon, Text } from '@chakra-ui/react'; // import _fromPairs from 'lodash/fromPairs'; import React from 'react'; import type { SubmitHandler } from 'react-hook-form'; @@ -136,62 +136,65 @@ const ContractMethodCallable = ({ data, onSubmit, - { inputs.map((input, index) => { - const fieldName = getFormFieldName(input.name, index); + + { inputs.map((input, index) => { + const fieldName = getFormFieldName(input.name, index); + + if (input.type === 'tuple' && input.components) { + return ( + + { index !== 0 && <>
} + + { input.name } ({ input.type }) + +
+ { input.components.map((component, componentIndex) => { + const fieldName = getFormFieldName(component.name, componentIndex, input.name); + + return ( + + ); + }) } + { index !== inputs.length - 1 && <>
} + + ); + } - if (input.type === 'tuple' && input.components) { return ( - - { index !== 0 && <>
} - - { input.name } ({ input.type }) - -
- { input.components.map((component, componentIndex) => { - const fieldName = getFormFieldName(component.name, componentIndex, input.name); - - return ( - - ); - }) } - { index !== inputs.length - 1 && <>
} - + ); - } - - return ( - - ); - }) } -
+ }) } +