From 46937e66ed683e3f08b17cc38a36deb5a000c971 Mon Sep 17 00:00:00 2001 From: Sebastian Scatularo Date: Wed, 9 Aug 2023 10:49:23 -0300 Subject: [PATCH] Enforce minimum amount for evm token transfers --- src/components/Transfer/Source.tsx | 5 +++- src/hooks/useMinimumAmountGuard.ts | 43 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/hooks/useMinimumAmountGuard.ts diff --git a/src/components/Transfer/Source.tsx b/src/components/Transfer/Source.tsx index e447d6402..033096af0 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,7 @@ function Source() { isPandle ); /* End pandle token check */ - + const isBelowMinimum = useMinimumAmountGuard(); return ( <> @@ -260,6 +261,8 @@ function Source() { value={amount} onChange={handleAmountChange} disabled={isTransferDisabled || shouldLockFields} + error={isBelowMinimum} + helperText={isBelowMinimum ? "Amount is below minimum" : ""} onMaxClick={ uiAmountString && !parsedTokenAccount.isNativeAsset ? handleMaxClick diff --git a/src/hooks/useMinimumAmountGuard.ts b/src/hooks/useMinimumAmountGuard.ts new file mode 100644 index 000000000..5afbe0b1d --- /dev/null +++ b/src/hooks/useMinimumAmountGuard.ts @@ -0,0 +1,43 @@ +import type { RootState } from "../store"; +import { useMemo } from "react"; +import { useSelector } from "react-redux"; +import { ChainId, isEVMChain } from "@certusone/wormhole-sdk"; + +function checkIfIsBelowMinimum(amount: string, decimals: number) { + try { + const divider = Math.pow(10, decimals); + const floatAmount = parseFloat(amount); + const intAmount = floatAmount * divider; + return Math.trunc(intAmount) <= 0; + } catch (err: any) { + console.error(err); + return true; + } +} + +function getAdjustedDecimals( + chainId: ChainId, + isNativeAsset: boolean, + decimals: number +) { + return isEVMChain(chainId) && !isNativeAsset && decimals > 8 + ? decimals - 8 + : decimals; +} + +export default function useMinimumAmountGuard() { + const { + amount, + sourceChain, + sourceParsedTokenAccount: { decimals = 0, isNativeAsset = false } = {}, + } = useSelector((state: RootState) => state.transfer); + const isBelowMinimum = useMemo( + () => + checkIfIsBelowMinimum( + amount, + getAdjustedDecimals(sourceChain, isNativeAsset, decimals) + ), + [amount, sourceChain, isNativeAsset, decimals] + ); + return isBelowMinimum; +}