/ src / components / transactions / Bridge / BridgeDestinationInput.tsx
BridgeDestinationInput.tsx
  1  import { t, Trans } from '@lingui/macro';
  2  import {
  3    CircularProgress,
  4    FormControlLabel,
  5    InputBase,
  6    Stack,
  7    Switch,
  8    Typography,
  9  } from '@mui/material';
 10  import { isAddress } from 'ethers/lib/utils';
 11  import { useEffect, useState } from 'react';
 12  import { useIsContractAddress } from 'src/hooks/useIsContractAddress';
 13  import { getENSProvider } from 'src/utils/marketsAndNetworksConfig';
 14  
 15  export const BridgeDestinationInput = ({
 16    connectedAccount,
 17    onInputValid,
 18    onInputError,
 19    sourceChainId,
 20  }: {
 21    connectedAccount: string;
 22    onInputValid: (destinationAccount: string) => void;
 23    onInputError: () => void;
 24    sourceChainId: number;
 25  }) => {
 26    const { data: isContractAddress, isFetching: fetchingIsContractAddress } = useIsContractAddress(
 27      connectedAccount,
 28      sourceChainId
 29    );
 30  
 31    const [useConnectedAccount, setUseConnectedAccount] = useState(true);
 32    const [destinationAccount, setDestinationAccount] = useState('');
 33    const [validatingENS, setValidatingENS] = useState(false);
 34  
 35    useEffect(() => {
 36      if (isContractAddress === undefined) {
 37        return;
 38      }
 39  
 40      if (isContractAddress) {
 41        setUseConnectedAccount(false);
 42        setDestinationAccount('');
 43      } else {
 44        setUseConnectedAccount(true);
 45        setDestinationAccount(connectedAccount);
 46      }
 47    }, [connectedAccount, isContractAddress]);
 48  
 49    useEffect(() => {
 50      const checkENS = async () => {
 51        setValidatingENS(true);
 52        const resolvedAddress = await getENSProvider().resolveName(destinationAccount);
 53        if (resolvedAddress) {
 54          setDestinationAccount(resolvedAddress.toLowerCase());
 55        }
 56        setValidatingENS(false);
 57      };
 58  
 59      if (destinationAccount.slice(-4) === '.eth') {
 60        checkENS();
 61      }
 62    }, [destinationAccount]);
 63  
 64    useEffect(() => {
 65      const validAddress = isAddress(destinationAccount);
 66      if (validAddress) {
 67        onInputValid(destinationAccount);
 68      } else {
 69        onInputError();
 70      }
 71    }, [destinationAccount, onInputError, onInputValid]);
 72  
 73    const showWarning = !useConnectedAccount && !isAddress(destinationAccount);
 74  
 75    return (
 76      <Stack direction="column" gap={1} width="100%">
 77        <Stack direction="row" justifyContent="space-between" alignItems="flex-end">
 78          <Typography color="text.secondary">
 79            <Trans>To</Trans>
 80          </Typography>
 81          <Stack direction="row" alignItems="center" sx={{ mb: -1 }}>
 82            <FormControlLabel
 83              sx={{ mx: 0 }}
 84              control={
 85                <Switch
 86                  disableRipple
 87                  checked={useConnectedAccount}
 88                  onClick={() => {
 89                    const newValue = !useConnectedAccount;
 90                    if (newValue) {
 91                      setDestinationAccount(connectedAccount);
 92                      onInputValid(connectedAccount);
 93                    } else {
 94                      setDestinationAccount('');
 95                      onInputError();
 96                    }
 97                    setUseConnectedAccount(newValue);
 98                  }}
 99                />
100              }
101              labelPlacement="start"
102              label={
103                <Typography sx={{ fontSize: '0.75rem' }} color="text.secondary">
104                  <Trans>Use connected account</Trans>
105                </Typography>
106              }
107            />
108          </Stack>
109        </Stack>
110        <InputBase
111          fullWidth
112          value={destinationAccount}
113          disabled={useConnectedAccount || fetchingIsContractAddress}
114          onChange={(e) => setDestinationAccount(e.target.value)}
115          placeholder={t`Enter ETH address or ENS`}
116          sx={(theme) => ({
117            height: '44px',
118            px: 2,
119            border: `1px solid ${theme.palette.divider}`,
120            borderRadius: '6px',
121            overflow: 'hidden',
122          })}
123          endAdornment={
124            validatingENS || fetchingIsContractAddress ? (
125              <CircularProgress color="inherit" size="16px" />
126            ) : null
127          }
128        />
129        <Typography
130          sx={{
131            visibility:
132              useConnectedAccount || fetchingIsContractAddress
133                ? 'hidden'
134                : showWarning
135                ? 'visible'
136                : 'hidden',
137          }}
138          variant="helperText"
139          color="error.main"
140        >
141          <Trans>Enter a valid address</Trans>
142        </Typography>
143      </Stack>
144    );
145  };