utils#shortenAddress TypeScript Examples
The following examples show how to use
utils#shortenAddress.
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: REPMintInfoLine.tsx From dxvote with GNU Affero General Public License v3.0 | 6 votes |
REPMintInfoLine: React.FC<ActionViewProps> = ({ decodedCall }) => {
const { parsedData } = useTotalSupply({ decodedCall });
const { tokenData } = useTokenData();
const totalSupply = useBigNumberToNumber(tokenData?.totalSupply, 18);
const { ensName, imageUrl } = useENSAvatar(parsedData?.toAddress, MAINNET_ID);
const roundedRepAmount = useBigNumberToNumber(parsedData?.amount, 16, 3);
const roundedRepPercent = roundedRepAmount / totalSupply;
return (
<>
<Segment>
<StyledMintIcon src={Mint} />
</Segment>
<Segment>Mint {roundedRepPercent} %</Segment>
<Segment>
<FiArrowRight />
</Segment>
<Segment>
<Avatar defaultSeed={parsedData?.toAddress} src={imageUrl} size={24} />
</Segment>
<Segment>{ensName || shortenAddress(parsedData?.toAddress)}</Segment>
</>
);
}
Example #2
Source File: REPMintSummary.tsx From dxvote with GNU Affero General Public License v3.0 | 6 votes |
REPMintSummary: React.FC<ActionViewProps> = ({ decodedCall }) => {
const { parsedData } = useTotalSupply({ decodedCall });
const { tokenData } = useTokenData();
const { ensName, imageUrl } = useENSAvatar(parsedData?.toAddress, MAINNET_ID);
const roundedRepAmount = useBigNumberToNumber(parsedData?.amount, 18, 3);
return (
<>
<DetailHeader>
<DetailCell>Receiver</DetailCell>
<DetailCell>Amount</DetailCell>
</DetailHeader>
<DetailRow>
<DetailCell>
<Segment>
<Avatar
defaultSeed={parsedData?.toAddress}
src={imageUrl}
size={24}
/>
</Segment>
<Segment>{ensName || shortenAddress(parsedData?.toAddress)}</Segment>
</DetailCell>
<DetailCell>
{roundedRepAmount} {tokenData?.name}
</DetailCell>
</DetailRow>
</>
);
}
Example #3
Source File: ERC20TransferSummary.tsx From dxvote with GNU Affero General Public License v3.0 | 5 votes |
ERC20TransferSummary: React.FC<ActionViewProps> = ({ decodedCall }) => {
const parsedData = useMemo(() => {
if (!decodedCall) return null;
return {
tokenAddress: decodedCall.to,
amount: BigNumber.from(decodedCall.args._value),
source: decodedCall.from,
destination: decodedCall.args._to,
};
}, [decodedCall]);
const { data: tokenInfo } = useERC20Info(parsedData?.tokenAddress);
const roundedBalance = useBigNumberToNumber(
parsedData?.amount,
tokenInfo?.decimals,
4
);
const { ensName, imageUrl } = useENSAvatar(
parsedData?.destination,
MAINNET_ID
);
return (
<>
<DetailHeader>
<DetailCell>Receiver</DetailCell>
<DetailCell>Amount</DetailCell>
</DetailHeader>
<DetailRow>
<DetailCell>
<Segment>
<Avatar
defaultSeed={parsedData?.destination}
src={imageUrl}
size={24}
/>
</Segment>
<Segment>
{ensName || shortenAddress(parsedData?.destination)}
</Segment>
</DetailCell>
<DetailCell>
{roundedBalance} {tokenInfo?.symbol}
</DetailCell>
</DetailRow>
</>
);
}
Example #4
Source File: ERC20TransferInfoLine.tsx From dxvote with GNU Affero General Public License v3.0 | 5 votes |
ERC20TransferInfoLine: React.FC<ActionViewProps> = ({ decodedCall }) => {
const parsedData = useMemo(() => {
if (!decodedCall) return null;
return {
tokenAddress: decodedCall.to,
amount: BigNumber.from(decodedCall.args._value),
source: decodedCall.from,
destination: decodedCall.args._to as string,
};
}, [decodedCall]);
const { data: tokenInfo } = useERC20Info(parsedData?.tokenAddress);
const roundedBalance = useBigNumberToNumber(
parsedData?.amount,
tokenInfo?.decimals,
4
);
const { ensName, imageUrl } = useENSAvatar(
parsedData?.destination,
MAINNET_ID
);
return (
<>
<Segment>
<FiNavigation size={16} />
</Segment>
<Segment>
Transfer {roundedBalance} {tokenInfo?.symbol}
</Segment>
<Segment>
<FiArrowRight />
</Segment>
<Segment>
<Avatar
defaultSeed={parsedData?.destination}
src={imageUrl}
size={24}
/>
</Segment>
<Segment>
{ensName || parsedData?.destination
? shortenAddress(parsedData?.destination)
: ''}
</Segment>
</>
);
}
Example #5
Source File: Wallet.tsx From frontend-v1 with GNU Affero General Public License v3.0 | 5 votes |
Wallet: FC = () => {
const { account, isConnected, chainId } = useConnection();
const [isOpen, setIsOpen] = useState(false);
const modalRef = useRef(null);
const { trackEvent } = useMatomo();
useClickOutsideModal(modalRef, () => setIsOpen(false));
// Note: this must be before early returns.
useEffect(() => {
if (!isConnected && isOpen) setIsOpen(false);
}, [isConnected, isOpen]);
const disconnectWallet = () => {
setIsOpen(false);
reset();
};
// Add Matomo helpers for connect/disconnect
const initWithMatomo = () => {
// Matomo track wallet connect
// TODO: Eventually add address to `name` field
trackEvent({ category: "wallet", action: "connect", name: "null" });
init();
};
const disconnectWithMatomo = () => {
// Matomo track wallet disconnect
// TODO: Eventually add address to `name` field
trackEvent({ category: "wallet", action: "disconnect", name: "null" });
disconnectWallet();
};
const { data: balance } = useETHBalance(
{ account: account ?? "", chainId: chainId ?? DEFAULT_FROM_CHAIN_ID },
{ skip: !isConnected }
);
if (account && !isConnected && !chainId) {
return (
<UnsupportedNetwork>
Unsupported network. Please change networks.
</UnsupportedNetwork>
);
}
if (!isConnected) {
return (
<ConnectButton onClick={initWithMatomo}>Connect Wallet</ConnectButton>
);
}
return (
<div ref={modalRef}>
<Wrapper onClick={() => setIsOpen(!isOpen)}>
<Info>
<div>
{formatEther(balance ?? "0")}{" "}
{CHAINS[chainId ?? 1].nativeCurrency.symbol}
</div>
<div>{CHAINS[chainId ?? 1].name}</div>
</Info>
<Account>{shortenAddress(account ?? "")}</Account>
</Wrapper>
{isOpen && (
<WalletModal>
<WalletModalHeader>Connected</WalletModalHeader>
<WalletModalAccount>{account}</WalletModalAccount>
<WalletModalChain>{CHAINS[chainId ?? 1].name}</WalletModalChain>
<WalletModalDisconnect onClick={() => disconnectWithMatomo()}>
Disconnect
</WalletModalDisconnect>
</WalletModal>
)}
</div>
);
}
Example #6
Source File: SwapModalHeader.tsx From glide-frontend with GNU General Public License v3.0 | 4 votes |
export default function SwapModalHeader({
trade,
allowedSlippage,
recipient,
showAcceptChanges,
onAcceptChanges,
}: {
trade: Trade
allowedSlippage: number
recipient: string | null
showAcceptChanges: boolean
onAcceptChanges: () => void
}) {
const { t } = useTranslation()
const slippageAdjustedAmounts = useMemo(
() => computeSlippageAdjustedAmounts(trade, allowedSlippage),
[trade, allowedSlippage],
)
const { priceImpactWithoutFee } = useMemo(() => computeTradePriceBreakdown(trade), [trade])
const priceImpactSeverity = warningSeverity(priceImpactWithoutFee)
return (
<AutoColumn gap="md">
<RowBetween align="flex-end">
<RowFixed gap="0px">
<CurrencyLogo currency={trade.inputAmount.currency} size="24px" style={{ marginRight: '12px' }} />
<TruncatedText
fontSize="24px"
color={showAcceptChanges && trade.tradeType === TradeType.EXACT_OUTPUT ? 'primary' : 'text'}
>
{trade.inputAmount.toSignificant(6)}
</TruncatedText>
</RowFixed>
<RowFixed gap="0px">
<Text fontSize="24px" ml="10px">
{trade.inputAmount.currency.symbol}
</Text>
</RowFixed>
</RowBetween>
<RowFixed>
<ArrowDownIcon width="16px" ml="4px" />
</RowFixed>
<RowBetween align="flex-end">
<RowFixed gap="0px">
<CurrencyLogo currency={trade.outputAmount.currency} size="24px" style={{ marginRight: '12px' }} />
<TruncatedText
fontSize="24px"
color={
priceImpactSeverity > 2
? 'failure'
: showAcceptChanges && trade.tradeType === TradeType.EXACT_INPUT
? 'primary'
: 'text'
}
>
{trade.outputAmount.toSignificant(6)}
</TruncatedText>
</RowFixed>
<RowFixed gap="0px">
<Text fontSize="24px" ml="10px">
{trade.outputAmount.currency.symbol}
</Text>
</RowFixed>
</RowBetween>
{showAcceptChanges ? (
<SwapShowAcceptChanges justify="flex-start" gap="0px">
<RowBetween>
<RowFixed>
<ErrorIcon mr="8px" />
<Text bold> {t('Price Updated')}</Text>
</RowFixed>
<Button onClick={onAcceptChanges}>{t('Accept')}</Button>
</RowBetween>
</SwapShowAcceptChanges>
) : null}
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '24px 0 0 0px' }}>
{trade.tradeType === TradeType.EXACT_INPUT ? (
<Text small color="textSubtle" textAlign="left" style={{ width: '100%' }}>
{t(`Output is estimated. You will receive at least`)}{' '}
<b>
{slippageAdjustedAmounts[Field.OUTPUT]?.toSignificant(6)} {trade.outputAmount.currency.symbol}
</b>
{' '}{t('or the transaction will revert.')}
</Text>
) : (
<Text small color="textSubtle" textAlign="left" style={{ width: '100%' }}>
{t(`Input is estimated. You will sell at most`)}{' '}
<b>
{slippageAdjustedAmounts[Field.INPUT]?.toSignificant(6)} {trade.inputAmount.currency.symbol}
</b>
{' '}{t('or the transaction will revert.')}
</Text>
)}
</AutoColumn>
{recipient !== null ? (
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
<Text color="textSubtle">
{t('Output will be sent to')}{' '}
<b title={recipient}>{isAddress(recipient) ? shortenAddress(recipient) : recipient}</b>
</Text>
</AutoColumn>
) : null}
</AutoColumn>
)
}
Example #7
Source File: SwapModalHeader.tsx From glide-frontend with GNU General Public License v3.0 | 4 votes |
export default function SwapModalHeader({
trade,
allowedSlippage,
recipient,
showAcceptChanges,
onAcceptChanges,
}: {
trade: Trade
allowedSlippage: number
recipient: string | null
showAcceptChanges: boolean
onAcceptChanges: () => void
}) {
const slippageAdjustedAmounts = useMemo(
() => computeSlippageAdjustedAmounts(trade, allowedSlippage),
[trade, allowedSlippage],
)
const { priceImpactWithoutFee } = useMemo(() => computeTradePriceBreakdown(trade), [trade])
const priceImpactSeverity = warningSeverity(priceImpactWithoutFee)
return (
<AutoColumn gap="md">
<RowBetween align="flex-end">
<RowFixed gap="0px">
<CurrencyLogo currency={trade.inputAmount.currency} size="24px" style={{ marginRight: '12px' }} />
<TruncatedText
fontSize="24px"
color={showAcceptChanges && trade.tradeType === TradeType.EXACT_OUTPUT ? 'primary' : 'text'}
>
{trade.inputAmount.toSignificant(6)}
</TruncatedText>
</RowFixed>
<RowFixed gap="0px">
<Text fontSize="24px" ml="10px">
{trade.inputAmount.currency.symbol}
</Text>
</RowFixed>
</RowBetween>
<RowFixed>
<ArrowDownIcon width="16px" ml="4px" />
</RowFixed>
<RowBetween align="flex-end">
<RowFixed gap="0px">
<CurrencyLogo currency={trade.outputAmount.currency} size="24px" style={{ marginRight: '12px' }} />
<TruncatedText
fontSize="24px"
color={
priceImpactSeverity > 2
? 'failure'
: showAcceptChanges && trade.tradeType === TradeType.EXACT_INPUT
? 'primary'
: 'text'
}
>
{trade.outputAmount.toSignificant(6)}
</TruncatedText>
</RowFixed>
<RowFixed gap="0px">
<Text fontSize="24px" ml="10px">
{trade.outputAmount.currency.symbol}
</Text>
</RowFixed>
</RowBetween>
{showAcceptChanges ? (
<SwapShowAcceptChanges justify="flex-start" gap="0px">
<RowBetween>
<RowFixed>
<ErrorIcon mr="8px" />
<Text bold> Price Updated</Text>
</RowFixed>
<Button onClick={onAcceptChanges}>Accept</Button>
</RowBetween>
</SwapShowAcceptChanges>
) : null}
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '24px 0 0 0px' }}>
{trade.tradeType === TradeType.EXACT_INPUT ? (
<Text small color="textSubtle" textAlign="left" style={{ width: '100%' }}>
{`Output is estimated. You will receive at least `}
<b>
{slippageAdjustedAmounts[Field.OUTPUT]?.toSignificant(6)} {trade.outputAmount.currency.symbol}
</b>
{' or the transaction will revert.'}
</Text>
) : (
<Text small color="textSubtle" textAlign="left" style={{ width: '100%' }}>
{`Input is estimated. You will sell at most `}
<b>
{slippageAdjustedAmounts[Field.INPUT]?.toSignificant(6)} {trade.inputAmount.currency.symbol}
</b>
{' or the transaction will revert.'}
</Text>
)}
</AutoColumn>
{recipient !== null ? (
<AutoColumn justify="flex-start" gap="sm" style={{ padding: '12px 0 0 0px' }}>
<Text color="textSubtle">
Output will be sent to{' '}
<b title={recipient}>{isAddress(recipient) ? shortenAddress(recipient) : recipient}</b>
</Text>
</AutoColumn>
) : null}
</AutoColumn>
)
}
Example #8
Source File: index.test.ts From glide-frontend with GNU General Public License v3.0 | 4 votes |
describe('utils', () => {
describe('#getBscScanLink', () => {
it('correct for tx', () => {
expect(getBscScanLink('abc', 'transaction', ChainId.MAINNET)).toEqual('https://explorer.com/tx/abc')
})
it('correct for token', () => {
expect(getBscScanLink('abc', 'token', ChainId.MAINNET)).toEqual('https://explorer.com/token/abc')
})
it('correct for address', () => {
expect(getBscScanLink('abc', 'address', ChainId.MAINNET)).toEqual('https://explorer.com/address/abc')
})
it('enum', () => {
expect(getBscScanLink('abc', 'address', ChainId.TESTNET)).toEqual('https://testnet.explorer.com/address/abc')
})
})
describe('#calculateSlippageAmount', () => {
it('bounds are correct', () => {
const tokenAmount = new TokenAmount(new Token(ChainId.MAINNET, AddressZero, 0), '100')
expect(() => calculateSlippageAmount(tokenAmount, -1)).toThrow()
expect(calculateSlippageAmount(tokenAmount, 0).map((bound) => bound.toString())).toEqual(['100', '100'])
expect(calculateSlippageAmount(tokenAmount, 100).map((bound) => bound.toString())).toEqual(['99', '101'])
expect(calculateSlippageAmount(tokenAmount, 200).map((bound) => bound.toString())).toEqual(['98', '102'])
expect(calculateSlippageAmount(tokenAmount, 10000).map((bound) => bound.toString())).toEqual(['0', '200'])
expect(() => calculateSlippageAmount(tokenAmount, 10001)).toThrow()
})
})
describe('#isAddress', () => {
it('returns false if not', () => {
expect(isAddress('')).toBe(false)
expect(isAddress('0x0000')).toBe(false)
expect(isAddress(1)).toBe(false)
expect(isAddress({})).toBe(false)
expect(isAddress(undefined)).toBe(false)
})
it('returns the checksummed address', () => {
expect(isAddress('0xf164fc0ec4e93095b804a4795bbe1e041497b92a')).toBe('0xf164fC0Ec4E93095b804a4795bBe1e041497b92a')
expect(isAddress('0xf164fC0Ec4E93095b804a4795bBe1e041497b92a')).toBe('0xf164fC0Ec4E93095b804a4795bBe1e041497b92a')
})
it('succeeds even without prefix', () => {
expect(isAddress('f164fc0ec4e93095b804a4795bbe1e041497b92a')).toBe('0xf164fC0Ec4E93095b804a4795bBe1e041497b92a')
})
it('fails if too long', () => {
expect(isAddress('f164fc0ec4e93095b804a4795bbe1e041497b92a0')).toBe(false)
})
})
describe('#shortenAddress', () => {
it('throws on invalid address', () => {
expect(() => shortenAddress('abc')).toThrow("Invalid 'address'")
})
it('truncates middle characters', () => {
expect(shortenAddress('0xf164fc0ec4e93095b804a4795bbe1e041497b92a')).toBe('0xf164...b92a')
})
it('truncates middle characters even without prefix', () => {
expect(shortenAddress('f164fc0ec4e93095b804a4795bbe1e041497b92a')).toBe('0xf164...b92a')
})
it('renders checksummed address', () => {
expect(shortenAddress('0x2E1b342132A67Ea578e4E3B814bae2107dc254CC'.toLowerCase())).toBe('0x2E1b...54CC')
})
})
describe('#calculateGasMargin', () => {
it('adds 10%', () => {
expect(calculateGasMargin(BigNumber.from(1000)).toString()).toEqual('1100')
expect(calculateGasMargin(BigNumber.from(50)).toString()).toEqual('55')
})
})
describe('#basisPointsToPercent', () => {
it('converts basis points numbers to percents', () => {
expect(basisPointsToPercent(100).equalTo(new Percent(JSBI.BigInt(1), JSBI.BigInt(100)))).toBeTruthy()
expect(basisPointsToPercent(500).equalTo(new Percent(JSBI.BigInt(5), JSBI.BigInt(100)))).toBeTruthy()
expect(basisPointsToPercent(50).equalTo(new Percent(JSBI.BigInt(5), JSBI.BigInt(1000)))).toBeTruthy()
})
})
})
Example #9
Source File: AddressSelection.tsx From frontend-v1 with GNU Affero General Public License v3.0 | 4 votes |
AddressSelection: React.FC = () => {
const { isConnected } = useConnection();
const { toChain, toAddress, fromChain, setToAddress } = useSend();
const [address, setAddress] = useState("");
const [open, setOpen] = useState(false);
const dispatch = useAppDispatch();
const sendState = useAppSelector((state) => state.send);
const { trackEvent } = useMatomo();
const {
isOpen,
selectedItem,
getLabelProps,
getToggleButtonProps,
getItemProps,
getMenuProps,
} = useSelect({
items: CHAINS_SELECTION,
defaultSelectedItem: sendState.currentlySelectedToChain,
selectedItem: sendState.currentlySelectedToChain,
onSelectedItemChange: ({ selectedItem }) => {
if (selectedItem) {
// Matomo track toChain selection
trackEvent({
category: "send",
action: "setToChain",
name: selectedItem.chainId.toString(),
});
const nextState = { ...sendState, toChain: selectedItem.chainId };
dispatch(actions.toChain(nextState));
dispatch(actions.updateSelectedToChain(selectedItem));
const nsToChain = { ...sendState };
if (selectedItem.chainId === ChainId.MAINNET) {
nsToChain.fromChain = ChainId.OPTIMISM;
dispatch(actions.fromChain(nsToChain));
dispatch(actions.updateSelectedFromChain(CHAINS_SELECTION[0]));
}
}
},
});
useEffect(() => {
if (toAddress) {
setAddress(toAddress);
}
}, [toAddress]);
const toggle = () => {
// modal is closing, reset address to the current toAddress
if (!isConnected) return;
if (open) setAddress(toAddress || address);
setOpen((oldOpen) => !oldOpen);
};
const clearInput = () => {
setAddress("");
};
const handleChange = (evt: React.ChangeEvent<HTMLInputElement>) => {
setAddress(evt.target.value);
};
const isValid = !address || isValidAddress(address);
const handleSubmit = () => {
if (isValid && address) {
setToAddress({ toAddress: address });
toggle();
}
};
const isL1toL2 = fromChain === ChainId.MAINNET;
return (
<AnimatePresence>
<LastSection>
<Wrapper>
<SectionTitle>To</SectionTitle>
<InputGroup>
<RoundBox as="label" {...getLabelProps()}>
<ToggleButton type="button" {...getToggleButtonProps()}>
<Logo src={selectedItem?.logoURI} alt={selectedItem?.name} />
<div>
<ToggleChainName>
{selectedItem?.name === "Ether"
? "Mainnet"
: selectedItem?.name}
</ToggleChainName>
{toAddress && <Address>{shortenAddress(toAddress)}</Address>}
</div>
<ToggleIcon />
</ToggleButton>
</RoundBox>
<Menu isOpen={isOpen} {...getMenuProps()}>
{isOpen &&
sendState.currentlySelectedToChain.chainId !==
ChainId.MAINNET &&
CHAINS_SELECTION.map((t, index) => {
return (
<Item
className={
t === sendState.currentlySelectedToChain ||
t.chainId === ChainId.MAINNET
? "disabled"
: ""
}
{...getItemProps({ item: t, index })}
key={t.chainId}
>
<Logo src={t.logoURI} alt={t.name} />
<div>{t.name}</div>
<span className="layer-type">
{t.chainId !== ChainId.MAINNET ? "L2" : "L1"}
</span>
</Item>
);
})}
{isOpen &&
sendState.currentlySelectedToChain.chainId ===
ChainId.MAINNET && (
<>
<ItemWarning
initial={{ y: -10 }}
animate={{ y: 0 }}
exit={{ y: -10 }}
>
<p>
Transfers between L2 chains is not possible at this time
</p>
</ItemWarning>
{CHAINS_SELECTION.map((t, index) => {
return (
<Item
className={"disabled"}
{...getItemProps({ item: t, index })}
key={t.chainId}
initial={{ y: -10 }}
animate={{ y: 0 }}
exit={{ y: -10 }}
>
<Logo src={t.logoURI} alt={t.name} />
<div>{t.name}</div>
<span className="layer-type">
{index !== CHAINS_SELECTION.length - 1
? "L2"
: "L1"}
</span>
</Item>
);
})}
</>
)}
</Menu>
</InputGroup>
{!isL1toL2 && (
<ChangeWrapper onClick={toggle}>
<ChangeButton className={!isConnected ? "disabled" : ""}>
Change account
</ChangeButton>
</ChangeWrapper>
)}
</Wrapper>
<Dialog isOpen={open} onClose={toggle}>
<h3>Send To</h3>
<div>Address on {CHAINS[toChain].name}</div>
<InputWrapper>
<Input onChange={handleChange} value={address} />
<ClearButton onClick={clearInput}>
<XOctagon
fill="var(--color-gray-300)"
stroke="var(--color-white)"
/>
</ClearButton>
{!isValid && <InputError>Not a valid address</InputError>}
</InputWrapper>
<ButtonGroup>
<CancelButton onClick={toggle}>Cancel</CancelButton>
<SecondaryButton
onClick={handleSubmit}
disabled={!isValid || !address}
>
Save Changes
</SecondaryButton>
</ButtonGroup>
</Dialog>
</LastSection>
</AnimatePresence>
);
}
Example #10
Source File: AnalyticsTokenDetails.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
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}¤cy1=ETH`);
}}
>
<Typography variant='body2'>Add Liquidity</Typography>
</Box>
<Box
className={cx(classes.button, classes.filledButton)}
onClick={() => {
history.push(`/swap?currency0=${token.id}¤cy1=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 #11
Source File: AnalyticsPairDetails.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
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}¤cy1=${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}¤cy1=${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 #12
Source File: AnalyticsHeader.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
AnalyticsHeader: React.FC<AnalyticHeaderProps> = ({ data, type }) => {
const classes = useStyles();
const { palette } = useTheme();
const history = useHistory();
const { pathname } = useLocation();
return (
<Box width='100%' mb={3}>
<Box mb={4}>
<Typography variant='h4'>Quickswap Analytics</Typography>
</Box>
<Box
mb={4}
position='relative'
display='flex'
justifyContent='space-between'
flexWrap='wrap'
>
<Box marginY={1.5} display='flex' alignItems='center'>
{type && data && (
<Box display='flex' alignItems='center' color={palette.text.hint}>
<Typography
variant='caption'
className={classes.link}
onClick={() => {
history.push('/analytics');
}}
>
Analytics
</Typography>
<ArrowForwardIos style={{ width: 16 }} />
<Typography
variant='caption'
className={classes.link}
onClick={() => {
history.push(`/analytics/${type}s`);
}}
>
{type === 'token' ? 'Tokens' : 'Pairs'}
</Typography>
<ArrowForwardIos style={{ width: 16 }} />
<Typography variant='caption'>
<span style={{ color: '#b6b9cc' }}>
{type === 'token'
? data.symbol
: `${data.token0.symbol}/${data.token1.symbol}`}
</span>
({shortenAddress(data.id)})
</Typography>
</Box>
)}
{!type && (
<>
<Box
className={cx(
classes.topTab,
pathname.indexOf('pair') === -1 &&
pathname.indexOf('token') === -1 &&
classes.selectedTab,
)}
onClick={() => history.push(`/analytics`)}
>
<Typography variant='body1'>Overview</Typography>
</Box>
<Box
className={cx(
classes.topTab,
pathname.indexOf('token') > -1 && classes.selectedTab,
)}
onClick={() => history.push(`/analytics/tokens`)}
>
<Typography variant='body1'>Tokens</Typography>
</Box>
<Box
className={cx(
classes.topTab,
pathname.indexOf('pair') > -1 && classes.selectedTab,
)}
onClick={() => history.push(`/analytics/pairs`)}
>
<Typography variant='body1'>Pairs</Typography>
</Box>
</>
)}
</Box>
<Search />
</Box>
</Box>
);
}
Example #13
Source File: useSwapCallback.ts From interface-v2 with GNU General Public License v3.0 | 4 votes |
// returns a function that will execute a swap, if the parameters are all valid
// and the user has approved the slippage adjusted input amount for the trade
export function useSwapCallback(
trade: Trade | undefined, // trade to execute, required
allowedSlippage: number = GlobalConst.utils.INITIAL_ALLOWED_SLIPPAGE, // in bips
recipientAddressOrName: string | null, // the ENS name or address of the recipient of the trade, or null if swap should be returned to sender
): {
state: SwapCallbackState;
callback:
| null
| (() => Promise<{ response: TransactionResponse; summary: string }>);
error: string | null;
} {
const { account, chainId, library } = useActiveWeb3React();
const swapCalls = useSwapCallArguments(
trade,
allowedSlippage,
recipientAddressOrName,
);
const addTransaction = useTransactionAdder();
const { address: recipientAddress } = useENS(recipientAddressOrName);
const recipient =
recipientAddressOrName === null ? account : recipientAddress;
return useMemo(() => {
if (!trade || !library || !account || !chainId) {
return {
state: SwapCallbackState.INVALID,
callback: null,
error: 'Missing dependencies',
};
}
if (!recipient) {
if (recipientAddressOrName !== null) {
return {
state: SwapCallbackState.INVALID,
callback: null,
error: 'Invalid recipient',
};
} else {
return {
state: SwapCallbackState.LOADING,
callback: null,
error: null,
};
}
}
const tradeVersion = Version.v2;
return {
state: SwapCallbackState.VALID,
callback: async function onSwap(): Promise<{
response: TransactionResponse;
summary: string;
}> {
const estimatedCalls: EstimatedSwapCall[] = await Promise.all(
swapCalls.map((call) => {
const {
parameters: { methodName, args, value },
contract,
} = call;
const options = !value || isZero(value) ? {} : { value };
return contract.estimateGas[methodName](...args, options)
.then((gasEstimate) => {
return {
call,
gasEstimate: gasEstimate.add(100000),
};
})
.catch((gasError) => {
console.debug(
'Gas estimate failed, trying eth_call to extract error',
call,
);
return contract.callStatic[methodName](...args, options)
.then((result) => {
console.debug(
'Unexpected successful call after failed estimate gas',
call,
gasError,
result,
);
return {
call,
error: new Error(
'Unexpected issue with estimating the gas. Please try again.',
),
};
})
.catch((callError) => {
console.debug('Call threw error', call, callError);
let errorMessage: string;
switch (callError.reason) {
case 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT':
case 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT':
errorMessage =
'This transaction will not succeed either due to price movement or fee on transfer. Try increasing your slippage tolerance.';
break;
default:
errorMessage = `The transaction cannot succeed due to error: ${callError.reason}. This is probably an issue with one of the tokens you are swapping.`;
}
return { call, error: new Error(errorMessage) };
});
});
}),
);
// a successful estimation is a bignumber gas estimate and the next call is also a bignumber gas estimate
const successfulEstimation = estimatedCalls.find(
(el, ix, list): el is SuccessfulCall =>
'gasEstimate' in el &&
(ix === list.length - 1 || 'gasEstimate' in list[ix + 1]),
);
if (!successfulEstimation) {
const errorCalls = estimatedCalls.filter(
(call): call is FailedCall => 'error' in call,
);
if (errorCalls.length > 0)
throw errorCalls[errorCalls.length - 1].error;
throw new Error(
'Unexpected error. Please contact support: none of the calls threw an error',
);
}
const {
call: {
contract,
parameters: { methodName, args, value },
},
gasEstimate,
} = successfulEstimation;
return contract[methodName](...args, {
gasLimit: calculateGasMargin(gasEstimate),
...(value && !isZero(value)
? { value, from: account }
: { from: account }),
})
.then((response: TransactionResponse) => {
const inputSymbol = trade.inputAmount.currency.symbol;
const outputSymbol = trade.outputAmount.currency.symbol;
const inputAmount = formatTokenAmount(trade.inputAmount);
const outputAmount = formatTokenAmount(trade.outputAmount);
const base = `Swap ${inputAmount} ${inputSymbol} for ${outputAmount} ${outputSymbol}`;
const withRecipient =
recipient === account
? base
: `${base} to ${
recipientAddressOrName && isAddress(recipientAddressOrName)
? shortenAddress(recipientAddressOrName)
: recipientAddressOrName
}`;
const withVersion =
tradeVersion === Version.v2
? withRecipient
: `${withRecipient} on ${(tradeVersion as any).toUpperCase()}`;
addTransaction(response, {
summary: withVersion,
});
return { response, summary: withVersion };
})
.catch((error: any) => {
// if the user rejected the tx, pass this along
if (error?.code === 4001) {
throw new Error('Transaction rejected.');
} else {
// otherwise, the error was unexpected and we need to convey that
console.error(`Swap failed`, error, methodName, args, value);
throw new Error(`Swap failed: ${error.message}`);
}
});
},
error: null,
};
}, [
trade,
library,
account,
chainId,
recipient,
recipientAddressOrName,
swapCalls,
addTransaction,
]);
}
Example #14
Source File: SwapTokenDetails.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
SwapTokenDetails: React.FC<{
token: Token;
}> = ({ token }) => {
const classes = useStyles();
const currency = unwrappedToken(token);
const tokenAddress = token.address;
const { palette } = useTheme();
const latestBlock = useBlockNumber();
const { tokenDetails, updateTokenDetails } = useTokenDetails();
const [tokenData, setTokenData] = useState<any>(null);
const [priceData, setPriceData] = useState<any>(null);
const priceUp = Number(tokenData?.priceChangeUSD) > 0;
const priceUpPercent = Number(tokenData?.priceChangeUSD).toFixed(2);
const [isCopied, setCopied] = useCopyClipboard();
const prices = priceData ? priceData.map((price: any) => price.close) : [];
useEffect(() => {
async function fetchTokenData() {
const tokenDetail = tokenDetails.find(
(item) => item.address === tokenAddress,
);
setTokenData(tokenDetail?.tokenData);
setPriceData(tokenDetail?.priceData);
const currentTime = dayjs.utc();
const startTime = currentTime
.subtract(1, 'day')
.startOf('hour')
.unix();
const tokenPriceData = await getIntervalTokenData(
tokenAddress,
startTime,
3600,
latestBlock,
);
setPriceData(tokenPriceData);
const [newPrice, oneDayPrice] = await getEthPrice();
const tokenInfo = await getTokenInfo(newPrice, oneDayPrice, tokenAddress);
if (tokenInfo) {
const token0 = tokenInfo[0];
setTokenData(token0);
const tokenDetailToUpdate = {
address: tokenAddress,
tokenData: token0,
priceData: tokenPriceData,
};
updateTokenDetails(tokenDetailToUpdate);
}
}
fetchTokenData();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [tokenAddress]);
return (
<Box>
<Box
display='flex'
alignItems='center'
justifyContent='space-between'
px={2}
py={1.5}
>
<Box display='flex' alignItems='center'>
<CurrencyLogo currency={currency} size='28px' />
<Box ml={1}>
<Typography variant='body2'>{currency.symbol}</Typography>
{tokenData ? (
<Box display='flex' alignItems='center'>
<Typography variant='body2'>
${formatNumber(tokenData.priceUSD)}
</Typography>
<Box
ml={0.5}
display='flex'
alignItems='center'
className={priceUp ? classes.success : classes.danger}
>
{priceUp ? <ArrowDropUp /> : <ArrowDropDown />}
<Typography variant='body2'>{priceUpPercent}%</Typography>
</Box>
</Box>
) : (
<Skeleton variant='rect' width={100} height={20} />
)}
</Box>
</Box>
{tokenData && priceData ? (
<Box width={88} height={47} position='relative'>
<Box position='absolute' top={-30} width={1}>
{prices.length > 0 && (
<LineChart
data={prices}
width='100%'
height={120}
color={priceUp ? palette.success.main : palette.error.main}
/>
)}
</Box>
</Box>
) : (
<Skeleton variant='rect' width={88} height={47} />
)}
</Box>
<Box
borderTop={`1px solid ${palette.secondary.light}`}
borderBottom={`1px solid ${palette.secondary.light}`}
px={2}
>
<Grid container>
<Grid item xs={6}>
<Box borderRight={`1px solid ${palette.secondary.light}`} py={1}>
{tokenData ? (
<Typography
variant='body2'
style={{ color: palette.text.secondary }}
>
TVL: {formatCompact(tokenData?.totalLiquidityUSD)}
</Typography>
) : (
<Skeleton variant='rect' width={100} height={16} />
)}
</Box>
</Grid>
<Grid item xs={6}>
<Box py={1} pl={2}>
{tokenData ? (
<Typography
variant='body2'
style={{ color: palette.text.secondary }}
>
24h VOL: {formatCompact(tokenData?.oneDayVolumeUSD)}
</Typography>
) : (
<Skeleton variant='rect' width={100} height={16} />
)}
</Box>
</Grid>
</Grid>
</Box>
<Box
display='flex'
justifyContent='space-between'
alignItems='center'
py={1}
px={2}
>
<a
href={`https://polygonscan.com/token/${tokenAddress}`}
target='_blank'
rel='noopener noreferrer'
style={{ textDecoration: 'none' }}
>
<Typography variant='body2' style={{ color: palette.primary.main }}>
{shortenAddress(tokenAddress)}
</Typography>
</a>
<Box
display='flex'
style={{ cursor: 'pointer', opacity: isCopied ? 0.5 : 1 }}
onClick={() => {
setCopied(tokenAddress);
}}
>
<CopyIcon />
</Box>
</Box>
</Box>
);
}
Example #15
Source File: Header.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
Header: React.FC = () => {
const classes = useStyles();
const { pathname } = useLocation();
const { account } = useActiveWeb3React();
const { ethereum } = window as any;
const { ENSName } = useENSName(account ?? undefined);
const [openDetailMenu, setOpenDetailMenu] = useState(false);
const theme = useTheme();
const allTransactions = useAllTransactions();
const sortedRecentTransactions = useMemo(() => {
const txs = Object.values(allTransactions);
return txs.filter(isTransactionRecent).sort(newTransactionsFirst);
}, [allTransactions]);
const pending = sortedRecentTransactions
.filter((tx: any) => !tx.receipt)
.map((tx: any) => tx.hash);
const confirmed = sortedRecentTransactions
.filter((tx: any) => tx.receipt)
.map((tx: any) => tx.hash);
const tabletWindowSize = useMediaQuery(theme.breakpoints.down('sm'));
const mobileWindowSize = useMediaQuery(theme.breakpoints.down('xs'));
const toggleWalletModal = useWalletModalToggle();
const menuItems = [
{
link: '/swap',
text: 'Swap',
id: 'swap-page-link',
},
{
link: '/pools',
text: 'Pool',
id: 'pools-page-link',
},
{
link: '/farm',
text: 'Farm',
id: 'farm-page-link',
},
{
link: '/dragons',
text: 'Dragon’s Lair',
id: 'dragons-page-link',
},
{
link: '/convert',
text: 'Convert',
id: 'convert-quick',
},
{
link: '/analytics',
text: 'Analytics',
id: 'analytics-page-link',
},
];
const outLinks: any[] = [
// {
// link: '/',
// text: 'Governance',
// },
// {
// link: '/',
// text: 'Docs',
// },
// {
// link: '/',
// text: 'For Developers',
// },
// {
// link: '/',
// text: 'Help & Tutorials',
// },
// {
// link: '/',
// text: 'Knowledge Base',
// },
// {
// link: '/',
// text: 'News',
// },
];
return (
<Box className={classes.header}>
<WalletModal
ENSName={ENSName ?? undefined}
pendingTransactions={pending}
confirmedTransactions={confirmed}
/>
<Link to='/'>
<img
src={mobileWindowSize ? QuickIcon : QuickLogo}
alt='QuickLogo'
height={60}
/>
</Link>
{!tabletWindowSize && (
<Box className={classes.mainMenu}>
{menuItems.map((val, index) => (
<Link
to={val.link}
key={index}
id={val.id}
className={
pathname.indexOf(val.link) > -1 ? 'active' : 'menuItem'
}
>
<Typography variant='body2'>{val.text}</Typography>
</Link>
))}
{/* <Box display='flex' className='menuItem'>
<ThreeDotIcon />
<Box
position='absolute'
top={32}
left={0}
width={209}
paddingTop={10}
>
<Box className='subMenu'>
{outLinks.map((item, ind) => (
<a href={item.link} key={ind}>
<Typography variant='body2'>{item.text}</Typography>
</a>
))}
</Box>
</Box>
</Box> */}
</Box>
)}
{tabletWindowSize && (
<Box className={classes.mobileMenuContainer}>
<Box className={classes.mobileMenu}>
{menuItems.slice(0, 4).map((val, index) => (
<Link
to={val.link}
key={index}
className={
pathname.indexOf(val.link) > -1 ? 'active' : 'menuItem'
}
>
<Typography variant='body2'>{val.text}</Typography>
</Link>
))}
<Box display='flex' className='menuItem'>
<ThreeDotIcon
onClick={() => setOpenDetailMenu(!openDetailMenu)}
/>
{openDetailMenu && (
<Box
position='absolute'
bottom={72}
right={12}
width={209}
bgcolor={theme.palette.secondary.dark}
borderRadius={20}
py={1}
border={`1px solid ${theme.palette.divider}`}
>
<Box className='subMenu'>
{menuItems.slice(4, menuItems.length).map((val, index) => (
<Link
to={val.link}
key={index}
className='menuItem'
onClick={() => setOpenDetailMenu(false)}
>
<Typography variant='body2'>{val.text}</Typography>
</Link>
))}
{outLinks.map((item, ind) => (
<a
href={item.link}
key={ind}
onClick={() => setOpenDetailMenu(false)}
>
<Typography variant='body2'>{item.text}</Typography>
</a>
))}
</Box>
</Box>
)}
</Box>
</Box>
</Box>
)}
<Box>
<Box
width={45}
height={36}
display='flex'
alignItems='center'
justifyContent='center'
marginRight={1}
>
<StyledPollingDot></StyledPollingDot>
<LightIcon />
</Box>
{account && (!ethereum || isSupportedNetwork(ethereum)) ? (
<Box
id='web3-status-connected'
className={classes.accountDetails}
onClick={toggleWalletModal}
>
<Typography>{shortenAddress(account)}</Typography>
<img src={WalletIcon} alt='Wallet' />
</Box>
) : (
<Box
className={cx(
classes.connectButton,
ethereum && !isSupportedNetwork(ethereum)
? classes.danger
: classes.primary,
)}
onClick={() => {
if (!ethereum || isSupportedNetwork(ethereum)) {
toggleWalletModal();
}
}}
>
{ethereum && !isSupportedNetwork(ethereum)
? 'Wrong Network'
: 'Connect Wallet'}
{ethereum && !isSupportedNetwork(ethereum) && (
<Box
position='absolute'
top={36}
width={272}
right={0}
paddingTop='18px'
>
<Box className={classes.wrongNetworkContent}>
<Typography variant='body2'>
Please switch your wallet to Polygon Network.
</Typography>
<Box onClick={addMaticToMetamask}>Switch to Polygon</Box>
</Box>
</Box>
)}
</Box>
)}
</Box>
</Box>
);
}
Example #16
Source File: AccountDetails.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
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 #17
Source File: REPMintEditor.tsx From dxvote with GNU Affero General Public License v3.0 | 4 votes |
Mint: React.FC<ActionEditorProps> = ({ decodedCall, updateCall }) => {
// parse transfer state from calls
const [repPercent, setRepPercent] = useState(0);
const [repAmount, setRepAmount] = useState(0);
const { parsedData } = useTotalSupply({ decodedCall });
const { tokenData } = useTokenData();
const totalSupply = useBigNumberToNumber(tokenData?.totalSupply, 18);
const { imageUrl } = useENSAvatar(parsedData?.toAddress, MAINNET_ID);
const setCallDataAmount = (value: string) => {
const amount = value ? ethers.utils.parseUnits(value) : null;
updateCall({
...decodedCall,
args: {
...decodedCall.args,
amount,
},
});
};
useEffect(() => {
setRepAmount((repPercent / 100) * totalSupply);
if (repAmount) {
setCallDataAmount(repAmount.toString());
}
}, [repPercent, repAmount, totalSupply]);
const handleRepChange = (e: number) => {
if (e) {
setRepPercent(e);
}
};
return (
<React.Fragment>
<Control>
<ControlLabel>
Recipient
<StyledIcon src={Info} />
</ControlLabel>
<ControlRow>
<Input
value={shortenAddress(parsedData?.toAddress)}
icon={
<Avatar
src={imageUrl}
defaultSeed={parsedData?.toAddress}
size={18}
/>
}
readOnly
/>
</ControlRow>
</Control>
<ControlRow>
<Control>
<ControlLabel>
Reputation in % <StyledIcon src={Info} />
</ControlLabel>
<ControlRow>
<RepMintInput value={repPercent} onUserInput={handleRepChange} />
</ControlRow>
</Control>
</ControlRow>
<ControlRow>
<Control>
<ControlLabel>
Reputation Amount <StyledIcon src={Info} />
</ControlLabel>
<ControlRow>
<RepMintInput
value={repAmount}
onUserInput={handleRepChange}
readOnly
/>
</ControlRow>
</Control>
</ControlRow>
</React.Fragment>
);
}