From 0d59324dec3fd7b5acd048a93669cb4f34f92037 Mon Sep 17 00:00:00 2001 From: Alberto Nicolas Penayo <74352651+bee344@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:51:24 -0300 Subject: [PATCH] fix(bug): user can input invalid lifetime for tx (#10862) * fix lifetime input * updated isLifetime --- packages/react-components/src/InputNumber.tsx | 64 ++++++++++++++----- packages/react-signer/src/SignFields.tsx | 1 + 2 files changed, 49 insertions(+), 16 deletions(-) diff --git a/packages/react-components/src/InputNumber.tsx b/packages/react-components/src/InputNumber.tsx index f0e1f0cd33..cc3032ed92 100644 --- a/packages/react-components/src/InputNumber.tsx +++ b/packages/react-components/src/InputNumber.tsx @@ -24,6 +24,7 @@ interface Props { isDisabled?: boolean; isError?: boolean; isFull?: boolean; + isLifetime?: boolean; isLoading?: boolean; isSi?: boolean; isDecimal?: boolean; @@ -94,13 +95,41 @@ function isValidNumber (bn: BN, bitLength: BitLength, isSigned: boolean, isZeroa return true; } -function inputToBn (api: ApiPromise, input: string, si: SiDef | null, bitLength: BitLength, isSigned: boolean, isZeroable: boolean, maxValue?: BN | null, decimals?: number): [BN, boolean] { +function inputToBn (api: ApiPromise, input: string, si: SiDef | null, bitLength: BitLength, isLifetime: boolean, isSigned: boolean, isZeroable: boolean, maxValue?: BN | null, decimals?: number): [string, BN, boolean] { const [siPower, basePower, siUnitPower] = getSiPowers(si, decimals); // eslint-disable-next-line @typescript-eslint/prefer-regexp-exec const isDecimalValue = input.match(/^(\d+)\.(\d+)$/); let result; + if (isLifetime) { + const maxLifetime = new BN(api.consts.system.blockHashCount); + + if (isDecimalValue) { + if (siUnitPower - isDecimalValue[2].length < -basePower) { + result = new BN(-1); + } + + const div = new BN(input.replace(/\.\d*$/, '')); + const modString = input.replace(/^\d+\./, '').substring(0, api.registry.chainDecimals[0]); + const mod = new BN(modString); + + result = BN.min(div + .mul(BN_TEN.pow(siPower)) + .add(mod.mul(BN_TEN.pow(new BN(basePower + siUnitPower - modString.length)))), maxLifetime); + } else { + result = BN.min(new BN(input.replace(/[^\d]/g, '')) + .mul(BN_TEN.pow(siPower)) + .muln(isSigned && input.startsWith('-') ? -1 : 1), maxLifetime); + } + + return [ + result.toString(), + result, + isValidNumber(result, bitLength, isSigned, isZeroable, maxValue) + ]; + } + if (isDecimalValue) { if (siUnitPower - isDecimalValue[2].length < -basePower) { result = new BN(-1); @@ -120,15 +149,15 @@ function inputToBn (api: ApiPromise, input: string, si: SiDef | null, bitLength: } return [ + result.toString(), result, isValidNumber(result, bitLength, isSigned, isZeroable, maxValue) ]; } -function getValuesFromString (api: ApiPromise, value: string, si: SiDef | null, bitLength: BitLength, isSigned: boolean, isZeroable: boolean, maxValue?: BN | null, decimals?: number): [string, BN, boolean] { +function getValuesFromString (api: ApiPromise, value: string, si: SiDef | null, bitLength: BitLength, isLifetime: boolean, isSigned: boolean, isZeroable: boolean, maxValue?: BN | null, decimals?: number): [string, BN, boolean] { return [ - value, - ...inputToBn(api, value, si, bitLength, isSigned, isZeroable, maxValue, decimals) + ...inputToBn(api, value, si, bitLength, isLifetime, isSigned, isZeroable, maxValue, decimals) ]; } @@ -142,19 +171,18 @@ function getValuesFromBn (valueBn: BN, si: SiDef | null, isSigned: boolean, isZe ? valueBn.div(BN_TEN.pow(new BN(decimals + si.power))).toString() : valueBn.toString(), valueBn, - isZeroable || isSigned - ? true - : valueBn.gt(BN_ZERO) + isZeroable || isSigned ? true : valueBn.gt(BN_ZERO) + ]; } -function getValues (api: ApiPromise, value: BN | string = BN_ZERO, si: SiDef | null, bitLength: BitLength, isSigned: boolean, isZeroable: boolean, maxValue?: BN | null, decimals?: number): [string, BN, boolean] { +function getValues (api: ApiPromise, value: BN | string = BN_ZERO, si: SiDef | null, bitLength: BitLength, isLifetime: boolean, isSigned: boolean, isZeroable: boolean, maxValue?: BN | null, decimals?: number): [string, BN, boolean] { return isBn(value) ? getValuesFromBn(value, si, isSigned, isZeroable, decimals) - : getValuesFromString(api, value, si, bitLength, isSigned, isZeroable, maxValue, decimals); + : getValuesFromString(api, value, si, bitLength, isLifetime, isSigned, isZeroable, maxValue, decimals); } -function InputNumber ({ autoFocus, bitLength = DEFAULT_BITLENGTH, children, className = '', defaultValue, isDecimal, isDisabled, isError = false, isFull, isLoading, isSi, isSigned = false, isWarning, isZeroable = true, label, labelExtra, maxLength, maxValue, onChange, onEnter, onEscape, placeholder, siDecimals, siDefault, siSymbol, value: propsValue }: Props): React.ReactElement { +function InputNumber ({ autoFocus, bitLength = DEFAULT_BITLENGTH, children, className = '', defaultValue, isDecimal, isDisabled, isError = false, isFull, isLifetime, isLoading, isSi, isSigned = false, isWarning, isZeroable = true, label, labelExtra, maxLength, maxValue, onChange, onEnter, onEscape, placeholder, siDecimals, siDefault, siSymbol, value: propsValue }: Props): React.ReactElement { const { t } = useTranslation(); const { api } = useApi(); const [si] = useState(() => @@ -163,8 +191,9 @@ function InputNumber ({ autoFocus, bitLength = DEFAULT_BITLENGTH, children, clas : null ); const [[value, valueBn, isValid], setValues] = useState<[string, BN, boolean]>(() => - getValues(api, propsValue || defaultValue, si, bitLength, isSigned, isZeroable, maxValue, siDecimals) + getValues(api, propsValue || defaultValue, si, bitLength, !!isLifetime, isSigned, isZeroable, maxValue, siDecimals) ); + const [isPreKeyDown, setIsPreKeyDown] = useState(false); useEffect((): void => { @@ -172,14 +201,17 @@ function InputNumber ({ autoFocus, bitLength = DEFAULT_BITLENGTH, children, clas }, [isValid, onChange, valueBn]); const _onChangeWithSi = useCallback( - (input: string, si: SiDef | null) => setValues( - getValuesFromString(api, input, si, bitLength, isSigned, isZeroable, maxValue, siDecimals) - ), - [api, bitLength, isSigned, isZeroable, maxValue, siDecimals] + (input: string, si: SiDef | null) => + setValues( + getValuesFromString(api, input, si, bitLength, !!isLifetime, isSigned, isZeroable, maxValue, siDecimals) + ), + [api, bitLength, isLifetime, isSigned, isZeroable, maxValue, siDecimals] ); const _onChange = useCallback( - (input: string) => _onChangeWithSi(input, si), + (input: string) => { + _onChangeWithSi(input, si); + }, [_onChangeWithSi, si] ); diff --git a/packages/react-signer/src/SignFields.tsx b/packages/react-signer/src/SignFields.tsx index 98ceb345b6..98f746019b 100644 --- a/packages/react-signer/src/SignFields.tsx +++ b/packages/react-signer/src/SignFields.tsx @@ -62,6 +62,7 @@ function SignFields ({ address, onChange, signedTx }: Props): React.ReactElement />