Skip to content

Commit

Permalink
enforce minimum amount for Evm token transfers (#293)
Browse files Browse the repository at this point in the history
* Enforce minimum amount for evm token transfers

* code review observations

* fix decimals to the max supported for evm chains if the decimals are higher

* [skip ci] - run prettier

* code review observations

* [skip ci] - cosmetic changes

* disable next button if the amount is below minimum

* [skip ci] - bump version
  • Loading branch information
sebastianscatularo committed Aug 18, 2023
1 parent 73442db commit 049538f
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
17 changes: 15 additions & 2 deletions src/components/Transfer/Source.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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 (
<>
<StepDescription>
Expand Down Expand Up @@ -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
Expand All @@ -272,7 +285,7 @@ function Source() {
))}
<TransferLimitedWarning isTransferLimited={isTransferLimited} />
<ButtonWithLoader
disabled={isTransferDisabled || !isSourceComplete}
disabled={isTransferDisabled || !isSourceComplete || isBelowMinimum}
onClick={handleNextClick}
showLoader={false}
error={isTransferDisabled ? "" : statusMessage || error}
Expand Down
65 changes: 65 additions & 0 deletions src/hooks/useMinimumAmountGuard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useMemo } from "react";
import { ChainId, isEVMChain } from "@certusone/wormhole-sdk";

export type MinimumAmountGuardArgs = {
amount: string;
sourceChain: ChainId;
decimals: number;
isNativeAsset: boolean;
};

const EIGHT_DECIMALS = 8;

function getMultiplier(decimals: number) {
return Math.pow(10, decimals);
}

function getAdjustedDecimals(
chainId: ChainId,
isNativeAsset: boolean,
decimals: number
) {
return isEVMChain(chainId) && !isNativeAsset && decimals > 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 };
}

0 comments on commit 049538f

Please sign in to comment.