Commit 88abf613 authored by tom's avatar tom

int validation

parent 7b5101df
......@@ -97,6 +97,8 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
.map(castFieldValue(inputs))
.map(([ , value ]) => value);
return;
setResult(undefined);
setLoading(true);
......@@ -131,7 +133,7 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
const fieldName = getFieldName(name, index);
return (
<ContractMethodField
key={ fieldName }
key={ index }
name={ fieldName }
valueType={ type }
placeholder={ `${ name }(${ type })` }
......
......@@ -8,6 +8,7 @@ import {
import React from 'react';
import type { Control, ControllerRenderProps, UseFormGetValues, UseFormSetValue, UseFormStateReturn } from 'react-hook-form';
import { Controller } from 'react-hook-form';
import { NumericFormat } from 'react-number-format';
import { isAddress } from 'viem';
import type { MethodFormFields } from './types';
......@@ -16,7 +17,7 @@ import type { SmartContractMethodArgType } from 'types/api/contract';
import ClearButton from 'ui/shared/ClearButton';
import ContractMethodFieldZeroes from './ContractMethodFieldZeroes';
import { addZeroesAllowed } from './utils';
import { INT_REGEXP, getIntBoundaries } from './utils';
interface Props {
control: Control<MethodFormFields>;
......@@ -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<MethodFormFields>; formState: UseFormStateReturn<MethodFormFields> },
) => {
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 (
<Box>
......@@ -64,6 +77,12 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue,
<InputGroup size="xs">
<Input
{ ...field }
{ ...(intMatch ? {
as: NumericFormat,
thousandSeparator: ' ',
decimalScale: 0,
allowNegative: !intMatch.isUnsigned,
} : {}) }
ref={ ref }
isInvalid={ Boolean(error) }
required
......@@ -80,18 +99,31 @@ const ContractMethodField = ({ control, name, valueType, placeholder, setValue,
{ error && <Box color="error" fontSize="sm" mt={ 1 }>{ error.message }</Box> }
</Box>
);
}, [ 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 (
<>
......
......@@ -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<unknown>) => {
const _value = Array.isArray(value) ? value[0] : value;
......@@ -12,24 +21,6 @@ export const getNativeCoinValue = (value: string | Array<unknown>) => {
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;
......
......@@ -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"
......
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