diff --git a/package.json b/package.json index 08c06afbc..5ef7a6b55 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@xlabs/portal-bridge-ui", - "version": "0.1.62", + "version": "0.1.63", "private": true, "dependencies": { "@certusone/wormhole-sdk": "^0.9.22", diff --git a/src/components/Transfer/Source.tsx b/src/components/Transfer/Source.tsx index e447d6402..a1426e1c8 100644 --- a/src/components/Transfer/Source.tsx +++ b/src/components/Transfer/Source.tsx @@ -52,6 +52,7 @@ import { RootState } from "../../store"; import useTransferControl from "../../hooks/useTransferControl"; import transferRules from "../../config/transferRules"; import useRoundTripTransfer from "../../hooks/useRoundTripTransfer"; +import useMinimumAmountGuard from "../../hooks/useMinimumAmountGuard"; const useStyles = makeStyles((theme) => ({ chainSelectWrapper: { @@ -169,7 +170,13 @@ function Source() { isPandle ); /* End pandle token check */ - + const { decimals = 0, isNativeAsset = false } = parsedTokenAccount || {}; + const { isBelowMinimum, minimum } = useMinimumAmountGuard({ + amount, + sourceChain, + decimals, + isNativeAsset, + }); return ( <> @@ -260,6 +267,12 @@ function Source() { value={amount} onChange={handleAmountChange} disabled={isTransferDisabled || shouldLockFields} + error={isBelowMinimum} + helperText={ + isBelowMinimum + ? `Amount sent is too small. The amount must be equal or greater than ${minimum}.` + : "" + } onMaxClick={ uiAmountString && !parsedTokenAccount.isNativeAsset ? handleMaxClick @@ -272,7 +285,7 @@ function Source() { ))} EIGHT_DECIMALS + ? EIGHT_DECIMALS // max decimals supported on evm chains + : decimals; +} + +function getMinimum(divider: number, adjustedDecimals: number) { + return (1 / divider).toFixed(adjustedDecimals); +} + +function checkIfIsBelowMinimum(amount: string, multiplier: number) { + try { + const floatAmount = parseFloat(amount); + const intAmount = floatAmount * multiplier; + return Math.trunc(intAmount) <= 0; + } catch (err: any) { + console.error(err); + return true; + } +} + +export default function useMinimumAmountGuard({ + amount, + sourceChain, + decimals = 0, + isNativeAsset = false, +}: MinimumAmountGuardArgs) { + const adjustedDecimals = useMemo( + () => getAdjustedDecimals(sourceChain, isNativeAsset, decimals), + [sourceChain, isNativeAsset, decimals] + ); + const multiplier = useMemo( + () => getMultiplier(adjustedDecimals), + [adjustedDecimals] + ); + const isBelowMinimum = useMemo( + () => checkIfIsBelowMinimum(amount, multiplier), + [amount, multiplier] + ); + const minimum = useMemo( + () => getMinimum(multiplier, adjustedDecimals), + [multiplier, adjustedDecimals] + ); + return { isBelowMinimum, minimum }; +}