utils#getEtherscanLink TypeScript Examples

The following examples show how to use utils#getEtherscanLink. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Transaction.tsx    From interface-v2 with GNU General Public License v3.0 6 votes vote down vote up
Transaction: React.FC<TransactionProps> = ({ hash }) => {
  const classes = useStyles();
  const { chainId } = useActiveWeb3React();
  const allTransactions = useAllTransactions();

  const tx = allTransactions?.[hash];
  const summary = tx?.summary;
  const pending = !tx?.confirmedTime;
  const success =
    !pending &&
    tx &&
    tx.receipt &&
    (tx.receipt.status === 1 || typeof tx.receipt.status === 'undefined');

  if (!chainId) return null;

  return (
    <Box className={classes.transactionState}>
      <a
        className={classes.transactionStatusText}
        href={getEtherscanLink(chainId, hash, 'transaction')}
        target='_blank'
        rel='noopener noreferrer'
      >
        {summary ?? hash} ↗
      </a>
      <Box className={classes.iconWrapper}>
        {pending ? (
          <CircularProgress size={16} />
        ) : success ? (
          <CheckCircle size='16' />
        ) : (
          <Triangle size='16' />
        )}
      </Box>
    </Box>
  );
}
Example #2
Source File: AddressInput.tsx    From interface-v2 with GNU General Public License v3.0 6 votes vote down vote up
AddressInput: React.FC<AddressInputProps> = ({
  value,
  onChange,
  placeholder,
  label,
}) => {
  const { chainId } = useActiveWeb3React();
  const { address, loading, name } = useENS(value);
  const error = Boolean(value.length > 0 && !loading && !address);
  const classes = useStyles({ error });

  return (
    <Box className={classes.addressInput}>
      <Box display='flex' justifyContent='space-between' alignItems='center'>
        <Typography>{label}</Typography>
        {address && chainId && (
          <a
            href={getEtherscanLink(chainId, name ?? address, 'address')}
            target='_blank'
            rel='noopener noreferrer'
          >
            (View on Block Explorer)
          </a>
        )}
      </Box>
      <input
        value={value}
        placeholder={placeholder}
        onChange={(evt) => {
          const input = evt.target.value;
          const withoutSpaces = input.replace(/\s+/g, '');
          onChange(withoutSpaces);
        }}
      />
    </Box>
  );
}
Example #3
Source File: TransactionConfirmationModal.tsx    From interface-v2 with GNU General Public License v3.0 5 votes vote down vote up
TransactionSubmittedContent: React.FC<TransactionSubmittedContentProps> = ({
  onDismiss,
  chainId,
  hash,
  txPending,
  modalContent,
}) => {
  const classes = useStyles();
  return (
    <Box padding={4}>
      <Box className={classes.modalHeader}>
        <Typography variant='h5'>
          Transaction {txPending ? 'Submitted' : 'Completed'}
        </Typography>
        <CloseIcon onClick={onDismiss} />
      </Box>
      {!txPending && (
        <Box mt={8} display='flex' justifyContent='center'>
          <TransactionSuccess />
        </Box>
      )}
      <Box className={classes.modalContent}>
        <Typography variant='body1'>{modalContent}</Typography>
      </Box>
      <Box display='flex' justifyContent='space-between' mt={2}>
        {chainId && hash && (
          <a
            href={getEtherscanLink(chainId, hash, 'transaction')}
            target='_blank'
            rel='noopener noreferrer'
            style={{ width: '48%', textDecoration: 'none' }}
          >
            <Button className={classes.submitButton}>
              View on Block Explorer
            </Button>
          </a>
        )}
        <Button
          className={classes.submitButton}
          style={{ width: '48%' }}
          onClick={onDismiss}
        >
          Close
        </Button>
      </Box>
    </Box>
  );
}
Example #4
Source File: RecentTransactionsModal.tsx    From goose-frontend-amm with GNU General Public License v3.0 5 votes vote down vote up
RecentTransactionsModal = ({ onDismiss = defaultOnDismiss }: RecentTransactionsModalProps) => {
  const { account, chainId } = useActiveWeb3React()
  const allTransactions = useAllTransactions()

  // Logic taken from Web3Status/index.tsx line 175
  const sortedRecentTransactions = useMemo(() => {
    const txs = Object.values(allTransactions)
    return txs.filter(isTransactionRecent).sort(newTransactionsFirst)
  }, [allTransactions])

  return (
    <Modal title="Recent Transactions" onDismiss={onDismiss}>
      {!account && (
        <Flex justifyContent="center" flexDirection="column" alignItems="center">
          <Text mb="8px" bold>
            Please connect your wallet to view your recent transactions
          </Text>
          <Button variant="tertiary" size="sm" onClick={onDismiss}>
            Close
          </Button>
        </Flex>
      )}
      {account && chainId && sortedRecentTransactions.length === 0 && (
        <Flex justifyContent="center" flexDirection="column" alignItems="center">
          <Text mb="8px" bold>
            No recent transactions
          </Text>
          <Button variant="tertiary" size="sm" onClick={onDismiss}>
            Close
          </Button>
        </Flex>
      )}
      {account &&
        chainId &&
        sortedRecentTransactions.map((sortedRecentTransaction) => {
          const { hash, summary } = sortedRecentTransaction
          const { icon, color } = getRowStatus(sortedRecentTransaction)

          return (
            <>
              <Flex key={hash} alignItems="center" justifyContent="space-between" mb="4px">
                <LinkExternal href={getEtherscanLink(chainId, hash, 'transaction')} color={color}>
                  {summary ?? hash}
                </LinkExternal>
                {icon}
              </Flex>
            </>
          )
        })}
    </Modal>
  )
}
Example #5
Source File: UnsupportedCurrencyFooter.tsx    From forward.swaps with GNU General Public License v3.0 5 votes vote down vote up
export default function UnsupportedCurrencyFooter({
  show,
  currencies
}: {
  show: boolean
  currencies: (Currency | undefined)[]
}) {
  const { chainId } = useActiveWeb3React()
  const [showDetails, setShowDetails] = useState(false)

  const tokens =
    chainId && currencies
      ? currencies.map(currency => {
          return wrappedCurrency(currency, chainId)
        })
      : []

  const unsupportedTokens: { [address: string]: Token } = useUnsupportedTokens()

  return (
    <DetailsFooter show={show}>
      <Modal isOpen={showDetails} onDismiss={() => setShowDetails(false)}>
        <Card padding="2rem">
          <AutoColumn gap="lg">
            <RowBetween>
              <TYPE.mediumHeader>Unsupported Assets</TYPE.mediumHeader>

              <CloseIcon onClick={() => setShowDetails(false)} />
            </RowBetween>
            {tokens.map(token => {
              return (
                token &&
                unsupportedTokens &&
                Object.keys(unsupportedTokens).includes(token.address) && (
                  <OutlineCard key={token.address?.concat('not-supported')}>
                    <AutoColumn gap="10px">
                      <AutoRow gap="5px" align="center">
                        <CurrencyLogo currency={token} size={'24px'} />
                        <TYPE.body fontWeight={500}>{token.symbol}</TYPE.body>
                      </AutoRow>
                      {chainId && (
                        <ExternalLink href={getEtherscanLink(chainId, token.address, 'address')}>
                          <AddressText>{token.address}</AddressText>
                        </ExternalLink>
                      )}
                    </AutoColumn>
                  </OutlineCard>
                )
              )
            })}
            <AutoColumn gap="lg">
              <TYPE.body fontWeight={500}>
                Some assets are not available through this interface because they may not work well with our smart
                contract or we are unable to allow trading for legal reasons.
              </TYPE.body>
            </AutoColumn>
          </AutoColumn>
        </Card>
      </Modal>
      <ButtonEmpty padding={'0'} onClick={() => setShowDetails(true)}>
        <TYPE.blue>Read more about unsupported assets</TYPE.blue>
      </ButtonEmpty>
    </DetailsFooter>
  )
}
Example #6
Source File: AccountDetails.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
AccountDetails: React.FC<AccountDetailsProps> = ({
  toggleWalletModal,
  pendingTransactions,
  confirmedTransactions,
  ENSName,
  openOptions,
}) => {
  const { chainId, account, connector } = useActiveWeb3React();
  const classes = useStyles();
  const { palette } = useTheme();
  const dispatch = useDispatch<AppDispatch>();

  function formatConnectorName() {
    const { ethereum } = window as any;
    const isMetaMask = !!(
      ethereum &&
      !ethereum.isBitKeep &&
      ethereum.isMetaMask
    );
    const isBitkeep = !!(ethereum && ethereum.isBitKeep);
    const isBlockWallet = !!(ethereum && ethereum.isBlockWallet);
    const name = Object.keys(SUPPORTED_WALLETS)
      .filter(
        (k) =>
          SUPPORTED_WALLETS[k].connector === connector &&
          (connector !== injected ||
            (isBlockWallet && k === 'BLOCKWALLET') ||
            (isBitkeep && k === 'BITKEEP') ||
            (isMetaMask && k === 'METAMASK')),
      )
      .map((k) => SUPPORTED_WALLETS[k].name)[0];
    return <Typography variant='body2'>Connected with {name}</Typography>;
  }

  const clearAllTransactionsCallback = useCallback(() => {
    if (chainId) dispatch(clearAllTransactions({ chainId }));
  }, [dispatch, chainId]);

  return (
    <Box paddingX={3} paddingY={4}>
      <Box display='flex' justifyContent='space-between'>
        <Typography variant='h5'>Account</Typography>
        <Close style={{ cursor: 'pointer' }} onClick={toggleWalletModal} />
      </Box>
      <Box
        mt={2}
        padding={2}
        borderRadius={10}
        bgcolor={palette.secondary.dark}
      >
        <Box display='flex' justifyContent='space-between' alignItems='center'>
          {formatConnectorName()}
          <Box display='flex' alignItems='center'>
            {connector !== injected &&
              connector !== walletlink &&
              connector !== safeApp && (
                <Typography
                  style={{ cursor: 'pointer', marginRight: 8 }}
                  onClick={() => {
                    (connector as any).close();
                  }}
                  variant='body2'
                >
                  Disconnect
                </Typography>
              )}
            {connector !== safeApp && (
              <Typography
                style={{ cursor: 'pointer' }}
                onClick={() => {
                  openOptions();
                }}
                variant='body2'
              >
                Change
              </Typography>
            )}
          </Box>
        </Box>
        <Box display='flex' alignItems='center' my={1.5}>
          <StatusIcon />
          <Typography
            variant='h5'
            style={{ marginLeft: 8 }}
            id='web3-account-identifier-row'
          >
            {ENSName ? ENSName : account && shortenAddress(account)}
          </Typography>
        </Box>
        <Box display='flex' justifyContent='space-between' alignItems='center'>
          {account && (
            <Copy toCopy={account}>
              <span style={{ marginLeft: '4px' }}>Copy Address</span>
            </Copy>
          )}
          {chainId && account && (
            <a
              className={classes.addressLink}
              href={
                chainId &&
                getEtherscanLink(
                  chainId,
                  ENSName ? ENSName : account,
                  'address',
                )
              }
              target='_blank'
              rel='noopener noreferrer'
            >
              <LinkIcon size={16} />
              <Typography variant='body2'>View on Block Explorer</Typography>
            </a>
          )}
        </Box>
      </Box>
      {!!pendingTransactions.length || !!confirmedTransactions.length ? (
        <>
          <Box
            display='flex'
            justifyContent='space-between'
            alignItems='center'
            paddingX={2}
            pt={2}
            mb={1}
          >
            <Typography variant='body2'>Recent Transactions</Typography>
            <Typography
              variant='body2'
              style={{ cursor: 'pointer' }}
              onClick={clearAllTransactionsCallback}
            >
              Clear all
            </Typography>
          </Box>
          <Box paddingX={2} flex={1} overflow='auto'>
            {renderTransactions(pendingTransactions)}
            {renderTransactions(confirmedTransactions)}
          </Box>
        </>
      ) : (
        <Box paddingX={2} pt={2}>
          <Typography variant='body2'>
            Your transactions will appear here...
          </Typography>
        </Box>
      )}
    </Box>
  );
}
Example #7
Source File: TransactionsTable.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
TransactionsTable: React.FC<TransactionsTableProps> = ({ data }) => {
  const [txFilter, setTxFilter] = useState(-1);
  const txHeadCells = headCells(txFilter, setTxFilter);
  const classes = useStyles();
  const { chainId } = useActiveWeb3React();
  const { palette, breakpoints } = useTheme();
  const isMobile = useMediaQuery(breakpoints.down('xs'));
  const { t } = useTranslation();
  const getTxString = (txn: any) => {
    const messageData = {
      token0Symbol: txn.pair.token1.symbol,
      token1Symbol: txn.pair.token0.symbol,
    };
    if (txn.type === TxnType.SWAP) {
      return t('txnSwapMessage', messageData);
    } else if (txn.type === TxnType.ADD) {
      return t('txnAddMessage', messageData);
    } else if (txn.type === TxnType.REMOVE) {
      return t('txnRemoveMessage', messageData);
    }
    return '';
  };
  const mobileHTML = (txn: any, index: number) => {
    return (
      <Box mt={index === 0 ? 0 : 3} key={index}>
        <Box mb={1}>
          {chainId ? (
            <a
              href={getEtherscanLink(
                chainId,
                txn.transaction.id,
                'transaction',
              )}
              target='_blank'
              rel='noopener noreferrer'
              style={{ textDecoration: 'none' }}
            >
              <Typography
                variant='body1'
                style={{ color: palette.primary.main }}
              >
                {getTxString(txn)}
              </Typography>
            </a>
          ) : (
            <Typography variant='body1' style={{ color: palette.primary.main }}>
              {getTxString(txn)}
            </Typography>
          )}
        </Box>
        <Divider />
        <Box className={classes.mobileRow}>
          <Typography variant='body1'>Total Value</Typography>
          <Typography variant='body1' color='textPrimary'>
            ${Number(txn.amountUSD).toLocaleString()}
          </Typography>
        </Box>
        <Box className={classes.mobileRow}>
          <Typography variant='body1'>Token Amount</Typography>
          <Typography variant='body1' color='textPrimary'>
            {formatNumber(txn.amount0)} {txn.pair.token0.symbol}
          </Typography>
        </Box>
        <Box className={classes.mobileRow}>
          <Typography variant='body1'>Token Amount</Typography>
          <Typography variant='body1' color='textPrimary'>
            {formatNumber(txn.amount1)} {txn.pair.token1.symbol}
          </Typography>
        </Box>
        <Box className={classes.mobileRow}>
          <Typography variant='body1'>TXN</Typography>
          {chainId ? (
            <a
              href={getEtherscanLink(
                chainId,
                txn.transaction.id,
                'transaction',
              )}
              target='_blank'
              rel='noopener noreferrer'
              style={{ textDecoration: 'none' }}
            >
              <Typography
                variant='body1'
                style={{ color: palette.primary.main }}
              >
                {shortenTx(txn.transaction.id)}
              </Typography>
            </a>
          ) : (
            <Typography variant='body1' style={{ color: palette.primary.main }}>
              {shortenTx(txn.transaction.id)}
            </Typography>
          )}
        </Box>
        <Box className={classes.mobileRow}>
          <Typography variant='body1'>Time</Typography>
          <Typography variant='body1' color='textPrimary'>
            {dayjs(Number(txn.transaction.timestamp) * 1000).fromNow()}
          </Typography>
        </Box>
      </Box>
    );
  };

  const desktopHTML = (txn: any) => {
    return [
      {
        html: chainId ? (
          <a
            href={getEtherscanLink(chainId, txn.transaction.id, 'transaction')}
            target='_blank'
            rel='noopener noreferrer'
            style={{ textDecoration: 'none' }}
          >
            <Typography variant='body1' style={{ color: palette.primary.main }}>
              {getTxString(txn)}
            </Typography>
          </a>
        ) : (
          <Typography variant='body1' style={{ color: palette.primary.main }}>
            {getTxString(txn)}
          </Typography>
        ),
      },
      {
        html: (
          <Typography variant='body1' color='textPrimary'>
            ${Number(txn.amountUSD).toLocaleString()}
          </Typography>
        ),
      },
      {
        html: (
          <Typography variant='body1' color='textPrimary'>
            {formatNumber(txn.amount1)} {txn.pair.token1.symbol}
          </Typography>
        ),
      },
      {
        html: (
          <Typography variant='body1' color='textPrimary'>
            {formatNumber(txn.amount0)} {txn.pair.token0.symbol}
          </Typography>
        ),
      },
      {
        html: chainId ? (
          <a
            href={getEtherscanLink(chainId, txn.transaction.id, 'transaction')}
            target='_blank'
            rel='noopener noreferrer'
            style={{ textDecoration: 'none' }}
          >
            <Typography variant='body1' style={{ color: palette.primary.main }}>
              {shortenTx(txn.transaction.id)}
            </Typography>
          </a>
        ) : (
          <Typography variant='body1' style={{ color: palette.primary.main }}>
            {shortenTx(txn.transaction.id)}
          </Typography>
        ),
      },
      {
        html: (
          <Typography variant='body1' color='textPrimary'>
            {dayjs(Number(txn.transaction.timestamp) * 1000).fromNow()}
          </Typography>
        ),
      },
    ];
  };

  return (
    <Box position='relative'>
      {isMobile && (
        <Box
          display='flex'
          alignItems='center'
          position='absolute'
          top={-48}
          right={0}
        >
          <Box padding={1} onClick={() => setTxFilter(-1)}>
            <Typography
              variant='body1'
              color={txFilter === -1 ? 'textPrimary' : 'textSecondary'}
            >
              All
            </Typography>
          </Box>
          <Box padding={1} onClick={() => setTxFilter(TxnType.SWAP)}>
            <Typography
              variant='body1'
              color={
                txFilter === TxnType.SWAP ? 'textPrimary' : 'textSecondary'
              }
            >
              Swap
            </Typography>
          </Box>
          <Box padding={1} onClick={() => setTxFilter(TxnType.ADD)}>
            <Typography
              variant='body1'
              color={txFilter === TxnType.ADD ? 'textPrimary' : 'textSecondary'}
            >
              Add
            </Typography>
          </Box>
          <Box padding={1} onClick={() => setTxFilter(TxnType.REMOVE)}>
            <Typography
              variant='body1'
              color={
                txFilter === TxnType.REMOVE ? 'textPrimary' : 'textSecondary'
              }
            >
              Remove
            </Typography>
          </Box>
        </Box>
      )}
      <CustomTable
        showPagination={data.length > 10}
        headCells={txHeadCells}
        defaultOrderBy={txHeadCells[5]}
        rowsPerPage={10}
        data={data.filter((item) =>
          txFilter === -1 ? true : item.type === txFilter,
        )}
        mobileHTML={mobileHTML}
        desktopHTML={desktopHTML}
      />
    </Box>
  );
}
Example #8
Source File: AnalyticsPairDetails.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
AnalyticsPairDetails: React.FC = () => {
  const classes = useStyles();
  const { palette, breakpoints } = useTheme();
  const isMobile = useMediaQuery(breakpoints.down('xs'));
  const history = useHistory();
  const match = useRouteMatch<{ id: string }>();
  const pairAddress = match.params.id;
  const [pairData, setPairData] = useState<any>(null);
  const [pairTransactions, setPairTransactions] = useState<any>(null);
  const pairTransactionsList = useMemo(() => {
    if (pairTransactions) {
      const mints = pairTransactions.mints.map((item: any) => {
        return { ...item, type: TxnType.ADD };
      });
      const swaps = pairTransactions.swaps.map((item: any) => {
        const amount0 = item.amount0Out > 0 ? item.amount0Out : item.amount1Out;
        const amount1 = item.amount0In > 0 ? item.amount0In : item.amount1In;
        const token0 =
          item.amount0Out > 0 ? item.pair.token0 : item.pair.token1;
        const token1 =
          item.amount0Out > 0 ? item.pair.token1 : item.pair.token0;
        return {
          ...item,
          amount0,
          amount1,
          pair: { token0, token1 },
          type: TxnType.SWAP,
        };
      });
      const burns = pairTransactions.burns.map((item: any) => {
        return { ...item, type: TxnType.REMOVE };
      });
      return mints.concat(swaps).concat(burns);
    } else {
      return null;
    }
  }, [pairTransactions]);
  const { chainId } = useActiveWeb3React();
  const currency0 = pairData
    ? new Token(
        ChainId.MATIC,
        getAddress(pairData.token0.id),
        pairData.token0.decimals,
      )
    : undefined;
  const currency1 = pairData
    ? new Token(
        ChainId.MATIC,
        getAddress(pairData.token1.id),
        pairData.token1.decimals,
      )
    : undefined;

  const token0Rate =
    pairData && pairData.reserve0 && pairData.reserve1
      ? Number(pairData.reserve1) / Number(pairData.reserve0) >= 0.0001
        ? (Number(pairData.reserve1) / Number(pairData.reserve0)).toFixed(
            Number(pairData.reserve1) / Number(pairData.reserve0) > 1 ? 2 : 4,
          )
        : '< 0.0001'
      : '-';
  const token1Rate =
    pairData && pairData.reserve0 && pairData.reserve1
      ? Number(pairData.reserve0) / Number(pairData.reserve1) >= 0.0001
        ? (Number(pairData.reserve0) / Number(pairData.reserve1)).toFixed(
            Number(pairData.reserve0) / Number(pairData.reserve1) > 1 ? 2 : 4,
          )
        : '< 0.0001'
      : '-';
  const usingUtVolume =
    pairData &&
    pairData.oneDayVolumeUSD === 0 &&
    !!pairData.oneDayVolumeUntracked;
  const fees =
    pairData && (pairData.oneDayVolumeUSD || pairData.oneDayVolumeUSD === 0)
      ? usingUtVolume
        ? (
            Number(pairData.oneDayVolumeUntracked) *
            GlobalConst.utils.FEEPERCENT
          ).toLocaleString()
        : (
            Number(pairData.oneDayVolumeUSD) * GlobalConst.utils.FEEPERCENT
          ).toLocaleString()
      : '-';

  useEffect(() => {
    async function checkEthPrice() {
      const [newPrice] = await getEthPrice();
      const pairInfo = await getBulkPairData([pairAddress], newPrice);
      if (pairInfo && pairInfo.length > 0) {
        setPairData(pairInfo[0]);
      }
    }
    async function fetchTransctions() {
      const transactions = await getPairTransactions(pairAddress);
      if (transactions) {
        setPairTransactions(transactions);
      }
    }
    checkEthPrice();
    fetchTransctions();
  }, [pairAddress]);

  return (
    <>
      <AnalyticsHeader type='pair' data={pairData} />
      {pairData ? (
        <>
          <Box
            width={1}
            display='flex'
            flexWrap='wrap'
            justifyContent='space-between'
          >
            <Box>
              <Box display='flex' alignItems='center'>
                <DoubleCurrencyLogo
                  currency0={currency0}
                  currency1={currency1}
                  size={32}
                />
                <Box ml={1}>
                  <Typography className={classes.heading2}>
                    <Link to={`/analytics/token/${pairData.token0.id}`}>
                      {pairData.token0.symbol}
                    </Link>{' '}
                    /{' '}
                    <Link to={`/analytics/token/${pairData.token1.id}`}>
                      {pairData.token1.symbol}
                    </Link>
                  </Typography>
                </Box>
              </Box>
              <Box mt={2} display='flex'>
                <Box
                  paddingY={0.75}
                  paddingX={1.5}
                  borderRadius={20}
                  display='flex'
                  alignItems='center'
                  bgcolor={palette.grey.A700}
                >
                  <CurrencyLogo currency={currency0} size='16px' />
                  <Typography
                    variant='body2'
                    color='textPrimary'
                    style={{ marginLeft: 6 }}
                  >
                    1 {pairData.token0.symbol} = {token0Rate}{' '}
                    {pairData.token1.symbol}
                  </Typography>
                </Box>
                <Box
                  padding={0.75}
                  paddingX={1.5}
                  ml={2}
                  borderRadius={20}
                  display='flex'
                  alignItems='center'
                  bgcolor={palette.grey.A700}
                >
                  <CurrencyLogo currency={currency1} size='16px' />
                  <Typography
                    variant='body2'
                    color='textPrimary'
                    style={{ marginLeft: 6 }}
                  >
                    1 {pairData.token1.symbol} = {token1Rate}{' '}
                    {pairData.token0.symbol}
                  </Typography>
                </Box>
              </Box>
            </Box>
            <Box my={2} display='flex'>
              <Box
                className={classes.button}
                mr={1.5}
                border={`1px solid ${palette.primary.main}`}
                onClick={() => {
                  history.push(
                    `/pools?currency0=${pairData.token0.id}&currency1=${pairData.token1.id}`,
                  );
                }}
              >
                <Typography variant='body2'>Add Liquidity</Typography>
              </Box>
              <Box
                className={cx(classes.button, classes.filledButton)}
                onClick={() => {
                  history.push(
                    `/swap?currency0=${pairData.token0.id}&currency1=${pairData.token1.id}`,
                  );
                }}
              >
                <Typography variant='body2'>Swap</Typography>
              </Box>
            </Box>
          </Box>
          <Box width={1} className={classes.panel} mt={4}>
            <Grid container>
              <Grid item xs={12} sm={12} md={6}>
                <AnalyticsPairChart pairData={pairData} />
              </Grid>
              <Grid item xs={12} sm={12} md={6}>
                <Box
                  my={2}
                  height={1}
                  display='flex'
                  justifyContent='center'
                  alignItems='center'
                >
                  <Box
                    width={isMobile ? 1 : 0.8}
                    display='flex'
                    justifyContent='space-between'
                  >
                    <Box width={212}>
                      <Box>
                        <Typography
                          variant='caption'
                          style={{ color: palette.text.disabled }}
                        >
                          TOTAL TOKENS LOCKED
                        </Typography>
                        <Box
                          mt={1.5}
                          bgcolor={palette.grey.A400}
                          borderRadius={8}
                          padding={1.5}
                        >
                          <Box
                            display='flex'
                            alignItems='center'
                            justifyContent='space-between'
                          >
                            <Box display='flex' alignItems='center'>
                              <CurrencyLogo currency={currency0} size='16px' />
                              <Typography
                                variant='caption'
                                color='textPrimary'
                                style={{ marginLeft: 6 }}
                              >
                                {pairData.token0.symbol} :
                              </Typography>
                            </Box>
                            <Typography variant='caption' color='textPrimary'>
                              {Number(pairData.reserve0).toLocaleString()}
                            </Typography>
                          </Box>
                          <Box
                            mt={1}
                            display='flex'
                            alignItems='center'
                            justifyContent='space-between'
                          >
                            <Box display='flex' alignItems='center'>
                              <CurrencyLogo currency={currency1} size='16px' />
                              <Typography
                                variant='caption'
                                color='textPrimary'
                                style={{ marginLeft: 6 }}
                              >
                                {pairData.token1.symbol} :
                              </Typography>
                            </Box>
                            <Typography variant='caption' color='textPrimary'>
                              {Number(pairData.reserve1).toLocaleString()}
                            </Typography>
                          </Box>
                        </Box>
                      </Box>
                      <Box mt={4}>
                        <Typography
                          variant='caption'
                          style={{ color: palette.text.disabled }}
                        >
                          7d Trading Vol
                        </Typography>
                        <Typography variant={isMobile ? 'body1' : 'h5'}>
                          ${pairData.oneWeekVolumeUSD.toLocaleString()}
                        </Typography>
                      </Box>
                      <Box mt={4}>
                        <Typography
                          variant='caption'
                          style={{ color: palette.text.disabled }}
                        >
                          24h FEES
                        </Typography>
                        <Typography variant={isMobile ? 'body1' : 'h5'}>
                          ${fees}
                        </Typography>
                      </Box>
                    </Box>
                    <Box width={140}>
                      <Typography
                        variant='caption'
                        style={{ color: palette.text.disabled }}
                      >
                        TOTAL LIQUIDITY
                      </Typography>
                      <Typography variant={isMobile ? 'body1' : 'h5'}>
                        $
                        {Number(
                          pairData.reserveUSD
                            ? pairData.reserveUSD
                            : pairData.trackedReserveUSD,
                        ).toLocaleString()}
                      </Typography>
                      <Box mt={4}>
                        <Typography
                          variant='caption'
                          style={{ color: palette.text.disabled }}
                        >
                          24h Trading Vol
                        </Typography>
                        <Typography variant={isMobile ? 'body1' : 'h5'}>
                          ${pairData.oneDayVolumeUSD.toLocaleString()}
                        </Typography>
                      </Box>
                      <Box mt={4}>
                        <Typography
                          variant='caption'
                          style={{ color: palette.text.disabled }}
                        >
                          Contract Address
                        </Typography>
                        <Typography
                          variant='h5'
                          style={{ color: palette.primary.main }}
                        >
                          {chainId ? (
                            <a
                              href={getEtherscanLink(
                                chainId,
                                pairData.id,
                                'address',
                              )}
                              target='_blank'
                              rel='noopener noreferrer'
                              style={{
                                color: palette.primary.main,
                                textDecoration: 'none',
                              }}
                            >
                              {shortenAddress(pairData.id)}
                            </a>
                          ) : (
                            shortenAddress(pairData.id)
                          )}
                        </Typography>
                      </Box>
                    </Box>
                  </Box>
                </Box>
              </Grid>
            </Grid>
          </Box>
          <Box width={1} mt={5}>
            <Typography variant='body1'>Transactions</Typography>
          </Box>
          <Box width={1} className={classes.panel} mt={4}>
            {pairTransactionsList ? (
              <TransactionsTable data={pairTransactionsList} />
            ) : (
              <Skeleton variant='rect' width='100%' height={150} />
            )}
          </Box>
        </>
      ) : (
        <Skeleton width='100%' height={100} />
      )}
    </>
  );
}
Example #9
Source File: AnalyticsTokenDetails.tsx    From interface-v2 with GNU General Public License v3.0 4 votes vote down vote up
AnalyticsTokenDetails: React.FC = () => {
  const classes = useStyles();
  const { palette, breakpoints } = useTheme();
  const isMobile = useMediaQuery(breakpoints.down('xs'));
  const history = useHistory();
  const match = useRouteMatch<{ id: string }>();
  const tokenAddress = match.params.id;
  const [token, setToken] = useState<any>(null);
  const { chainId } = useActiveWeb3React();
  const currency = token
    ? new Token(ChainId.MATIC, getAddress(token.id), token.decimals)
    : undefined;
  const [tokenPairs, updateTokenPairs] = useState<any>(null);
  const {
    bookmarkTokens,
    addBookmarkToken,
    removeBookmarkToken,
  } = useBookmarkTokens();

  useEffect(() => {
    async function fetchTokenInfo() {
      const [newPrice, oneDayPrice] = await getEthPrice();
      const tokenInfo = await getTokenInfo(newPrice, oneDayPrice, tokenAddress);
      if (tokenInfo) {
        setToken(tokenInfo[0]);
      }
    }
    fetchTokenInfo();
  }, [tokenAddress]);

  useEffect(() => {
    async function fetchTokenPairs() {
      const [newPrice] = await getEthPrice();
      const tokenPairs = await getTokenPairs2(tokenAddress);
      const formattedPairs = tokenPairs
        ? tokenPairs.map((pair: any) => {
            return pair.id;
          })
        : [];
      const pairData = await getBulkPairData(formattedPairs, newPrice);
      if (pairData) {
        updateTokenPairs(pairData);
      }
    }
    fetchTokenPairs();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [updateTokenPairs, tokenAddress]);

  const tokenPercentColor = getPriceColor(
    token ? Number(token.priceChangeUSD) : 0,
    palette,
  );

  return (
    <>
      <AnalyticsHeader type='token' data={token} />
      {token ? (
        <>
          <Box
            width={1}
            display='flex'
            flexWrap='wrap'
            justifyContent='space-between'
          >
            <Box display='flex'>
              <CurrencyLogo currency={currency} size='32px' />
              <Box ml={1.5}>
                <Box display='flex' alignItems='center'>
                  <Box display='flex' alignItems='flex-end' mr={0.5}>
                    <Typography className={classes.heading1}>
                      {token.name}{' '}
                    </Typography>
                    <Typography className={classes.heading2}>
                      ({token.symbol})
                    </Typography>
                  </Box>
                  {bookmarkTokens.includes(token.id) ? (
                    <StarChecked
                      onClick={() => removeBookmarkToken(token.id)}
                    />
                  ) : (
                    <StarUnchecked onClick={() => addBookmarkToken(token.id)} />
                  )}
                </Box>
                <Box mt={1.25} display='flex' alignItems='center'>
                  <Typography
                    variant='h5'
                    style={{ color: palette.text.primary }}
                  >
                    ${formatNumber(token.priceUSD)}
                  </Typography>
                  <Box
                    className={classes.priceChangeWrapper}
                    ml={2}
                    bgcolor={tokenPercentColor.bgColor}
                    color={tokenPercentColor.textColor}
                  >
                    <Typography variant='body2'>
                      {getFormattedPrice(Number(token.priceChangeUSD))}%
                    </Typography>
                  </Box>
                </Box>
              </Box>
            </Box>
            <Box my={2} display='flex'>
              <Box
                className={classes.button}
                mr={1.5}
                border={`1px solid ${palette.primary.main}`}
                onClick={() => {
                  history.push(`/pools?currency0=${token.id}&currency1=ETH`);
                }}
              >
                <Typography variant='body2'>Add Liquidity</Typography>
              </Box>
              <Box
                className={cx(classes.button, classes.filledButton)}
                onClick={() => {
                  history.push(`/swap?currency0=${token.id}&currency1=ETH`);
                }}
              >
                <Typography variant='body2'>Swap</Typography>
              </Box>
            </Box>
          </Box>
          <Box width={1} className={classes.panel} mt={4}>
            <Grid container>
              <Grid item xs={12} sm={12} md={6}>
                <AnalyticsTokenChart token={token} />
              </Grid>
              <Grid item xs={12} sm={12} md={6}>
                <Box
                  my={2}
                  height={1}
                  display='flex'
                  flexDirection='column'
                  alignItems='center'
                  justifyContent='center'
                >
                  <Box
                    width={isMobile ? 1 : 0.8}
                    display='flex'
                    justifyContent='space-between'
                  >
                    <Box width={180}>
                      <Typography
                        variant='caption'
                        style={{ color: palette.text.disabled }}
                      >
                        TOTAL LIQUIDITY
                      </Typography>
                      <Typography variant={isMobile ? 'body1' : 'h5'}>
                        ${token.totalLiquidityUSD.toLocaleString()}
                      </Typography>
                    </Box>
                    <Box width={140}>
                      <Typography
                        variant='caption'
                        style={{ color: palette.text.disabled }}
                      >
                        7d Trading Vol
                      </Typography>
                      <Typography variant={isMobile ? 'body1' : 'h5'}>
                        ${token.oneWeekVolumeUSD.toLocaleString()}
                      </Typography>
                    </Box>
                  </Box>
                  <Box
                    width={isMobile ? 1 : 0.8}
                    mt={4}
                    display='flex'
                    justifyContent='space-between'
                  >
                    <Box width={180}>
                      <Typography
                        variant='caption'
                        style={{ color: palette.text.disabled }}
                      >
                        24h Trading Vol
                      </Typography>
                      <Typography variant={isMobile ? 'body1' : 'h5'}>
                        ${token.oneDayVolumeUSD.toLocaleString()}
                      </Typography>
                    </Box>
                    <Box width={140}>
                      <Typography
                        variant='caption'
                        style={{ color: palette.text.disabled }}
                      >
                        24h FEES
                      </Typography>
                      <Typography variant={isMobile ? 'body1' : 'h5'}>
                        $
                        {(
                          token.oneDayVolumeUSD * GlobalConst.utils.FEEPERCENT
                        ).toLocaleString()}
                      </Typography>
                    </Box>
                  </Box>
                  <Box
                    width={isMobile ? 1 : 0.8}
                    mt={4}
                    display='flex'
                    justifyContent='space-between'
                  >
                    <Box width={180}>
                      <Typography
                        variant='caption'
                        style={{ color: palette.text.disabled }}
                      >
                        Contract Address
                      </Typography>
                      <Typography
                        variant='h5'
                        style={{ color: palette.primary.main }}
                      >
                        {chainId ? (
                          <a
                            href={getEtherscanLink(
                              chainId,
                              token.id,
                              'address',
                            )}
                            target='_blank'
                            rel='noopener noreferrer'
                            style={{
                              color: palette.primary.main,
                              textDecoration: 'none',
                            }}
                          >
                            {shortenAddress(token.id)}
                          </a>
                        ) : (
                          shortenAddress(token.id)
                        )}
                      </Typography>
                    </Box>
                  </Box>
                </Box>
              </Grid>
            </Grid>
          </Box>
          <Box width={1} mt={5}>
            <Typography variant='body1'>{token.symbol} Pools</Typography>
          </Box>
          <Box width={1} className={classes.panel} mt={4}>
            {tokenPairs ? (
              <PairTable data={tokenPairs} />
            ) : (
              <Skeleton variant='rect' width='100%' height={150} />
            )}
          </Box>
        </>
      ) : (
        <Skeleton width='100%' height={100} />
      )}
    </>
  );
}
Example #10
Source File: ImportToken.tsx    From forward.swaps with GNU General Public License v3.0 4 votes vote down vote up
export function ImportToken({ tokens, onBack, onDismiss, handleCurrencySelect }: ImportProps) {
  const theme = useTheme()

  const { chainId } = useActiveWeb3React()

  const [confirmed, setConfirmed] = useState(false)

  const addToken = useAddUserToken()

  // use for showing import source on inactive tokens
  const inactiveTokenList = useCombinedInactiveList()

  // higher warning severity if either is not on a list
  const fromLists =
    (chainId && inactiveTokenList?.[chainId]?.[tokens[0]?.address]?.list) ||
    (chainId && inactiveTokenList?.[chainId]?.[tokens[1]?.address]?.list)

  return (
    <Wrapper>
      <PaddedColumn gap="14px" style={{ width: '100%', flex: '1 1' }}>
        <RowBetween>
          {onBack ? <ArrowLeft style={{ cursor: 'pointer' }} onClick={onBack} /> : <div></div>}
          <TYPE.mediumHeader>Import {tokens.length > 1 ? 'Tokens' : 'Token'}</TYPE.mediumHeader>
          {onDismiss ? <CloseIcon onClick={onDismiss} /> : <div></div>}
        </RowBetween>
      </PaddedColumn>
      <SectionBreak />
      <PaddedColumn gap="md">
        {tokens.map(token => {
          const list = chainId && inactiveTokenList?.[chainId]?.[token.address]?.list
          return (
            <Card backgroundColor={theme.bg2} key={'import' + token.address} className=".token-warning-container">
              <AutoColumn gap="10px">
                <AutoRow align="center">
                  <CurrencyLogo currency={token} size={'24px'} />
                  <TYPE.body ml="8px" mr="8px" fontWeight={500}>
                    {token.symbol}
                  </TYPE.body>
                  <TYPE.darkGray fontWeight={300}>{token.name}</TYPE.darkGray>
                </AutoRow>
                {chainId && (
                  <ExternalLink href={getEtherscanLink(chainId, token.address, 'address')}>
                    <AddressText>{token.address}</AddressText>
                  </ExternalLink>
                )}
                {list !== undefined ? (
                  <RowFixed>
                    {list.logoURI && <ListLogo logoURI={list.logoURI} size="12px" />}
                    <TYPE.small ml="6px" color={theme.text3}>
                      via {list.name}
                    </TYPE.small>
                  </RowFixed>
                ) : (
                  <WarningWrapper borderRadius="4px" padding="4px" highWarning={true}>
                    <RowFixed>
                      <AlertTriangle stroke={theme.red1} size="10px" />
                      <TYPE.body color={theme.red1} ml="4px" fontSize="10px" fontWeight={500}>
                        Unkown Source
                      </TYPE.body>
                    </RowFixed>
                  </WarningWrapper>
                )}
              </AutoColumn>
            </Card>
          )
        })}

        <Card
          style={{ backgroundColor: fromLists ? transparentize(0.8, theme.yellow2) : transparentize(0.8, theme.red1) }}
        >
          <AutoColumn justify="center" style={{ textAlign: 'center', gap: '16px', marginBottom: '12px' }}>
            <AlertTriangle stroke={fromLists ? theme.yellow2 : theme.red1} size={32} />
            <TYPE.body fontWeight={600} fontSize={20} color={fromLists ? theme.yellow2 : theme.red1}>
              Trade at your own risk!
            </TYPE.body>
          </AutoColumn>

          <AutoColumn style={{ textAlign: 'center', gap: '16px', marginBottom: '12px' }}>
            <TYPE.body fontWeight={400} color={fromLists ? theme.yellow2 : theme.red1}>
              Anyone can create a token, including creating fake versions of existing tokens that claim to represent
              projects.
            </TYPE.body>
            <TYPE.body fontWeight={600} color={fromLists ? theme.yellow2 : theme.red1}>
              If you purchase this token, you may not be able to sell it back.
            </TYPE.body>
          </AutoColumn>
          <AutoRow justify="center" style={{ cursor: 'pointer' }} onClick={() => setConfirmed(!confirmed)}>
            <Checkbox
              className=".understand-checkbox"
              name="confirmed"
              type="checkbox"
              checked={confirmed}
              onChange={() => setConfirmed(!confirmed)}
            />
            <TYPE.body ml="10px" fontSize="16px" color={fromLists ? theme.yellow2 : theme.red1} fontWeight={500}>
              I understand
            </TYPE.body>
          </AutoRow>
        </Card>
        <ButtonPrimary
          disabled={!confirmed}
          altDisabledStyle={true}
          borderRadius="20px"
          padding="10px 1rem"
          onClick={() => {
            tokens.map(token => addToken(token))
            handleCurrencySelect && handleCurrencySelect(tokens[0])
          }}
          className=".token-dismiss-button"
        >
          Import
        </ButtonPrimary>
      </PaddedColumn>
    </Wrapper>
  )
}
Example #11
Source File: ManageTokens.tsx    From forward.swaps with GNU General Public License v3.0 4 votes vote down vote up
export default function ManageTokens({
  setModalView,
  setImportToken
}: {
  setModalView: (view: CurrencyModalView) => void
  setImportToken: (token: Token) => void
}) {
  const { chainId } = useActiveWeb3React()

  const [searchQuery, setSearchQuery] = useState<string>('')
  const theme = useTheme()

  // manage focus on modal show
  const inputRef = useRef<HTMLInputElement>()
  const handleInput = useCallback(event => {
    const input = event.target.value
    const checksummedInput = isAddress(input)
    setSearchQuery(checksummedInput || input)
  }, [])

  // if they input an address, use it
  const isAddressSearch = isAddress(searchQuery)
  const searchToken = useToken(searchQuery)

  // all tokens for local lisr
  const userAddedTokens: Token[] = useUserAddedTokens()
  const removeToken = useRemoveUserAddedToken()

  const handleRemoveAll = useCallback(() => {
    if (chainId && userAddedTokens) {
      userAddedTokens.map(token => {
        return removeToken(chainId, token.address)
      })
    }
  }, [removeToken, userAddedTokens, chainId])

  const tokenList = useMemo(() => {
    return (
      chainId &&
      userAddedTokens.map(token => (
        <RowBetween key={token.address} width="100%">
          <RowFixed>
            <CurrencyLogo currency={token} size={'20px'} />
            <ExternalLink href={getEtherscanLink(chainId, token.address, 'address')}>
              <TYPE.main ml={'10px'} fontWeight={600}>
                {token.symbol}
              </TYPE.main>
            </ExternalLink>
          </RowFixed>
          <RowFixed>
            <TrashIcon onClick={() => removeToken(chainId, token.address)} />
            <ExternalLinkIcon href={getEtherscanLink(chainId, token.address, 'address')} />
          </RowFixed>
        </RowBetween>
      ))
    )
  }, [userAddedTokens, chainId, removeToken])

  return (
    <Wrapper>
      <Column style={{ width: '100%', flex: '1 1' }}>
        <PaddedColumn gap="14px">
          <Row>
            <SearchInput
              type="text"
              id="token-search-input"
              placeholder={'0x0000'}
              value={searchQuery}
              autoComplete="off"
              ref={inputRef as RefObject<HTMLInputElement>}
              onChange={handleInput}
            />
          </Row>
          {searchQuery !== '' && !isAddressSearch && <TYPE.error error={true}>Enter valid token address</TYPE.error>}
          {searchToken && (
            <Card backgroundColor={theme.bg2} padding="10px 0">
              <ImportRow
                token={searchToken}
                showImportView={() => setModalView(CurrencyModalView.importToken)}
                setImportToken={setImportToken}
                style={{ height: 'fit-content' }}
              />
            </Card>
          )}
        </PaddedColumn>
        <Separator />
        <PaddedColumn gap="lg">
          <RowBetween>
            <TYPE.main fontWeight={600}>
              {userAddedTokens?.length} Custom {userAddedTokens.length === 1 ? 'Token' : 'Tokens'}
            </TYPE.main>
            {userAddedTokens.length > 0 && (
              <ButtonText onClick={handleRemoveAll}>
                <TYPE.blue>Clear all</TYPE.blue>
              </ButtonText>
            )}
          </RowBetween>
          {tokenList}
        </PaddedColumn>
      </Column>
      <Footer>
        <TYPE.darkGray>Tip: Custom tokens are stored locally in your browser</TYPE.darkGray>
      </Footer>
    </Wrapper>
  )
}