Commit 1bb4db54 authored by Moody Salem's avatar Moody Salem Committed by GitHub

Make the hooks directory strict (#817)

* Make the hooks directory strict

* Move using the v1 factory contract to hooks

* Add a comment to why we copy the token map

* Fix another lint error and make AllTokens deep readonly

* Move ALL_TOKENS to constants directory
parent 536de89a
......@@ -3,8 +3,9 @@ import { transparentize } from 'polished'
import React, { useMemo } from 'react'
import styled from 'styled-components'
import { ReactComponent as Close } from '../../assets/images/x.svg'
import { ALL_TOKENS } from '../../constants/tokens'
import { useActiveWeb3React } from '../../hooks'
import { ALL_TOKENS, useAllTokens } from '../../hooks/Tokens'
import { useAllTokens } from '../../hooks/Tokens'
import { Field } from '../../state/swap/actions'
import { useTokenWarningDismissal } from '../../state/user/hooks'
import { Link, TYPE } from '../../theme'
......
import { ChainId, Token, WETH } from '@uniswap/sdk'
import KOVAN_TOKENS from './kovan'
import MAINNET_TOKENS from './mainnet'
import RINKEBY_TOKENS from './rinkeby'
import ROPSTEN_TOKENS from './ropsten'
type AllTokens = Readonly<{ [chainId in ChainId]: Readonly<{ [tokenAddress: string]: Token }> }>
export const ALL_TOKENS: AllTokens = [
// WETH on all chains
...Object.values(WETH),
// chain-specific tokens
...MAINNET_TOKENS,
...RINKEBY_TOKENS,
...KOVAN_TOKENS,
...ROPSTEN_TOKENS
]
// remap WETH to ETH
.map(token => {
if (token.equals(WETH[token.chainId])) {
;(token as any).symbol = 'ETH'
;(token as any).name = 'Ether'
}
return token
})
// put into an object
.reduce<AllTokens>(
(tokenMap, token) => {
if (tokenMap[token.chainId][token.address] !== undefined) throw Error('Duplicate tokens.')
return {
...tokenMap,
[token.chainId]: {
...tokenMap[token.chainId],
[token.address]: token
}
}
},
{
[ChainId.MAINNET]: {},
[ChainId.RINKEBY]: {},
[ChainId.GÖRLI]: {},
[ChainId.ROPSTEN]: {},
[ChainId.KOVAN]: {}
}
)
import { Contract } from '@ethersproject/contracts'
import { Token, TokenAmount, Pair } from '@uniswap/sdk'
import useSWR from 'swr'
import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json'
import { SWRKeys, useKeepSWRDataLiveAsBlocksArrive } from '.'
import { useContract } from '../hooks'
import { usePairContract } from '../hooks'
function getReserves(contract: Contract, tokenA: Token, tokenB: Token): () => Promise<Pair | null> {
return async (): Promise<Pair | null> =>
......@@ -28,7 +27,7 @@ function getReserves(contract: Contract, tokenA: Token, tokenB: Token): () => Pr
*/
export function usePair(tokenA?: Token, tokenB?: Token): undefined | Pair | null {
const pairAddress = !!tokenA && !!tokenB && !tokenA.equals(tokenB) ? Pair.getAddress(tokenA, tokenB) : undefined
const contract = useContract(pairAddress, IUniswapV2PairABI, false)
const contract = usePairContract(pairAddress, false)
const shouldFetch = !!contract
const key = shouldFetch ? [pairAddress, tokenA.chainId, SWRKeys.Reserves] : null
......
import { Contract } from '@ethersproject/contracts'
import { Token, TokenAmount } from '@uniswap/sdk'
import useSWR from 'swr'
import { abi as IERC20ABI } from '@uniswap/v2-core/build/IERC20.json'
import { SWRKeys, useKeepSWRDataLiveAsBlocksArrive } from '.'
import { useContract } from '../hooks'
import { useTokenContract } from '../hooks'
function getTotalSupply(contract: Contract, token: Token): () => Promise<TokenAmount> {
return async (): Promise<TokenAmount> =>
......@@ -14,7 +13,7 @@ function getTotalSupply(contract: Contract, token: Token): () => Promise<TokenAm
}
export function useTotalSupply(token?: Token): TokenAmount {
const contract = useContract(token?.address, IERC20ABI, false)
const contract = useTokenContract(token?.address, false)
const shouldFetch = !!contract
const { data, mutate } = useSWR(
......
......@@ -2,10 +2,7 @@ import { Contract } from '@ethersproject/contracts'
import { Token, TokenAmount, Pair, Trade, ChainId, WETH, Route, TradeType, Percent } from '@uniswap/sdk'
import useSWR from 'swr'
import { useActiveWeb3React } from '../hooks'
import IUniswapV1Factory from '../constants/abis/v1_factory.json'
import { V1_FACTORY_ADDRESS } from '../constants'
import { useContract } from '../hooks'
import { useV1FactoryContract } from '../hooks'
import { SWRKeys } from '.'
import { useETHBalances, useTokenBalances } from '../state/wallet/hooks'
......@@ -16,7 +13,7 @@ function getV1PairAddress(contract: Contract): (tokenAddress: string) => Promise
function useV1PairAddress(tokenAddress: string) {
const { chainId } = useActiveWeb3React()
const contract = useContract(V1_FACTORY_ADDRESS, IUniswapV1Factory, false)
const contract = useV1FactoryContract()
const shouldFetch = chainId === ChainId.MAINNET && typeof tokenAddress === 'string' && !!contract
const { data } = useSWR(shouldFetch ? [tokenAddress, SWRKeys.V1PairAddress] : null, getV1PairAddress(contract), {
......
import { ChainId, Token, WETH } from '@uniswap/sdk'
import { ChainId, Token } from '@uniswap/sdk'
import { useEffect, useMemo } from 'react'
import { ALL_TOKENS } from '../constants/tokens'
import { useAddUserToken, useFetchTokenByAddress, useUserAddedTokens } from '../state/user/hooks'
import { useActiveWeb3React } from './index'
import MAINNET_TOKENS from '../constants/tokens/mainnet'
import RINKEBY_TOKENS from '../constants/tokens/rinkeby'
import KOVAN_TOKENS from '../constants/tokens/kovan'
import ROPSTEN_TOKENS from '../constants/tokens/ropsten'
type AllTokens = { [chainId in ChainId]?: { [tokenAddress: string]: Token } }
export const ALL_TOKENS: Readonly<AllTokens> = [
// WETH on all chains
...Object.values(WETH),
// chain-specific tokens
...MAINNET_TOKENS,
...RINKEBY_TOKENS,
...KOVAN_TOKENS,
...ROPSTEN_TOKENS
]
// remap WETH to ETH
.map(token => {
if (token.equals(WETH[token.chainId])) {
;(token as any).symbol = 'ETH'
;(token as any).name = 'Ether'
}
return token
})
// put into an object
.reduce<AllTokens>((tokenMap, token) => {
if (tokenMap?.[token.chainId]?.[token.address] !== undefined) throw Error('Duplicate tokens.')
return {
...tokenMap,
[token.chainId]: {
...tokenMap?.[token.chainId],
[token.address]: token
}
}
}, {})
export function useAllTokens(): { [address: string]: Token } {
const { chainId } = useActiveWeb3React()
......@@ -52,7 +19,9 @@ export function useAllTokens(): { [address: string]: Token } {
tokenMap[token.address] = token
return tokenMap
},
{ ...ALL_TOKENS[chainId] }
// must make a copy because reduce modifies the map, and we do not
// want to make a copy in every iteration
{ ...ALL_TOKENS[chainId as ChainId] }
)
)
}, [userAddedTokens, chainId])
......@@ -81,5 +50,5 @@ export function useTokenByAddressAndAutomaticallyAdd(tokenAddress?: string): Tok
}
}, [tokenAddress, allTokens, fetchTokenByAddress, addToken])
return allTokens?.[tokenAddress]
return tokenAddress ? allTokens?.[tokenAddress] : undefined
}
......@@ -12,28 +12,31 @@ function useAllCommonPairs(tokenA?: Token, tokenB?: Token): Pair[] {
const pairBetween = usePair(tokenA, tokenB)
// get token<->WETH pairs
const aToETH = usePair(tokenA, WETH[chainId])
const bToETH = usePair(tokenB, WETH[chainId])
const aToETH = usePair(tokenA, WETH[chainId as ChainId])
const bToETH = usePair(tokenB, WETH[chainId as ChainId])
// get token<->DAI pairs
const aToDAI = usePair(tokenA, chainId === ChainId.MAINNET ? DAI : null)
const bToDAI = usePair(tokenB, chainId === ChainId.MAINNET ? DAI : null)
const aToDAI = usePair(tokenA, chainId === ChainId.MAINNET ? DAI : undefined)
const bToDAI = usePair(tokenB, chainId === ChainId.MAINNET ? DAI : undefined)
// get token<->USDC pairs
const aToUSDC = usePair(tokenA, chainId === ChainId.MAINNET ? USDC : null)
const bToUSDC = usePair(tokenB, chainId === ChainId.MAINNET ? USDC : null)
const aToUSDC = usePair(tokenA, chainId === ChainId.MAINNET ? USDC : undefined)
const bToUSDC = usePair(tokenB, chainId === ChainId.MAINNET ? USDC : undefined)
// get connecting pairs
const DAIToETH = usePair(chainId === ChainId.MAINNET ? DAI : null, WETH[chainId])
const USDCToETH = usePair(chainId === ChainId.MAINNET ? USDC : null, WETH[chainId])
const DAIToUSDC = usePair(chainId === ChainId.MAINNET ? DAI : null, chainId === ChainId.MAINNET ? USDC : null)
const DAIToETH = usePair(chainId === ChainId.MAINNET ? DAI : undefined, WETH[chainId as ChainId])
const USDCToETH = usePair(chainId === ChainId.MAINNET ? USDC : undefined, WETH[chainId as ChainId])
const DAIToUSDC = usePair(
chainId === ChainId.MAINNET ? DAI : undefined,
chainId === ChainId.MAINNET ? USDC : undefined
)
// only pass along valid pairs, non-duplicated pairs
return useMemo(
() =>
[pairBetween, aToETH, bToETH, aToDAI, bToDAI, aToUSDC, bToUSDC, DAIToETH, USDCToETH, DAIToUSDC]
// filter out invalid pairs
.filter(p => !!p)
.filter((p): p is Pair => !!p)
// filter out duplicated pairs
.filter(
(p, i, pairs) => i === pairs.findIndex(pair => pair?.liquidityToken.address === p.liquidityToken.address)
......
interface Window {
ethereum?: {
isMetaMask?: true
on?: (...args: any[]) => void
removeListener?: (...args: any[]) => void
}
web3?: {}
}
......@@ -5,10 +5,12 @@ import { useWeb3React as useWeb3ReactCore } from '@web3-react/core'
import { isMobile } from 'react-device-detect'
import copy from 'copy-to-clipboard'
import IUniswapV1Factory from '../constants/abis/v1_factory.json'
import ERC20_ABI from '../constants/abis/erc20.json'
import { abi as IUniswapV2PairABI } from '@uniswap/v2-core/build/IUniswapV2Pair.json'
import { injected } from '../connectors'
import { NetworkContextName } from '../constants'
import { getContract, getExchangeContract, isAddress } from '../utils'
import { NetworkContextName, V1_FACTORY_ADDRESS } from '../constants'
import { getContract, isAddress } from '../utils'
export function useActiveWeb3React() {
const context = useWeb3ReactCore<Web3Provider>()
......@@ -66,7 +68,7 @@ export function useInactiveListener(suppress = false) {
})
}
const handleAccountsChanged = accounts => {
const handleAccountsChanged = (accounts: string[]) => {
if (accounts.length > 0) {
// eat errors
activate(injected, undefined, true).catch(error => {
......@@ -94,6 +96,7 @@ export function useInactiveListener(suppress = false) {
}
}
}
return
}, [active, error, suppress, activate])
}
......@@ -119,7 +122,7 @@ export function useDebounce<T>(value: T, delay: number): T {
}
// modified from https://usehooks.com/useKeyPress/
export function useBodyKeyDown(targetKey, onKeyDown, suppressOnKeyDown = false) {
export function useBodyKeyDown(targetKey: string, onKeyDown: () => void, suppressOnKeyDown = false) {
const downHandler = useCallback(
event => {
const {
......@@ -142,12 +145,13 @@ export function useBodyKeyDown(targetKey, onKeyDown, suppressOnKeyDown = false)
}, [downHandler])
}
export function useENSName(address) {
export function useENSName(address?: string): string | null {
const { library } = useActiveWeb3React()
const [ENSName, setENSName] = useState<string | null>(null)
useEffect(() => {
if (!library || !address) return
if (isAddress(address)) {
let stale = false
library
......@@ -172,47 +176,37 @@ export function useENSName(address) {
setENSName(null)
}
}
return
}, [library, address])
return ENSName
}
// returns null on errors
export function useContract(address, ABI, withSignerIfPossible = true) {
function useContract(address?: string, ABI?: any, withSignerIfPossible = true): Contract | null {
const { library, account } = useActiveWeb3React()
return useMemo(() => {
if (!address || !ABI || !library) return null
try {
return getContract(address, ABI, library, withSignerIfPossible ? account : undefined)
return getContract(address, ABI, library, withSignerIfPossible && account ? account : undefined)
} catch {
return null
}
}, [address, ABI, library, withSignerIfPossible, account])
}
// returns null on errors
export function useTokenContract(tokenAddress: string, withSignerIfPossible = true): Contract {
const { library, account } = useActiveWeb3React()
return useMemo(() => {
try {
return getContract(tokenAddress, ERC20_ABI, library, withSignerIfPossible ? account : undefined)
} catch {
return null
}
}, [tokenAddress, library, withSignerIfPossible, account])
export function useV1FactoryContract(): Contract | null {
return useContract(V1_FACTORY_ADDRESS, IUniswapV1Factory, false)
}
export function usePairContract(pairAddress, withSignerIfPossible = true) {
const { library, account } = useActiveWeb3React()
// returns null on errors
export function useTokenContract(tokenAddress?: string, withSignerIfPossible = true): Contract | null {
return useContract(tokenAddress, ERC20_ABI, withSignerIfPossible)
}
return useMemo(() => {
try {
return getExchangeContract(pairAddress, library, withSignerIfPossible ? account : undefined)
} catch {
return null
}
}, [pairAddress, library, withSignerIfPossible, account])
export function usePairContract(pairAddress?: string, withSignerIfPossible = true): Contract | null {
return useContract(pairAddress, IUniswapV2PairABI, withSignerIfPossible)
}
export function useCopyClipboard(timeout = 500): [boolean, (toCopy: string) => void] {
......@@ -233,16 +227,17 @@ export function useCopyClipboard(timeout = 500): [boolean, (toCopy: string) => v
clearTimeout(hide)
}
}
return
}, [isCopied, setIsCopied, timeout])
return [isCopied, staticCopy]
}
// modified from https://usehooks.com/usePrevious/
export function usePrevious(value) {
export function usePrevious<T>(value: T) {
// The ref object is a generic container whose current property is mutable ...
// ... and can hold any value, similar to an instance property on a class
const ref = useRef()
const ref = useRef<T>()
// Store current value in ref
useEffect(() => {
......
{
"extends": "../../tsconfig.strict.json",
"include": ["**/*"]
}
\ No newline at end of file
import { MaxUint256 } from '@ethersproject/constants'
import { TransactionResponse } from '@ethersproject/providers'
import { Trade, WETH, TokenAmount } from '@uniswap/sdk'
import { useCallback, useMemo } from 'react'
import { ROUTER_ADDRESS } from '../constants'
......@@ -9,7 +10,7 @@ import { computeSlippageAdjustedAmounts } from '../utils/prices'
import { calculateGasMargin } from '../utils'
import { useTokenContract, useActiveWeb3React } from './index'
export enum Approval {
export enum ApprovalState {
UNKNOWN,
NOT_APPROVED,
PENDING,
......@@ -20,29 +21,40 @@ export enum Approval {
export function useApproveCallback(
amountToApprove?: TokenAmount,
addressToApprove?: string
): [Approval, () => Promise<void>] {
): [ApprovalState, () => Promise<void>] {
const { account } = useActiveWeb3React()
const currentAllowance = useTokenAllowance(amountToApprove?.token, account, addressToApprove)
const currentAllowance = useTokenAllowance(amountToApprove?.token, account ?? undefined, addressToApprove)
const pendingApproval = useHasPendingApproval(amountToApprove?.token?.address)
// check the current approval status
const approval = useMemo(() => {
if (!amountToApprove) return ApprovalState.UNKNOWN
// we treat WETH as ETH which requires no approvals
if (amountToApprove?.token?.equals(WETH[amountToApprove?.token?.chainId])) return Approval.APPROVED
if (amountToApprove.token.equals(WETH[amountToApprove.token.chainId])) return ApprovalState.APPROVED
// we might not have enough data to know whether or not we need to approve
if (!currentAllowance) return Approval.UNKNOWN
if (pendingApproval) return Approval.PENDING
if (!currentAllowance) return ApprovalState.UNKNOWN
if (pendingApproval) return ApprovalState.PENDING
// amountToApprove will be defined if currentAllowance is
return currentAllowance.lessThan(amountToApprove) ? Approval.NOT_APPROVED : Approval.APPROVED
return currentAllowance.lessThan(amountToApprove) ? ApprovalState.NOT_APPROVED : ApprovalState.APPROVED
}, [amountToApprove, currentAllowance, pendingApproval])
const tokenContract = useTokenContract(amountToApprove?.token?.address)
const addTransaction = useTransactionAdder()
const approve = useCallback(async (): Promise<void> => {
if (approval !== Approval.NOT_APPROVED) {
console.error('approve was called unnecessarily, this is likely an error.')
if (approval !== ApprovalState.NOT_APPROVED) {
console.error('approve was called unnecessarily')
return
}
if (!tokenContract) {
console.error('tokenContract is null')
return
}
if (!amountToApprove) {
console.error('missing amount to approve')
return
}
......@@ -57,13 +69,13 @@ export function useApproveCallback(
.approve(addressToApprove, useExact ? amountToApprove.raw.toString() : MaxUint256, {
gasLimit: calculateGasMargin(estimatedGas)
})
.then(response => {
.then((response: TransactionResponse) => {
addTransaction(response, {
summary: 'Approve ' + amountToApprove?.token?.symbol,
approvalOfToken: amountToApprove?.token?.address
})
})
.catch(error => {
.catch((error: Error) => {
console.debug('Failed to approve token', error)
throw error
})
......@@ -74,9 +86,9 @@ export function useApproveCallback(
// wraps useApproveCallback in the context of a swap
export function useApproveCallbackFromTrade(trade?: Trade, allowedSlippage = 0) {
const amountToApprove = useMemo(() => computeSlippageAdjustedAmounts(trade, allowedSlippage)[Field.INPUT], [
trade,
allowedSlippage
])
const amountToApprove = useMemo(
() => (trade ? computeSlippageAdjustedAmounts(trade, allowedSlippage)[Field.INPUT] : undefined),
[trade, allowedSlippage]
)
return useApproveCallback(amountToApprove, ROUTER_ADDRESS)
}
......@@ -11,12 +11,14 @@ export default function useInterval(callback: () => void, delay: null | number)
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current()
const current = savedCallback.current
current && current()
}
if (delay !== null) {
const id = setInterval(tick, delay)
return () => clearInterval(id)
}
return
}, [delay])
}
import { BigNumber } from '@ethersproject/bignumber'
import { WETH, TokenAmount, JSBI } from '@uniswap/sdk'
import { TransactionResponse } from '@ethersproject/providers'
import { WETH, TokenAmount, JSBI, ChainId } from '@uniswap/sdk'
import { useMemo } from 'react'
import { useTransactionAdder } from '../state/transactions/hooks'
import { useTokenBalanceTreatingWETHasETH } from '../state/wallet/hooks'
......@@ -14,7 +15,7 @@ export function useSendCallback(amount?: TokenAmount, recipient?: string): null
const addTransaction = useTransactionAdder()
const ensName = useENSName(recipient)
const tokenContract = useTokenContract(amount?.token?.address)
const balance = useTokenBalanceTreatingWETHasETH(account, amount?.token)
const balance = useTokenBalanceTreatingWETHasETH(account ?? undefined, amount?.token)
return useMemo(() => {
if (!amount) return null
......@@ -26,16 +27,19 @@ export function useSendCallback(amount?: TokenAmount, recipient?: string): null
const token = amount?.token
return async function onSend(): Promise<string> {
if (token.equals(WETH[chainId])) {
if (!chainId || !library || !account || !tokenContract) {
throw new Error('missing dependencies in onSend callback')
}
if (token.equals(WETH[chainId as ChainId])) {
return getSigner(library, account)
.sendTransaction({ to: recipient, value: BigNumber.from(amount.raw.toString()) })
.then(response => {
.then((response: TransactionResponse) => {
addTransaction(response, {
summary: 'Send ' + amount.toSignificant(3) + ' ' + token?.symbol + ' to ' + (ensName ?? recipient)
})
return response.hash
})
.catch(error => {
.catch((error: Error) => {
console.error('Failed to transfer ETH', error)
throw error
})
......@@ -47,7 +51,7 @@ export function useSendCallback(amount?: TokenAmount, recipient?: string): null
.transfer(recipient, amount.raw.toString(), {
gasLimit: calculateGasMargin(estimatedGasLimit)
})
.then(response => {
.then((response: TransactionResponse) => {
addTransaction(response, {
summary: 'Send ' + amount.toSignificant(3) + ' ' + token.symbol + ' to ' + (ensName ?? recipient)
})
......
import { BigNumber } from '@ethersproject/bignumber'
import { Contract } from '@ethersproject/contracts'
import { Token, Trade, TradeType, WETH } from '@uniswap/sdk'
import { ChainId, Token, Trade, TradeType, WETH } from '@uniswap/sdk'
import { useMemo } from 'react'
import { DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE, ROUTER_ADDRESS } from '../constants'
import { useTokenAllowance } from '../data/Allowances'
......@@ -21,17 +21,17 @@ enum SwapType {
function getSwapType(tokens: { [field in Field]?: Token }, isExactIn: boolean, chainId: number): SwapType {
if (isExactIn) {
if (tokens[Field.INPUT]?.equals(WETH[chainId])) {
if (tokens[Field.INPUT]?.equals(WETH[chainId as ChainId])) {
return SwapType.EXACT_ETH_FOR_TOKENS
} else if (tokens[Field.OUTPUT]?.equals(WETH[chainId])) {
} else if (tokens[Field.OUTPUT]?.equals(WETH[chainId as ChainId])) {
return SwapType.EXACT_TOKENS_FOR_ETH
} else {
return SwapType.EXACT_TOKENS_FOR_TOKENS
}
} else {
if (tokens[Field.INPUT]?.equals(WETH[chainId])) {
if (tokens[Field.INPUT]?.equals(WETH[chainId as ChainId])) {
return SwapType.ETH_FOR_EXACT_TOKENS
} else if (tokens[Field.OUTPUT]?.equals(WETH[chainId])) {
} else if (tokens[Field.OUTPUT]?.equals(WETH[chainId as ChainId])) {
return SwapType.TOKENS_FOR_EXACT_ETH
} else {
return SwapType.TOKENS_FOR_EXACT_TOKENS
......@@ -48,27 +48,35 @@ export function useSwapCallback(
to?: string // recipient of output, optional
): null | (() => Promise<string>) {
const { account, chainId, library } = useActiveWeb3React()
const inputAllowance = useTokenAllowance(trade?.inputAmount?.token, account, ROUTER_ADDRESS)
const inputAllowance = useTokenAllowance(trade?.inputAmount?.token, account ?? undefined, ROUTER_ADDRESS)
const addTransaction = useTransactionAdder()
const recipient = to ? isAddress(to) : account
const ensName = useENSName(to)
return useMemo(() => {
if (!trade) return null
if (!recipient) return null
if (!trade || !recipient) return null
// will always be defined
const slippageAdjustedAmounts = computeSlippageAdjustedAmounts(trade, allowedSlippage)
const {
[Field.INPUT]: slippageAdjustedInput,
[Field.OUTPUT]: slippageAdjustedOutput
} = computeSlippageAdjustedAmounts(trade, allowedSlippage)
if (!slippageAdjustedInput || !slippageAdjustedOutput) return null
// no allowance
if (
!trade.inputAmount.token.equals(WETH[chainId]) &&
(!inputAllowance || slippageAdjustedAmounts[Field.INPUT].greaterThan(inputAllowance))
!trade.inputAmount.token.equals(WETH[chainId as ChainId]) &&
(!inputAllowance || slippageAdjustedInput.greaterThan(inputAllowance))
) {
return null
}
return async function onSwap() {
if (!chainId || !library || !account) {
throw new Error('missing dependencies in onSwap callback')
}
const routerContract: Contract = getRouterContract(chainId, library, account)
const path = trade.route.path.map(t => t.address)
......@@ -78,17 +86,17 @@ export function useSwapCallback(
const swapType = getSwapType(
{ [Field.INPUT]: trade.inputAmount.token, [Field.OUTPUT]: trade.outputAmount.token },
trade.tradeType === TradeType.EXACT_INPUT,
chainId
chainId as ChainId
)
let estimate, method, args, value
let estimate, method: Function, args: Array<string | string[] | number>, value: BigNumber | null
switch (swapType) {
case SwapType.EXACT_TOKENS_FOR_TOKENS:
estimate = routerContract.estimateGas.swapExactTokensForTokens
method = routerContract.swapExactTokensForTokens
args = [
slippageAdjustedAmounts[Field.INPUT].raw.toString(),
slippageAdjustedAmounts[Field.OUTPUT].raw.toString(),
slippageAdjustedInput.raw.toString(),
slippageAdjustedOutput.raw.toString(),
path,
recipient,
deadlineFromNow
......@@ -99,8 +107,8 @@ export function useSwapCallback(
estimate = routerContract.estimateGas.swapTokensForExactTokens
method = routerContract.swapTokensForExactTokens
args = [
slippageAdjustedAmounts[Field.OUTPUT].raw.toString(),
slippageAdjustedAmounts[Field.INPUT].raw.toString(),
slippageAdjustedOutput.raw.toString(),
slippageAdjustedInput.raw.toString(),
path,
recipient,
deadlineFromNow
......@@ -110,15 +118,15 @@ export function useSwapCallback(
case SwapType.EXACT_ETH_FOR_TOKENS:
estimate = routerContract.estimateGas.swapExactETHForTokens
method = routerContract.swapExactETHForTokens
args = [slippageAdjustedAmounts[Field.OUTPUT].raw.toString(), path, recipient, deadlineFromNow]
value = BigNumber.from(slippageAdjustedAmounts[Field.INPUT].raw.toString())
args = [slippageAdjustedOutput.raw.toString(), path, recipient, deadlineFromNow]
value = BigNumber.from(slippageAdjustedInput.raw.toString())
break
case SwapType.TOKENS_FOR_EXACT_ETH:
estimate = routerContract.estimateGas.swapTokensForExactETH
method = routerContract.swapTokensForExactETH
args = [
slippageAdjustedAmounts[Field.OUTPUT].raw.toString(),
slippageAdjustedAmounts[Field.INPUT].raw.toString(),
slippageAdjustedOutput.raw.toString(),
slippageAdjustedInput.raw.toString(),
path,
recipient,
deadlineFromNow
......@@ -129,8 +137,8 @@ export function useSwapCallback(
estimate = routerContract.estimateGas.swapExactTokensForETH
method = routerContract.swapExactTokensForETH
args = [
slippageAdjustedAmounts[Field.INPUT].raw.toString(),
slippageAdjustedAmounts[Field.OUTPUT].raw.toString(),
slippageAdjustedInput.raw.toString(),
slippageAdjustedOutput.raw.toString(),
path,
recipient,
deadlineFromNow
......@@ -140,8 +148,8 @@ export function useSwapCallback(
case SwapType.ETH_FOR_EXACT_TOKENS:
estimate = routerContract.estimateGas.swapETHForExactTokens
method = routerContract.swapETHForExactTokens
args = [slippageAdjustedAmounts[Field.OUTPUT].raw.toString(), path, recipient, deadlineFromNow]
value = BigNumber.from(slippageAdjustedAmounts[Field.INPUT].raw.toString())
args = [slippageAdjustedOutput.raw.toString(), path, recipient, deadlineFromNow]
value = BigNumber.from(slippageAdjustedInput.raw.toString())
break
}
......@@ -157,11 +165,11 @@ export function useSwapCallback(
addTransaction(response, {
summary:
'Swap ' +
slippageAdjustedAmounts[Field.INPUT].toSignificant(3) +
slippageAdjustedInput.toSignificant(3) +
' ' +
trade.inputAmount.token.symbol +
' for ' +
slippageAdjustedAmounts[Field.OUTPUT].toSignificant(3) +
slippageAdjustedOutput.toSignificant(3) +
' ' +
trade.outputAmount.token.symbol
})
......@@ -169,11 +177,11 @@ export function useSwapCallback(
addTransaction(response, {
summary:
'Swap ' +
slippageAdjustedAmounts[Field.INPUT].toSignificant(3) +
slippageAdjustedInput.toSignificant(3) +
' ' +
trade.inputAmount.token.symbol +
' for ' +
slippageAdjustedAmounts[Field.OUTPUT].toSignificant(3) +
slippageAdjustedOutput.toSignificant(3) +
' ' +
trade.outputAmount.token.symbol +
' to ' +
......
......@@ -31,7 +31,7 @@ import { TYPE } from '../../theme'
import { calculateGasMargin, calculateSlippageAmount, getRouterContract } from '../../utils'
import AppBody from '../AppBody'
import { ClickableText, FixedBottom, MaxButton, Wrapper } from '../Pool/styleds'
import { useApproveCallback, Approval } from '../../hooks/useApproveCallback'
import { useApproveCallback, ApprovalState } from '../../hooks/useApproveCallback'
import { Dots } from '../../components/swap/styleds'
// denominated in bips
......@@ -446,7 +446,7 @@ export default function RemoveLiquidity({ match: { params } }: RouteComponentPro
let estimate, method, args
// we have approval, use normal remove liquidity
if (approval === Approval.APPROVED) {
if (approval === ApprovalState.APPROVED) {
// removeLiquidityETH
if (oneTokenIsETH) {
estimate = router.estimateGas.removeLiquidityETH
......@@ -619,15 +619,15 @@ export default function RemoveLiquidity({ match: { params } }: RouteComponentPro
<RowBetween mt="1rem">
<ButtonConfirmed
onClick={onAttemptToApprove}
confirmed={approval === Approval.APPROVED || signatureData !== null}
disabled={approval !== Approval.NOT_APPROVED || signatureData !== null}
confirmed={approval === ApprovalState.APPROVED || signatureData !== null}
disabled={approval !== ApprovalState.NOT_APPROVED || signatureData !== null}
mr="0.5rem"
fontWeight={500}
fontSize={20}
>
{approval === Approval.PENDING ? (
{approval === ApprovalState.PENDING ? (
<Dots>Approving</Dots>
) : approval === Approval.APPROVED || signatureData !== null ? (
) : approval === ApprovalState.APPROVED || signatureData !== null ? (
'Approved'
) : (
'Approve'
......@@ -635,7 +635,7 @@ export default function RemoveLiquidity({ match: { params } }: RouteComponentPro
</ButtonConfirmed>
<ButtonPrimary
disabled={!(approval === Approval.APPROVED || signatureData !== null)}
disabled={!(approval === ApprovalState.APPROVED || signatureData !== null)}
onClick={onRemove}
ml="0.5rem"
>
......
......@@ -25,7 +25,7 @@ import TokenLogo from '../../components/TokenLogo'
import { TokenWarningCards } from '../../components/TokenWarningCard'
import { DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE, MIN_ETH } from '../../constants'
import { useActiveWeb3React } from '../../hooks'
import { useApproveCallbackFromTrade, Approval } from '../../hooks/useApproveCallback'
import { useApproveCallbackFromTrade, ApprovalState } from '../../hooks/useApproveCallback'
import { useSendCallback } from '../../hooks/useSendCallback'
import { useSwapCallback } from '../../hooks/useSwapCallback'
import { useWalletModalToggle } from '../../state/application/hooks'
......@@ -153,7 +153,7 @@ export default function Send({ location: { search } }: RouteComponentProps) {
}
const sendCallback = useSendCallback(parsedAmounts?.[Field.INPUT], recipient)
const isSendValid = sendCallback !== null && (sendingWithSwap === false || approval === Approval.APPROVED)
const isSendValid = sendCallback !== null && (sendingWithSwap === false || approval === ApprovalState.APPROVED)
async function onSend() {
setAttemptingTxn(true)
......@@ -465,9 +465,9 @@ export default function Send({ location: { search } }: RouteComponentProps) {
<GreyCard style={{ textAlign: 'center' }}>
<TYPE.main mb="4px">Insufficient liquidity for this trade.</TYPE.main>
</GreyCard>
) : approval === Approval.NOT_APPROVED || approval === Approval.PENDING ? (
<ButtonLight onClick={approveCallback} disabled={approval === Approval.PENDING}>
{approval === Approval.PENDING ? (
) : approval === ApprovalState.NOT_APPROVED || approval === ApprovalState.PENDING ? (
<ButtonLight onClick={approveCallback} disabled={approval === ApprovalState.PENDING}>
{approval === ApprovalState.PENDING ? (
<Dots>Approving {tokens[Field.INPUT]?.symbol}</Dots>
) : (
'Approve ' + tokens[Field.INPUT]?.symbol
......
......@@ -23,7 +23,7 @@ import V1TradeLink from '../../components/swap/V1TradeLink'
import { TokenWarningCards } from '../../components/TokenWarningCard'
import { DEFAULT_DEADLINE_FROM_NOW, INITIAL_ALLOWED_SLIPPAGE, MIN_ETH } from '../../constants'
import { useActiveWeb3React } from '../../hooks'
import { useApproveCallbackFromTrade, Approval } from '../../hooks/useApproveCallback'
import { useApproveCallbackFromTrade, ApprovalState } from '../../hooks/useApproveCallback'
import { useSwapCallback } from '../../hooks/useSwapCallback'
import { useWalletModalToggle } from '../../state/application/hooks'
import { Field } from '../../state/swap/actions'
......@@ -270,9 +270,9 @@ export default function Swap({ location: { search } }: RouteComponentProps) {
<GreyCard style={{ textAlign: 'center' }}>
<TYPE.main mb="4px">Insufficient liquidity for this trade.</TYPE.main>
</GreyCard>
) : approval === Approval.NOT_APPROVED || approval === Approval.PENDING ? (
<ButtonLight onClick={approveCallback} disabled={approval === Approval.PENDING}>
{approval === Approval.PENDING ? (
) : approval === ApprovalState.NOT_APPROVED || approval === ApprovalState.PENDING ? (
<ButtonLight onClick={approveCallback} disabled={approval === ApprovalState.PENDING}>
{approval === ApprovalState.PENDING ? (
<Dots>Approving {tokens[Field.INPUT]?.symbol}</Dots>
) : (
'Approve ' + tokens[Field.INPUT]?.symbol
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment