diff --git a/wormhole-connect/src/components/InputTransparent.tsx b/wormhole-connect/src/components/InputTransparent.tsx index 1354b001f..f575850a3 100644 --- a/wormhole-connect/src/components/InputTransparent.tsx +++ b/wormhole-connect/src/components/InputTransparent.tsx @@ -40,6 +40,7 @@ type Props = { disabled?: boolean; value?: string | number; testId?: string; + pattern?: string; }; const NUMBER_FORMAT_REGEX = /^\d*\.?\d*$/; @@ -78,6 +79,7 @@ function InputTransparent(props: Props) { readOnly={props.disabled} value={props.value} data-testid={props.testId} + pattern={props.pattern} /> ); } diff --git a/wormhole-connect/src/hooks/useAmountValidation.ts b/wormhole-connect/src/hooks/useAmountValidation.ts index 47ccf469c..7f6bfd2ee 100644 --- a/wormhole-connect/src/hooks/useAmountValidation.ts +++ b/wormhole-connect/src/hooks/useAmountValidation.ts @@ -82,9 +82,11 @@ export const useAmountValidation = (props: Props): HookReturn => { // All quotes fail. if (allRoutesFailed) { if (minAmount) { - const amountDisplay = sdkAmount.display(minAmount); + const formattedAmount = sdkAmount.whole(minAmount).toLocaleString('en', { + maximumFractionDigits: 4, + }); return { - error: `Amount too small (min ~${amountDisplay} ${props.tokenSymbol})`, + error: `Amount too small (min ~${formattedAmount} ${props.tokenSymbol})`, }; } else { return { @@ -95,9 +97,11 @@ export const useAmountValidation = (props: Props): HookReturn => { // MinQuote warnings information if (minAmount) { - const amountDisplay = sdkAmount.display(minAmount); + const formattedAmount = sdkAmount.whole(minAmount).toLocaleString('en', { + maximumFractionDigits: 4, + }); return { - warning: `More routes available for amounts exceeding ${amountDisplay} ${props.tokenSymbol}`, + warning: `More routes available for amounts exceeding ${formattedAmount} ${props.tokenSymbol}`, }; } diff --git a/wormhole-connect/src/utils/sdkv2.ts b/wormhole-connect/src/utils/sdkv2.ts index ec6781fca..3ac6ce282 100644 --- a/wormhole-connect/src/utils/sdkv2.ts +++ b/wormhole-connect/src/utils/sdkv2.ts @@ -445,5 +445,5 @@ export const isMinAmountError = ( error?: Error, ): error is routes.MinAmountError => { const unsafeCastError = error as routes.MinAmountError; - return isAmount(unsafeCastError?.min?.amount); + return isAmount(unsafeCastError?.min); }; diff --git a/wormhole-connect/src/views/Bridge/Inputs/AmountInput.tsx b/wormhole-connect/src/views/Bridge/Inputs/AmountInput.tsx new file mode 100644 index 000000000..582d045b9 --- /dev/null +++ b/wormhole-connect/src/views/Bridge/Inputs/AmountInput.tsx @@ -0,0 +1,94 @@ +import React, { useMemo, useRef } from 'react'; +import { useSelector } from 'react-redux'; + +import { RootState } from 'store'; +import { toFixedDecimals } from 'utils/balance'; +import { NO_INPUT } from 'utils/style'; + +import InputTransparent from 'components/InputTransparent'; +import Input from './Input'; +import config from 'config'; +import Price from 'components/Price'; +import { getTokenPrice, getUSDFormat } from 'utils'; +import { TransferSide } from 'config/types'; + +type Props = { + handleAmountChange: (value: string) => void; + value: string; + disabled?: boolean; + label?: string; + side: TransferSide; +}; +function AmountInput(props: Props) { + const amountEl = useRef(null); + const { + showValidationState: showErrors, + validations, + token, + isTransactionInProgress, + } = useSelector((state: RootState) => state.transferInput); + const { + usdPrices: { data }, + } = useSelector((state: RootState) => state.tokenPrices); + const prices = data || {}; + + function handleAmountChange( + e: + | React.ChangeEvent + | React.ChangeEvent + | undefined, + ) { + let value = e!.target.value; + const index = value.indexOf('.'); + if (index > 0 && value.length - index - 8 > 0) { + value = toFixedDecimals(value, 8); + } + + props.handleAmountChange(value); + } + + const focus = () => { + if (amountEl.current) { + (amountEl.current as any).focus(); + } + }; + + const price = useMemo(() => { + const tokenPrice = getTokenPrice(prices, config.tokens[token]) || 0; + if (!tokenPrice) return undefined; + return getUSDFormat(Number(props.value) * tokenPrice); + }, [props.value, token, prices]); + + return ( + + {token ? ( + <> + + {price && {price}} + + ) : ( +
{NO_INPUT}
+ )} + + ); +} + +export default AmountInput;