utils#isSupportedNetwork TypeScript Examples
The following examples show how to use
utils#isSupportedNetwork.
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: HeroSection.tsx From interface-v2 with GNU General Public License v3.0 | 5 votes |
HeroSection: React.FC<{ globalData: any }> = ({ globalData }) => {
const classes = useStyles();
const history = useHistory();
const { account } = useActiveWeb3React();
const { ethereum } = window as any;
const toggleWalletModal = useWalletModalToggle();
return (
<Box className={classes.heroSection}>
<Typography variant='body2' style={{ fontWeight: 'bold' }}>
Total Value Locked
</Typography>
{globalData ? (
<Box display='flex' pt='5px'>
<Typography variant='h3'>$</Typography>
<Typography variant='h1'>
{Number(globalData.totalLiquidityUSD).toLocaleString(undefined, {
maximumFractionDigits: 0,
})}
</Typography>
</Box>
) : (
<Box my={1}>
<Skeleton variant='rect' width={400} height={72} />
</Box>
)}
<Typography variant='h5'>
Top Asset Exchange on the Polygon Network
</Typography>
<Box mt={2} width={200} height={48}>
<Button
fullWidth
style={{
backgroundColor: '#004ce6',
borderRadius: '30px',
height: '100%',
fontSize: 16,
fontWeight: 500,
}}
onClick={() => {
ethereum && !isSupportedNetwork(ethereum)
? addMaticToMetamask()
: account
? history.push('/swap')
: toggleWalletModal();
}}
>
{ethereum && !isSupportedNetwork(ethereum)
? 'Switch to Polygon'
: account
? 'Enter App'
: 'Connect Wallet'}
</Button>
</Box>
</Box>
);
}
Example #2
Source File: AddLiquidity.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
AddLiquidity: React.FC<{
currency0?: Currency;
currency1?: Currency;
currencyBg?: string;
}> = ({ currency0, currency1, currencyBg }) => {
const classes = useStyles({});
const { palette } = useTheme();
const { t } = useTranslation();
const [addLiquidityErrorMessage, setAddLiquidityErrorMessage] = useState<
string | null
>(null);
const { account, chainId, library } = useActiveWeb3React();
const [showConfirm, setShowConfirm] = useState(false);
const [attemptingTxn, setAttemptingTxn] = useState(false);
const [txPending, setTxPending] = useState(false);
const [allowedSlippage] = useUserSlippageTolerance();
const deadline = useTransactionDeadline();
const [txHash, setTxHash] = useState('');
const addTransaction = useTransactionAdder();
const finalizedTransaction = useTransactionFinalizer();
const { independentField, typedValue, otherTypedValue } = useMintState();
const expertMode = useIsExpertMode();
const {
dependentField,
currencies,
pair,
pairState,
currencyBalances,
parsedAmounts,
price,
noLiquidity,
liquidityMinted,
poolTokenPercentage,
error,
} = useDerivedMintInfo();
const liquidityTokenData = {
amountA: formatTokenAmount(parsedAmounts[Field.CURRENCY_A]),
symbolA: currencies[Field.CURRENCY_A]?.symbol,
amountB: formatTokenAmount(parsedAmounts[Field.CURRENCY_B]),
symbolB: currencies[Field.CURRENCY_B]?.symbol,
};
const pendingText = t('supplyingTokens', liquidityTokenData);
const {
onFieldAInput,
onFieldBInput,
onCurrencySelection,
} = useMintActionHandlers(noLiquidity);
const maxAmounts: { [field in Field]?: TokenAmount } = [
Field.CURRENCY_A,
Field.CURRENCY_B,
].reduce((accumulator, field) => {
return {
...accumulator,
[field]: maxAmountSpend(currencyBalances[field]),
};
}, {});
const formattedAmounts = {
[independentField]: typedValue,
[dependentField]: noLiquidity
? otherTypedValue
: parsedAmounts[dependentField]?.toExact() ?? '',
};
const { ethereum } = window as any;
const toggleWalletModal = useWalletModalToggle();
const [approvingA, setApprovingA] = useState(false);
const [approvingB, setApprovingB] = useState(false);
const [approvalA, approveACallback] = useApproveCallback(
parsedAmounts[Field.CURRENCY_A],
chainId ? GlobalConst.addresses.ROUTER_ADDRESS[chainId] : undefined,
);
const [approvalB, approveBCallback] = useApproveCallback(
parsedAmounts[Field.CURRENCY_B],
chainId ? GlobalConst.addresses.ROUTER_ADDRESS[chainId] : undefined,
);
const userPoolBalance = useTokenBalance(
account ?? undefined,
pair?.liquidityToken,
);
const atMaxAmounts: { [field in Field]?: TokenAmount } = [
Field.CURRENCY_A,
Field.CURRENCY_B,
].reduce((accumulator, field) => {
return {
...accumulator,
[field]: maxAmounts[field]?.equalTo(parsedAmounts[field] ?? '0'),
};
}, {});
const handleCurrencyASelect = useCallback(
(currencyA: Currency) => {
onCurrencySelection(Field.CURRENCY_A, currencyA);
},
[onCurrencySelection],
);
const handleCurrencyBSelect = useCallback(
(currencyB: Currency) => {
onCurrencySelection(Field.CURRENCY_B, currencyB);
},
[onCurrencySelection],
);
useEffect(() => {
if (currency0) {
onCurrencySelection(Field.CURRENCY_A, currency0);
} else {
onCurrencySelection(Field.CURRENCY_A, Token.ETHER);
}
if (currency1) {
onCurrencySelection(Field.CURRENCY_B, currency1);
} else {
onCurrencySelection(Field.CURRENCY_B, returnTokenFromKey('QUICK'));
}
}, [onCurrencySelection, currency0, currency1]);
const onAdd = () => {
if (expertMode) {
onAddLiquidity();
} else {
setShowConfirm(true);
}
};
const router = useRouterContract();
const onAddLiquidity = async () => {
if (!chainId || !library || !account || !router) return;
const {
[Field.CURRENCY_A]: parsedAmountA,
[Field.CURRENCY_B]: parsedAmountB,
} = parsedAmounts;
if (
!parsedAmountA ||
!parsedAmountB ||
!currencies[Field.CURRENCY_A] ||
!currencies[Field.CURRENCY_B] ||
!deadline
) {
return;
}
const amountsMin = {
[Field.CURRENCY_A]: calculateSlippageAmount(
parsedAmountA,
noLiquidity ? 0 : allowedSlippage,
)[0],
[Field.CURRENCY_B]: calculateSlippageAmount(
parsedAmountB,
noLiquidity ? 0 : allowedSlippage,
)[0],
};
let estimate,
method: (...args: any) => Promise<TransactionResponse>,
args: Array<string | string[] | number>,
value: BigNumber | null;
if (
currencies[Field.CURRENCY_A] === ETHER ||
currencies[Field.CURRENCY_B] === ETHER
) {
const tokenBIsETH = currencies[Field.CURRENCY_B] === ETHER;
estimate = router.estimateGas.addLiquidityETH;
method = router.addLiquidityETH;
args = [
wrappedCurrency(
tokenBIsETH
? currencies[Field.CURRENCY_A]
: currencies[Field.CURRENCY_B],
chainId,
)?.address ?? '', // token
(tokenBIsETH ? parsedAmountA : parsedAmountB).raw.toString(), // token desired
amountsMin[
tokenBIsETH ? Field.CURRENCY_A : Field.CURRENCY_B
].toString(), // token min
amountsMin[
tokenBIsETH ? Field.CURRENCY_B : Field.CURRENCY_A
].toString(), // eth min
account,
deadline.toHexString(),
];
value = BigNumber.from(
(tokenBIsETH ? parsedAmountB : parsedAmountA).raw.toString(),
);
} else {
estimate = router.estimateGas.addLiquidity;
method = router.addLiquidity;
args = [
wrappedCurrency(currencies[Field.CURRENCY_A], chainId)?.address ?? '',
wrappedCurrency(currencies[Field.CURRENCY_B], chainId)?.address ?? '',
parsedAmountA.raw.toString(),
parsedAmountB.raw.toString(),
amountsMin[Field.CURRENCY_A].toString(),
amountsMin[Field.CURRENCY_B].toString(),
account,
deadline.toHexString(),
];
value = null;
}
setAttemptingTxn(true);
await estimate(...args, value ? { value } : {})
.then((estimatedGasLimit) =>
method(...args, {
...(value ? { value } : {}),
gasLimit: calculateGasMargin(estimatedGasLimit),
}).then(async (response) => {
setAttemptingTxn(false);
setTxPending(true);
const summary = t('addLiquidityTokens', liquidityTokenData);
addTransaction(response, {
summary,
});
setTxHash(response.hash);
try {
const receipt = await response.wait();
finalizedTransaction(receipt, {
summary,
});
setTxPending(false);
} catch (error) {
setTxPending(false);
setAddLiquidityErrorMessage(t('errorInTx'));
}
ReactGA.event({
category: 'Liquidity',
action: 'Add',
label: [
currencies[Field.CURRENCY_A]?.symbol,
currencies[Field.CURRENCY_B]?.symbol,
].join('/'),
});
}),
)
.catch((error) => {
setAttemptingTxn(false);
setAddLiquidityErrorMessage(t('txRejected'));
// we only care if the error is something _other_ than the user rejected the tx
if (error?.code !== 4001) {
console.error(error);
}
});
};
const connectWallet = () => {
if (ethereum && !isSupportedNetwork(ethereum)) {
addMaticToMetamask();
} else {
toggleWalletModal();
}
};
const handleDismissConfirmation = useCallback(() => {
setShowConfirm(false);
// if there was a tx hash, we want to clear the input
if (txHash) {
onFieldAInput('');
}
setTxHash('');
}, [onFieldAInput, txHash]);
const buttonText = useMemo(() => {
if (account) {
return error ?? t('supply');
} else if (ethereum && !isSupportedNetwork(ethereum)) {
return t('switchPolygon');
}
return t('connectWallet');
}, [account, ethereum, error, t]);
const modalHeader = () => {
return (
<Box>
<Box mt={10} mb={3} display='flex' justifyContent='center'>
<DoubleCurrencyLogo
currency0={currencies[Field.CURRENCY_A]}
currency1={currencies[Field.CURRENCY_B]}
size={48}
/>
</Box>
<Box mb={6} color={palette.text.primary} textAlign='center'>
<Typography variant='h6'>
{t('supplyingTokens', liquidityTokenData)}
<br />
{t('receiveLPTokens', {
amount: formatTokenAmount(liquidityMinted),
symbolA: currencies[Field.CURRENCY_A]?.symbol,
symbolB: currencies[Field.CURRENCY_B]?.symbol,
})}
</Typography>
</Box>
<Box mb={3} color={palette.text.secondary} textAlign='center'>
<Typography variant='body2'>
{t('outputEstimated', { slippage: allowedSlippage / 100 })}
</Typography>
</Box>
<Box className={classes.swapButtonWrapper}>
<Button onClick={onAddLiquidity}>{t('confirmSupply')}</Button>
</Box>
</Box>
);
};
return (
<Box>
{showConfirm && (
<TransactionConfirmationModal
isOpen={showConfirm}
onDismiss={handleDismissConfirmation}
attemptingTxn={attemptingTxn}
txPending={txPending}
hash={txHash}
content={() =>
addLiquidityErrorMessage ? (
<TransactionErrorContent
onDismiss={handleDismissConfirmation}
message={addLiquidityErrorMessage}
/>
) : (
<ConfirmationModalContent
title={t('supplyingliquidity')}
onDismiss={handleDismissConfirmation}
content={modalHeader}
/>
)
}
pendingText={pendingText}
modalContent={
txPending ? t('submittedTxLiquidity') : t('successAddedliquidity')
}
/>
)}
<CurrencyInput
id='add-liquidity-input-tokena'
title={`${t('token')} 1:`}
currency={currencies[Field.CURRENCY_A]}
showHalfButton={Boolean(maxAmounts[Field.CURRENCY_A])}
showMaxButton={!atMaxAmounts[Field.CURRENCY_A]}
onMax={() =>
onFieldAInput(maxAmounts[Field.CURRENCY_A]?.toExact() ?? '')
}
onHalf={() =>
onFieldAInput(
maxAmounts[Field.CURRENCY_A]
? (Number(maxAmounts[Field.CURRENCY_A]?.toExact()) / 2).toString()
: '',
)
}
handleCurrencySelect={handleCurrencyASelect}
amount={formattedAmounts[Field.CURRENCY_A]}
setAmount={onFieldAInput}
bgColor={currencyBg}
/>
<Box className={classes.exchangeSwap}>
<AddLiquidityIcon />
</Box>
<CurrencyInput
id='add-liquidity-input-tokenb'
title={`${t('token')} 2:`}
showHalfButton={Boolean(maxAmounts[Field.CURRENCY_B])}
currency={currencies[Field.CURRENCY_B]}
showMaxButton={!atMaxAmounts[Field.CURRENCY_B]}
onHalf={() =>
onFieldBInput(
maxAmounts[Field.CURRENCY_B]
? (Number(maxAmounts[Field.CURRENCY_B]?.toExact()) / 2).toString()
: '',
)
}
onMax={() =>
onFieldBInput(maxAmounts[Field.CURRENCY_B]?.toExact() ?? '')
}
handleCurrencySelect={handleCurrencyBSelect}
amount={formattedAmounts[Field.CURRENCY_B]}
setAmount={onFieldBInput}
bgColor={currencyBg}
/>
{currencies[Field.CURRENCY_A] &&
currencies[Field.CURRENCY_B] &&
pairState !== PairState.INVALID &&
price && (
<Box my={2}>
<Box className={classes.swapPrice}>
<Typography variant='body2'>
1 {currencies[Field.CURRENCY_A]?.symbol} ={' '}
{price.toSignificant(3)} {currencies[Field.CURRENCY_B]?.symbol}{' '}
</Typography>
<Typography variant='body2'>
1 {currencies[Field.CURRENCY_B]?.symbol} ={' '}
{price.invert().toSignificant(3)}{' '}
{currencies[Field.CURRENCY_A]?.symbol}{' '}
</Typography>
</Box>
<Box className={classes.swapPrice}>
<Typography variant='body2'>{t('yourPoolShare')}:</Typography>
<Typography variant='body2'>
{poolTokenPercentage
? poolTokenPercentage.toSignificant(6) + '%'
: '-'}
</Typography>
</Box>
<Box className={classes.swapPrice}>
<Typography variant='body2'>{t('lpTokenReceived')}:</Typography>
<Typography variant='body2'>
{formatTokenAmount(userPoolBalance)} {t('lpTokens')}
</Typography>
</Box>
</Box>
)}
<Box className={classes.swapButtonWrapper}>
{(approvalA === ApprovalState.NOT_APPROVED ||
approvalA === ApprovalState.PENDING ||
approvalB === ApprovalState.NOT_APPROVED ||
approvalB === ApprovalState.PENDING) &&
!error && (
<Box className={classes.approveButtons}>
{approvalA !== ApprovalState.APPROVED && (
<Box
width={approvalB !== ApprovalState.APPROVED ? '48%' : '100%'}
>
<Button
onClick={async () => {
setApprovingA(true);
try {
await approveACallback();
setApprovingA(false);
} catch (e) {
setApprovingA(false);
}
}}
disabled={approvingA || approvalA === ApprovalState.PENDING}
>
{approvalA === ApprovalState.PENDING
? `${t('approving')} ${
currencies[Field.CURRENCY_A]?.symbol
}`
: `${t('approve')} ${
currencies[Field.CURRENCY_A]?.symbol
}`}
</Button>
</Box>
)}
{approvalB !== ApprovalState.APPROVED && (
<Box
width={approvalA !== ApprovalState.APPROVED ? '48%' : '100%'}
>
<Button
onClick={async () => {
setApprovingB(true);
try {
await approveBCallback();
setApprovingB(false);
} catch (e) {
setApprovingB(false);
}
}}
disabled={approvingB || approvalB === ApprovalState.PENDING}
>
{approvalB === ApprovalState.PENDING
? `${t('approving')} ${
currencies[Field.CURRENCY_B]?.symbol
}`
: `${t('approve')} ${
currencies[Field.CURRENCY_B]?.symbol
}`}
</Button>
</Box>
)}
</Box>
)}
<Button
disabled={
Boolean(account) &&
(Boolean(error) ||
approvalA !== ApprovalState.APPROVED ||
approvalB !== ApprovalState.APPROVED)
}
onClick={account ? onAdd : connectWallet}
>
{buttonText}
</Button>
</Box>
</Box>
);
}
Example #3
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 #4
Source File: Swap.tsx From interface-v2 with GNU General Public License v3.0 | 4 votes |
Swap: React.FC<{
currency0?: Currency;
currency1?: Currency;
currencyBg?: string;
}> = ({ currency0, currency1, currencyBg }) => {
const { account } = useActiveWeb3React();
const { independentField, typedValue, recipient } = useSwapState();
const {
v1Trade,
v2Trade,
currencyBalances,
parsedAmount,
currencies,
inputError: swapInputError,
} = useDerivedSwapInfo();
const toggledVersion = useToggledVersion();
const finalizedTransaction = useTransactionFinalizer();
const [isExpertMode] = useExpertModeManager();
const {
wrapType,
execute: onWrap,
inputError: wrapInputError,
} = useWrapCallback(
currencies[Field.INPUT],
currencies[Field.OUTPUT],
typedValue,
);
const allTokens = useAllTokens();
const showWrap: boolean = wrapType !== WrapType.NOT_APPLICABLE;
const tradesByVersion = {
[Version.v1]: v1Trade,
[Version.v2]: v2Trade,
};
const trade = showWrap ? undefined : tradesByVersion[toggledVersion];
const {
onSwitchTokens,
onCurrencySelection,
onUserInput,
onChangeRecipient,
} = useSwapActionHandlers();
const { address: recipientAddress } = useENSAddress(recipient);
const [allowedSlippage] = useUserSlippageTolerance();
const [approving, setApproving] = useState(false);
const [approval, approveCallback] = useApproveCallbackFromTrade(
trade,
allowedSlippage,
);
const dependentField: Field =
independentField === Field.INPUT ? Field.OUTPUT : Field.INPUT;
const parsedAmounts = useMemo(() => {
return showWrap
? {
[Field.INPUT]: parsedAmount,
[Field.OUTPUT]: parsedAmount,
}
: {
[Field.INPUT]:
independentField === Field.INPUT
? parsedAmount
: trade?.inputAmount,
[Field.OUTPUT]:
independentField === Field.OUTPUT
? parsedAmount
: trade?.outputAmount,
};
}, [parsedAmount, independentField, trade, showWrap]);
const formattedAmounts = useMemo(() => {
return {
[independentField]: typedValue,
[dependentField]: showWrap
? parsedAmounts[independentField]?.toExact() ?? ''
: parsedAmounts[dependentField]?.toExact() ?? '',
};
}, [independentField, typedValue, dependentField, showWrap, parsedAmounts]);
const route = trade?.route;
const userHasSpecifiedInputOutput = Boolean(
currencies[Field.INPUT] &&
currencies[Field.OUTPUT] &&
parsedAmounts[independentField]?.greaterThan(JSBI.BigInt(0)),
);
const noRoute = !route;
const { priceImpactWithoutFee } = computeTradePriceBreakdown(trade);
const [approvalSubmitted, setApprovalSubmitted] = useState<boolean>(false);
const { ethereum } = window as any;
const [mainPrice, setMainPrice] = useState(true);
const priceImpactSeverity = warningSeverity(priceImpactWithoutFee);
const isValid = !swapInputError;
const showApproveFlow =
!swapInputError &&
(approval === ApprovalState.NOT_APPROVED ||
approval === ApprovalState.PENDING ||
(approvalSubmitted && approval === ApprovalState.APPROVED)) &&
!(priceImpactSeverity > 3 && !isExpertMode);
const classes = useStyles({ showApproveFlow });
const toggleWalletModal = useWalletModalToggle();
useEffect(() => {
if (approval === ApprovalState.PENDING) {
setApprovalSubmitted(true);
}
}, [approval, approvalSubmitted]);
const connectWallet = () => {
if (ethereum && !isSupportedNetwork(ethereum)) {
addMaticToMetamask();
} else {
toggleWalletModal();
}
};
const handleCurrencySelect = useCallback(
(inputCurrency) => {
setApprovalSubmitted(false); // reset 2 step UI for approvals
onCurrencySelection(Field.INPUT, inputCurrency);
},
[onCurrencySelection],
);
const handleOtherCurrencySelect = useCallback(
(outputCurrency) => onCurrencySelection(Field.OUTPUT, outputCurrency),
[onCurrencySelection],
);
const { callback: swapCallback, error: swapCallbackError } = useSwapCallback(
trade,
allowedSlippage,
recipient,
);
const swapButtonText = useMemo(() => {
if (account) {
if (!currencies[Field.INPUT] || !currencies[Field.OUTPUT]) {
return 'Select a token';
} else if (
formattedAmounts[Field.INPUT] === '' &&
formattedAmounts[Field.OUTPUT] === ''
) {
return 'Enter Amount';
} else if (showWrap) {
return wrapType === WrapType.WRAP
? 'Wrap'
: wrapType === WrapType.UNWRAP
? 'UnWrap'
: '';
} else if (noRoute && userHasSpecifiedInputOutput) {
return 'Insufficient liquidity for this trade.';
} else {
return swapInputError ?? 'Swap';
}
} else {
return ethereum && !isSupportedNetwork(ethereum)
? 'Switch to Polygon'
: 'Connect Wallet';
}
}, [
formattedAmounts,
currencies,
account,
ethereum,
noRoute,
userHasSpecifiedInputOutput,
showWrap,
wrapType,
swapInputError,
]);
const swapButtonDisabled = useMemo(() => {
if (account) {
if (showWrap) {
return Boolean(wrapInputError);
} else if (noRoute && userHasSpecifiedInputOutput) {
return true;
} else if (showApproveFlow) {
return (
!isValid ||
approval !== ApprovalState.APPROVED ||
(priceImpactSeverity > 3 && !isExpertMode)
);
} else {
return (
!isValid ||
(priceImpactSeverity > 3 && !isExpertMode) ||
!!swapCallbackError
);
}
} else {
return false;
}
}, [
account,
showWrap,
wrapInputError,
noRoute,
userHasSpecifiedInputOutput,
showApproveFlow,
approval,
priceImpactSeverity,
isValid,
swapCallbackError,
isExpertMode,
]);
const [
{
showConfirm,
txPending,
tradeToConfirm,
swapErrorMessage,
attemptingTxn,
txHash,
},
setSwapState,
] = useState<{
showConfirm: boolean;
txPending?: boolean;
tradeToConfirm: Trade | undefined;
attemptingTxn: boolean;
swapErrorMessage: string | undefined;
txHash: string | undefined;
}>({
showConfirm: false,
txPending: false,
tradeToConfirm: undefined,
attemptingTxn: false,
swapErrorMessage: undefined,
txHash: undefined,
});
const handleTypeInput = useCallback(
(value: string) => {
onUserInput(Field.INPUT, value);
},
[onUserInput],
);
const handleTypeOutput = useCallback(
(value: string) => {
onUserInput(Field.OUTPUT, value);
},
[onUserInput],
);
const maxAmountInput: CurrencyAmount | undefined = maxAmountSpend(
currencyBalances[Field.INPUT],
);
const halfAmountInput: CurrencyAmount | undefined = halfAmountSpend(
currencyBalances[Field.INPUT],
);
const handleMaxInput = useCallback(() => {
maxAmountInput && onUserInput(Field.INPUT, maxAmountInput.toExact());
}, [maxAmountInput, onUserInput]);
const handleHalfInput = useCallback(() => {
halfAmountInput && onUserInput(Field.INPUT, halfAmountInput.toExact());
}, [halfAmountInput, onUserInput]);
const atMaxAmountInput = Boolean(
maxAmountInput && parsedAmounts[Field.INPUT]?.equalTo(maxAmountInput),
);
const onSwap = () => {
if (showWrap && onWrap) {
onWrap();
} else if (isExpertMode) {
handleSwap();
} else {
setSwapState({
tradeToConfirm: trade,
attemptingTxn: false,
swapErrorMessage: undefined,
showConfirm: true,
txHash: undefined,
});
}
};
useEffect(() => {
onCurrencySelection(Field.INPUT, Token.ETHER);
}, [onCurrencySelection, allTokens]);
useEffect(() => {
if (currency0) {
onCurrencySelection(Field.INPUT, currency0);
}
if (currency1) {
onCurrencySelection(Field.OUTPUT, currency1);
}
}, [onCurrencySelection, currency0, currency1]);
const handleAcceptChanges = useCallback(() => {
setSwapState({
tradeToConfirm: trade,
swapErrorMessage,
txHash,
attemptingTxn,
showConfirm,
});
}, [attemptingTxn, showConfirm, swapErrorMessage, trade, txHash]);
const handleConfirmDismiss = useCallback(() => {
setSwapState({
showConfirm: false,
tradeToConfirm,
attemptingTxn,
swapErrorMessage,
txHash,
});
// if there was a tx hash, we want to clear the input
if (txHash) {
onUserInput(Field.INPUT, '');
}
}, [attemptingTxn, onUserInput, swapErrorMessage, tradeToConfirm, txHash]);
const handleSwap = useCallback(() => {
if (
priceImpactWithoutFee &&
!confirmPriceImpactWithoutFee(priceImpactWithoutFee)
) {
return;
}
if (!swapCallback) {
return;
}
setSwapState({
attemptingTxn: true,
tradeToConfirm,
showConfirm,
swapErrorMessage: undefined,
txHash: undefined,
});
swapCallback()
.then(async ({ response, summary }) => {
setSwapState({
attemptingTxn: false,
txPending: true,
tradeToConfirm,
showConfirm,
swapErrorMessage: undefined,
txHash: response.hash,
});
try {
const receipt = await response.wait();
finalizedTransaction(receipt, {
summary,
});
setSwapState({
attemptingTxn: false,
txPending: false,
tradeToConfirm,
showConfirm,
swapErrorMessage: undefined,
txHash: response.hash,
});
ReactGA.event({
category: 'Swap',
action:
recipient === null
? 'Swap w/o Send'
: (recipientAddress ?? recipient) === account
? 'Swap w/o Send + recipient'
: 'Swap w/ Send',
label: [
trade?.inputAmount?.currency?.symbol,
trade?.outputAmount?.currency?.symbol,
].join('/'),
});
} catch (error) {
setSwapState({
attemptingTxn: false,
tradeToConfirm,
showConfirm,
swapErrorMessage: (error as any).message,
txHash: undefined,
});
}
})
.catch((error) => {
setSwapState({
attemptingTxn: false,
tradeToConfirm,
showConfirm,
swapErrorMessage: error.message,
txHash: undefined,
});
});
}, [
tradeToConfirm,
account,
priceImpactWithoutFee,
recipient,
recipientAddress,
showConfirm,
swapCallback,
finalizedTransaction,
trade,
]);
return (
<Box>
{showConfirm && (
<ConfirmSwapModal
isOpen={showConfirm}
trade={trade}
originalTrade={tradeToConfirm}
onAcceptChanges={handleAcceptChanges}
attemptingTxn={attemptingTxn}
txPending={txPending}
txHash={txHash}
recipient={recipient}
allowedSlippage={allowedSlippage}
onConfirm={handleSwap}
swapErrorMessage={swapErrorMessage}
onDismiss={handleConfirmDismiss}
/>
)}
<CurrencyInput
title='From:'
id='swap-currency-input'
currency={currencies[Field.INPUT]}
onHalf={handleHalfInput}
onMax={handleMaxInput}
showHalfButton={true}
showMaxButton={!atMaxAmountInput}
otherCurrency={currencies[Field.OUTPUT]}
handleCurrencySelect={handleCurrencySelect}
amount={formattedAmounts[Field.INPUT]}
setAmount={handleTypeInput}
bgColor={currencyBg}
/>
<Box className={classes.exchangeSwap}>
<ExchangeIcon onClick={onSwitchTokens} />
</Box>
<CurrencyInput
title='To (estimate):'
id='swap-currency-output'
currency={currencies[Field.OUTPUT]}
showPrice={Boolean(trade && trade.executionPrice)}
showMaxButton={false}
otherCurrency={currencies[Field.INPUT]}
handleCurrencySelect={handleOtherCurrencySelect}
amount={formattedAmounts[Field.OUTPUT]}
setAmount={handleTypeOutput}
bgColor={currencyBg}
/>
{trade && trade.executionPrice && (
<Box className={classes.swapPrice}>
<Typography variant='body2'>Price:</Typography>
<Typography variant='body2'>
1{' '}
{
(mainPrice ? currencies[Field.INPUT] : currencies[Field.OUTPUT])
?.symbol
}{' '}
={' '}
{(mainPrice
? trade.executionPrice
: trade.executionPrice.invert()
).toSignificant(6)}{' '}
{
(mainPrice ? currencies[Field.OUTPUT] : currencies[Field.INPUT])
?.symbol
}{' '}
<PriceExchangeIcon
onClick={() => {
setMainPrice(!mainPrice);
}}
/>
</Typography>
</Box>
)}
{!showWrap && isExpertMode && (
<Box className={classes.recipientInput}>
<Box className='header'>
{recipient !== null ? (
<ArrowDown size='16' color='white' />
) : (
<Box />
)}
<Button
onClick={() => onChangeRecipient(recipient !== null ? null : '')}
>
{recipient !== null ? '- Remove send' : '+ Add a send (optional)'}
</Button>
</Box>
{recipient !== null && (
<AddressInput
label='Recipient'
placeholder='Wallet Address or ENS name'
value={recipient}
onChange={onChangeRecipient}
/>
)}
</Box>
)}
<AdvancedSwapDetails trade={trade} />
<Box className={classes.swapButtonWrapper}>
{showApproveFlow && (
<Button
color='primary'
disabled={
approving ||
approval !== ApprovalState.NOT_APPROVED ||
approvalSubmitted
}
onClick={async () => {
setApproving(true);
try {
await approveCallback();
setApproving(false);
} catch (err) {
setApproving(false);
}
}}
>
{approval === ApprovalState.PENDING ? (
<Box className='content'>
Approving <CircularProgress size={16} />
</Box>
) : approvalSubmitted && approval === ApprovalState.APPROVED ? (
'Approved'
) : (
'Approve ' + currencies[Field.INPUT]?.symbol
)}
</Button>
)}
<Button
disabled={swapButtonDisabled as boolean}
onClick={account ? onSwap : connectWallet}
>
{swapButtonText}
</Button>
</Box>
</Box>
);
}