Use eslint/prettier for typescript files (#737)
* Use eslint/prettier for typescript files * Fix more linting errors * Turn linting errors off so CI passes
This commit is contained in:
commit
e023a02037
32
.eslintrc.json
Normal file
32
.eslintrc.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
// Allows for the parsing of JSX
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"ignorePatterns": [
|
||||
"node_modules/**/*"
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
"extends": [
|
||||
"plugin:react/recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier/@typescript-eslint",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
"prettier/prettier": "error",
|
||||
"react/prop-types": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"react/display-name": "off"
|
||||
}
|
||||
}
|
13
.github/workflows/tests.yaml
vendored
13
.github/workflows/tests.yaml
vendored
@ -31,4 +31,15 @@ jobs:
|
||||
- run: yarn
|
||||
- run: yarn test
|
||||
|
||||
# todo: add job for typescript linting
|
||||
lint:
|
||||
name: Lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '12'
|
||||
- run: yarn
|
||||
- run: yarn lint
|
||||
|
||||
|
@ -15,4 +15,4 @@ describe('Homepage', () => {
|
||||
it('can enter an amount into output', () => {
|
||||
cy.get('#swapOutputField').type('0.001')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -15,7 +15,7 @@
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
module.exports = (on, config) => {
|
||||
module.exports = () => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
}
|
||||
|
@ -24,4 +24,4 @@
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
|
||||
// TODO(moodysalem): commands for connecting a mock ethereum provider.
|
||||
// TODO(moodysalem): commands for connecting a mock ethereum provider.
|
||||
|
16
package.json
16
package.json
@ -57,7 +57,13 @@
|
||||
"@types/react-dom": "^16.9.7",
|
||||
"@types/react-router-dom": "^5.0.0",
|
||||
"@types/styled-components": "^4.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.31.0",
|
||||
"@typescript-eslint/parser": "^2.31.0",
|
||||
"cypress": "^4.5.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
"eslint-plugin-react": "^7.19.0",
|
||||
"prettier": "^1.17.0",
|
||||
"serve": "^11.3.0",
|
||||
"start-server-and-test": "^1.11.0",
|
||||
@ -68,14 +74,8 @@
|
||||
"build": "cross-env REACT_APP_GIT_COMMIT_HASH=$(git show -s --format=%H) react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject",
|
||||
"lint:base": "yarn eslint './src/**/*.{js,jsx}'",
|
||||
"format:base": "yarn prettier './src/**/*.{js,jsx,scss}'",
|
||||
"fix:lint": "yarn lint:base --fix",
|
||||
"fix:format": "yarn format:base --write",
|
||||
"fix:all": "yarn fix:lint && yarn fix:format",
|
||||
"check:lint": "yarn lint:base",
|
||||
"check:format": "yarn format:base --check",
|
||||
"check:all": "yarn check:lint && yarn check:format",
|
||||
"lint": "eslint '**/*.{js,jsx,ts,tsx}'",
|
||||
"lint:fix": "eslint '**/*.{js,jsx,ts,tsx}' --fix",
|
||||
"cy:run": "cypress run",
|
||||
"serve:build": "serve -s build -l 3000",
|
||||
"integration-test": "yarn build && start-server-and-test 'yarn run serve:build' http://localhost:3000 cy:run"
|
||||
|
@ -33,12 +33,12 @@ export default function CopyHelper(props: { toCopy: string; children?: React.Rea
|
||||
{props.children}
|
||||
{isCopied ? (
|
||||
<TransactionStatusText>
|
||||
<CheckCircle size={'16'}/>
|
||||
<CheckCircle size={'16'} />
|
||||
<TransactionStatusText>Copied</TransactionStatusText>
|
||||
</TransactionStatusText>
|
||||
) : (
|
||||
<TransactionStatusText>
|
||||
<Copy size={'16'}/>
|
||||
<Copy size={'16'} />
|
||||
</TransactionStatusText>
|
||||
)}
|
||||
</CopyIcon>
|
||||
|
@ -43,7 +43,7 @@ const rotate = keyframes`
|
||||
}
|
||||
`
|
||||
|
||||
const TransactionState = styled.div<{pending?: boolean;}>`
|
||||
const TransactionState = styled.div<{ pending?: boolean }>`
|
||||
display: flex;
|
||||
background-color: ${({ pending, theme }) =>
|
||||
pending ? transparentize(0.95, theme.blue1) : transparentize(0.95, theme.green1)};
|
||||
@ -64,13 +64,13 @@ const TransactionState = styled.div<{pending?: boolean;}>`
|
||||
pending ? transparentize(0, theme.blue1) : transparentize(0, theme.green1)};
|
||||
}
|
||||
`
|
||||
const ButtonWrapper = styled.div<{pending: boolean}>`
|
||||
const ButtonWrapper = styled.div<{ pending: boolean }>`
|
||||
a {
|
||||
color: ${({ pending, theme }) => (pending ? theme.blue1 : theme.green1)};
|
||||
}
|
||||
`
|
||||
|
||||
export default function Transaction({ hash, pending }) {
|
||||
export default function Transaction({ hash, pending }: { hash: string; pending: boolean }) {
|
||||
const { chainId } = useWeb3React()
|
||||
const allTransactions = useAllTransactions()
|
||||
|
||||
|
@ -129,7 +129,7 @@ const LowerSection = styled.div`
|
||||
}
|
||||
`
|
||||
|
||||
const AccountControl = styled.div<{ hasENS: boolean; isENS: boolean; }>`
|
||||
const AccountControl = styled.div<{ hasENS: boolean; isENS: boolean }>`
|
||||
${({ theme }) => theme.flexRowNoWrap};
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
@ -156,7 +156,7 @@ const ConnectButtonRow = styled.div`
|
||||
margin: 10px 0;
|
||||
`
|
||||
|
||||
const StyledLink = styled(Link) <{ hasENS: boolean; isENS: boolean; }>`
|
||||
const StyledLink = styled(Link)<{ hasENS: boolean; isENS: boolean }>`
|
||||
color: ${({ hasENS, isENS, theme }) => (hasENS ? (isENS ? theme.blue1 : theme.text3) : theme.blue1)};
|
||||
`
|
||||
|
||||
@ -181,7 +181,7 @@ const WalletName = styled.div`
|
||||
width: initial;
|
||||
`
|
||||
|
||||
const IconWrapper = styled.div<{size?: number}>`
|
||||
const IconWrapper = styled.div<{ size?: number }>`
|
||||
${({ theme }) => theme.flexColumnNoWrap};
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -217,19 +217,27 @@ function renderTransactions(transactions, pending) {
|
||||
return (
|
||||
<TransactionListWrapper>
|
||||
{transactions.map((hash, i) => {
|
||||
return <Transaction key={i} hash={hash} pending={pending}/>
|
||||
return <Transaction key={i} hash={hash} pending={pending} />
|
||||
})}
|
||||
</TransactionListWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
interface AccountDetailsProps {
|
||||
toggleWalletModal: () => void
|
||||
pendingTransactions: any[]
|
||||
confirmedTransactions: any[]
|
||||
ENSName?: string
|
||||
openOptions: () => void
|
||||
}
|
||||
|
||||
export default function AccountDetails({
|
||||
toggleWalletModal,
|
||||
pendingTransactions,
|
||||
confirmedTransactions,
|
||||
ENSName,
|
||||
openOptions
|
||||
}) {
|
||||
toggleWalletModal,
|
||||
pendingTransactions,
|
||||
confirmedTransactions,
|
||||
ENSName,
|
||||
openOptions
|
||||
}: AccountDetailsProps) {
|
||||
const { chainId, account, connector } = useWeb3React()
|
||||
const theme = useContext(ThemeContext)
|
||||
|
||||
@ -249,32 +257,32 @@ export default function AccountDetails({
|
||||
if (connector === injected) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<Identicon/> {formatConnectorName()}
|
||||
<Identicon /> {formatConnectorName()}
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletconnect) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={WalletConnectIcon} alt={''}/> {formatConnectorName()}
|
||||
<img src={WalletConnectIcon} alt={''} /> {formatConnectorName()}
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletlink) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={CoinbaseWalletIcon} alt={''}/> {formatConnectorName()}
|
||||
<img src={CoinbaseWalletIcon} alt={''} /> {formatConnectorName()}
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === fortmatic) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={FortmaticIcon} alt={''}/> {formatConnectorName()}
|
||||
<img src={FortmaticIcon} alt={''} /> {formatConnectorName()}
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === portis) {
|
||||
return (
|
||||
<>
|
||||
<IconWrapper size={16}>
|
||||
<img src={PortisIcon} alt={''}/> {formatConnectorName()}
|
||||
<img src={PortisIcon} alt={''} /> {formatConnectorName()}
|
||||
<MainWalletAction
|
||||
onClick={() => {
|
||||
portis.portis.showPortis()
|
||||
@ -292,7 +300,7 @@ export default function AccountDetails({
|
||||
<>
|
||||
<UpperSection>
|
||||
<CloseIcon onClick={toggleWalletModal}>
|
||||
<CloseColor/>
|
||||
<CloseColor />
|
||||
</CloseIcon>
|
||||
<HeaderRow>Account</HeaderRow>
|
||||
<AccountSection>
|
||||
@ -304,7 +312,7 @@ export default function AccountDetails({
|
||||
{connector !== injected && connector !== walletlink && (
|
||||
<WalletAction
|
||||
onClick={() => {
|
||||
(connector as any).close()
|
||||
;(connector as any).close()
|
||||
}}
|
||||
>
|
||||
Disconnect
|
||||
@ -312,7 +320,7 @@ export default function AccountDetails({
|
||||
)}
|
||||
<CircleWrapper>
|
||||
<GreenCircle>
|
||||
<div/>
|
||||
<div />
|
||||
</GreenCircle>
|
||||
</CircleWrapper>
|
||||
</div>
|
||||
@ -323,14 +331,14 @@ export default function AccountDetails({
|
||||
<StyledLink hasENS={!!ENSName} isENS={true} href={getEtherscanLink(chainId, ENSName, 'address')}>
|
||||
{ENSName} ↗{' '}
|
||||
</StyledLink>
|
||||
<Copy toCopy={ENSName}/>
|
||||
<Copy toCopy={ENSName} />
|
||||
</AccountControl>
|
||||
) : (
|
||||
<AccountControl hasENS={!!ENSName} isENS={false}>
|
||||
<StyledLink hasENS={!!ENSName} isENS={false} href={getEtherscanLink(chainId, account, 'address')}>
|
||||
{account} ↗{' '}
|
||||
</StyledLink>
|
||||
<Copy toCopy={account}/>
|
||||
<Copy toCopy={account} />
|
||||
</AccountControl>
|
||||
)}
|
||||
</AccountGroupingRow>
|
||||
|
@ -63,7 +63,15 @@ const Input = styled.input<{ error: boolean }>`
|
||||
// border-radius: 8px;
|
||||
// `
|
||||
|
||||
export default function AddressInputPanel({ initialInput = '', onChange, onError }) {
|
||||
export default function AddressInputPanel({
|
||||
initialInput = '',
|
||||
onChange,
|
||||
onError
|
||||
}: {
|
||||
initialInput?: string
|
||||
onChange: (val: { address: string; name?: string }) => void
|
||||
onError: (error: boolean, input: string) => void
|
||||
}) {
|
||||
const { library } = useWeb3React()
|
||||
|
||||
const [input, setInput] = useState(initialInput ? initialInput : '')
|
||||
|
@ -17,7 +17,7 @@ const InputWrapper = styled(RowBetween)`
|
||||
padding: 4px 8px;
|
||||
border: 1px solid transparent;
|
||||
border: ${({ active, error, theme }) =>
|
||||
error ? '1px solid ' + theme.red1 : active ? '1px solid ' + theme.blue1 : ''};
|
||||
error ? '1px solid ' + theme.red1 : active ? '1px solid ' + theme.blue1 : ''};
|
||||
`
|
||||
|
||||
const SLIPPAGE_INDEX = {
|
||||
@ -34,7 +34,12 @@ interface AdvancedSettingsProps {
|
||||
setAllowedSlippage: (number) => void
|
||||
}
|
||||
|
||||
export default function AdvancedSettings({ setIsOpen, setDeadline, allowedSlippage, setAllowedSlippage }: AdvancedSettingsProps) {
|
||||
export default function AdvancedSettings({
|
||||
setIsOpen,
|
||||
setDeadline,
|
||||
allowedSlippage,
|
||||
setAllowedSlippage
|
||||
}: AdvancedSettingsProps) {
|
||||
// text translation
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -78,7 +83,7 @@ export default function AdvancedSettings({ setIsOpen, setDeadline, allowedSlippa
|
||||
setActiveIndex(3)
|
||||
} else {
|
||||
setActiveIndex(4)
|
||||
setSlippageInput('' + (allowedSlippage / 100))
|
||||
setSlippageInput('' + allowedSlippage / 100)
|
||||
parseCustomInput(allowedSlippage)
|
||||
}
|
||||
}, [allowedSlippage, parseCustomInput])
|
||||
@ -94,7 +99,7 @@ export default function AdvancedSettings({ setIsOpen, setDeadline, allowedSlippa
|
||||
</Link>
|
||||
<RowBetween>
|
||||
<TYPE.main>Front-running tolerance</TYPE.main>
|
||||
<QuestionHelper text={t('toleranceExplanation')}/>
|
||||
<QuestionHelper text={t('toleranceExplanation')} />
|
||||
</RowBetween>
|
||||
<Row>
|
||||
<ButtonRadio
|
||||
|
@ -10,7 +10,10 @@ export const ColumnCenter = styled(Column)`
|
||||
align-items: center;
|
||||
`
|
||||
|
||||
export const AutoColumn = styled.div<{gap?: 'sm' | 'md' | 'lg' | string; justify?: 'stretch' | 'center' | 'start' | 'end' | 'flex-start' | 'flex-end';}>`
|
||||
export const AutoColumn = styled.div<{
|
||||
gap?: 'sm' | 'md' | 'lg' | string
|
||||
justify?: 'stretch' | 'center' | 'start' | 'end' | 'flex-start' | 'flex-end'
|
||||
}>`
|
||||
display: grid;
|
||||
grid-auto-rows: auto;
|
||||
grid-row-gap: ${({ gap }) => (gap === 'sm' && '8px') || (gap === 'md' && '12px') || (gap === 'lg' && '24px') || gap};
|
||||
|
@ -45,17 +45,17 @@ interface ConfirmationModalProps extends RouteComponentProps<{}> {
|
||||
}
|
||||
|
||||
function ConfirmationModal({
|
||||
history,
|
||||
isOpen,
|
||||
onDismiss,
|
||||
hash,
|
||||
topContent,
|
||||
bottomContent,
|
||||
attemptingTxn,
|
||||
pendingConfirmation,
|
||||
pendingText,
|
||||
title = ''
|
||||
}: ConfirmationModalProps) {
|
||||
history,
|
||||
isOpen,
|
||||
onDismiss,
|
||||
hash,
|
||||
topContent,
|
||||
bottomContent,
|
||||
attemptingTxn,
|
||||
pendingConfirmation,
|
||||
pendingText,
|
||||
title = ''
|
||||
}: ConfirmationModalProps) {
|
||||
const { chainId } = useWeb3React()
|
||||
|
||||
const dismissAndReturn = useCallback(() => {
|
||||
@ -74,7 +74,7 @@ function ConfirmationModal({
|
||||
<Text fontWeight={500} fontSize={20}>
|
||||
{title}
|
||||
</Text>
|
||||
<CloseIcon onClick={onDismiss}/>
|
||||
<CloseIcon onClick={onDismiss} />
|
||||
</RowBetween>
|
||||
{topContent()}
|
||||
</Section>
|
||||
@ -84,14 +84,14 @@ function ConfirmationModal({
|
||||
<Wrapper>
|
||||
<Section>
|
||||
<RowBetween>
|
||||
<div/>
|
||||
<CloseIcon onClick={onDismiss}/>
|
||||
<div />
|
||||
<CloseIcon onClick={onDismiss} />
|
||||
</RowBetween>
|
||||
<ConfirmedIcon>
|
||||
{pendingConfirmation ? (
|
||||
<Loader size="90px"/>
|
||||
<Loader size="90px" />
|
||||
) : (
|
||||
<ArrowUpCircle strokeWidth={0.5} size={90} color="#ff007a"/>
|
||||
<ArrowUpCircle strokeWidth={0.5} size={90} color="#ff007a" />
|
||||
)}
|
||||
</ConfirmedIcon>
|
||||
<AutoColumn gap="12px" justify={'center'}>
|
||||
|
@ -139,41 +139,41 @@ interface CurrencyInputPanelProps {
|
||||
onUserInput: (field: number, val: string) => void
|
||||
onMax: () => void
|
||||
atMax: boolean
|
||||
label?: string,
|
||||
label?: string
|
||||
urlAddedTokens?: Token[]
|
||||
onTokenSelection?: (tokenAddress: string) => void
|
||||
token?: Token | null,
|
||||
disableTokenSelect?: boolean,
|
||||
hideBalance?: boolean,
|
||||
isExchange?: boolean,
|
||||
pair?: Pair | null,
|
||||
hideInput?: boolean,
|
||||
showSendWithSwap?: boolean,
|
||||
otherSelectedTokenAddress?: string | null,
|
||||
advanced?: boolean,
|
||||
token?: Token | null
|
||||
disableTokenSelect?: boolean
|
||||
hideBalance?: boolean
|
||||
isExchange?: boolean
|
||||
pair?: Pair | null
|
||||
hideInput?: boolean
|
||||
showSendWithSwap?: boolean
|
||||
otherSelectedTokenAddress?: string | null
|
||||
advanced?: boolean
|
||||
inputId: string
|
||||
}
|
||||
|
||||
export default function CurrencyInputPanel({
|
||||
value,
|
||||
field,
|
||||
onUserInput,
|
||||
onMax,
|
||||
atMax,
|
||||
label = 'Input',
|
||||
urlAddedTokens = [], // used
|
||||
onTokenSelection = null,
|
||||
token = null,
|
||||
disableTokenSelect = false,
|
||||
hideBalance = false,
|
||||
isExchange = false,
|
||||
pair = null, // used for double token logo
|
||||
hideInput = false,
|
||||
showSendWithSwap = false,
|
||||
otherSelectedTokenAddress = null,
|
||||
advanced = false,
|
||||
inputId,
|
||||
}: CurrencyInputPanelProps) {
|
||||
value,
|
||||
field,
|
||||
onUserInput,
|
||||
onMax,
|
||||
atMax,
|
||||
label = 'Input',
|
||||
urlAddedTokens = [], // used
|
||||
onTokenSelection = null,
|
||||
token = null,
|
||||
disableTokenSelect = false,
|
||||
hideBalance = false,
|
||||
isExchange = false,
|
||||
pair = null, // used for double token logo
|
||||
hideInput = false,
|
||||
showSendWithSwap = false,
|
||||
otherSelectedTokenAddress = null,
|
||||
advanced = false,
|
||||
inputId
|
||||
}: CurrencyInputPanelProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const [modalOpen, setModalOpen] = useState(false)
|
||||
@ -207,10 +207,7 @@ export default function CurrencyInputPanel({
|
||||
</RowBetween>
|
||||
</LabelRow>
|
||||
)}
|
||||
<InputRow
|
||||
style={hideInput ? { padding: '0', borderRadius: '8px' } : {}}
|
||||
selected={disableTokenSelect}
|
||||
>
|
||||
<InputRow style={hideInput ? { padding: '0', borderRadius: '8px' } : {}} selected={disableTokenSelect}>
|
||||
{!hideInput && (
|
||||
<>
|
||||
<NumericalInput
|
||||
@ -235,9 +232,9 @@ export default function CurrencyInputPanel({
|
||||
>
|
||||
<Aligner>
|
||||
{isExchange ? (
|
||||
<DoubleLogo a0={pair?.token0.address} a1={pair?.token1.address} size={24} margin={true}/>
|
||||
<DoubleLogo a0={pair?.token0.address} a1={pair?.token1.address} size={24} margin={true} />
|
||||
) : token?.address ? (
|
||||
<TokenLogo address={token?.address} size={'24px'}/>
|
||||
<TokenLogo address={token?.address} size={'24px'} />
|
||||
) : null}
|
||||
{isExchange ? (
|
||||
<StyledTokenName>
|
||||
@ -248,7 +245,7 @@ export default function CurrencyInputPanel({
|
||||
{(token && token.symbol) || t('selectToken')}
|
||||
</StyledTokenName>
|
||||
)}
|
||||
{!disableTokenSelect && <StyledDropDown selected={!!token?.address}/>}
|
||||
{!disableTokenSelect && <StyledDropDown selected={!!token?.address} />}
|
||||
</Aligner>
|
||||
</CurrencySelect>
|
||||
</InputRow>
|
||||
|
@ -3,11 +3,11 @@ import styled from 'styled-components'
|
||||
import TokenLogo from '../TokenLogo'
|
||||
|
||||
const TokenWrapper = styled.div<{ margin: boolean; sizeraw: number }>`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-right: ${({ sizeraw, margin }) => margin && (sizeraw / 3 + 8).toString() + 'px'};
|
||||
`
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-right: ${({ sizeraw, margin }) => margin && (sizeraw / 3 + 8).toString() + 'px'};
|
||||
`
|
||||
|
||||
interface DoubleTokenLogoProps {
|
||||
margin?: boolean
|
||||
@ -17,18 +17,18 @@ interface DoubleTokenLogoProps {
|
||||
}
|
||||
|
||||
const HigherLogo = styled(TokenLogo)`
|
||||
z-index: 2;
|
||||
`
|
||||
z-index: 2;
|
||||
`
|
||||
const CoveredLogo = styled(TokenLogo)<{ sizeraw: number }>`
|
||||
position: absolute;
|
||||
left: ${({ sizeraw }) => (sizeraw / 2).toString() + 'px'};
|
||||
`
|
||||
position: absolute;
|
||||
left: ${({ sizeraw }) => (sizeraw / 2).toString() + 'px'};
|
||||
`
|
||||
|
||||
export default function DoubleTokenLogo({ a0, a1, size = 16, margin = false }: DoubleTokenLogoProps) {
|
||||
return (
|
||||
<TokenWrapper sizeraw={size} margin={margin}>
|
||||
<HigherLogo address={a0} size={size.toString() + 'px'}/>
|
||||
<CoveredLogo address={a1} size={size.toString() + 'px'} sizeraw={size}/>
|
||||
<HigherLogo address={a0} size={size.toString() + 'px'} />
|
||||
<CoveredLogo address={a1} size={size.toString() + 'px'} sizeraw={size} />
|
||||
</TokenWrapper>
|
||||
)
|
||||
}
|
||||
|
@ -178,14 +178,22 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
}
|
||||
|
||||
const pair = usePair(tokens[Field.INPUT], tokens[Field.OUTPUT])
|
||||
let bestTradeExactIn = useTradeExactIn(tradeType === TradeType.EXACT_INPUT ? parsedAmounts[independentField] : null, tokens[Field.OUTPUT])
|
||||
let bestTradeExactOut = useTradeExactOut(tokens[Field.INPUT], tradeType === TradeType.EXACT_OUTPUT ? parsedAmounts[independentField] : null)
|
||||
const bestTradeExactIn = useTradeExactIn(
|
||||
tradeType === TradeType.EXACT_INPUT ? parsedAmounts[independentField] : null,
|
||||
tokens[Field.OUTPUT]
|
||||
)
|
||||
const bestTradeExactOut = useTradeExactOut(
|
||||
tokens[Field.INPUT],
|
||||
tradeType === TradeType.EXACT_OUTPUT ? parsedAmounts[independentField] : null
|
||||
)
|
||||
|
||||
const trade = tradeType === TradeType.EXACT_INPUT ? bestTradeExactIn : bestTradeExactOut
|
||||
const route = trade?.route
|
||||
const userHasSpecifiedInputOutput = !!parsedAmounts[independentField] &&
|
||||
const userHasSpecifiedInputOutput =
|
||||
!!parsedAmounts[independentField] &&
|
||||
parsedAmounts[independentField].greaterThan(JSBI.BigInt(0)) &&
|
||||
!!tokens[Field.INPUT] && !!tokens[Field.OUTPUT]
|
||||
!!tokens[Field.INPUT] &&
|
||||
!!tokens[Field.OUTPUT]
|
||||
const noRoute = !route
|
||||
|
||||
const slippageFromTrade: Percent = trade && trade.slippage
|
||||
@ -213,12 +221,15 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
JSBI.multiply(slippageFromTrade.denominator, JSBI.BigInt('1000'))
|
||||
)
|
||||
|
||||
const onTokenSelection = useCallback((field: Field, address: string) => {
|
||||
dispatch({
|
||||
type: SwapAction.SELECT_TOKEN,
|
||||
payload: { field, address }
|
||||
})
|
||||
}, [dispatch])
|
||||
const onTokenSelection = useCallback(
|
||||
(field: Field, address: string) => {
|
||||
dispatch({
|
||||
type: SwapAction.SELECT_TOKEN,
|
||||
payload: { field, address }
|
||||
})
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const onSwapTokens = useCallback(() => {
|
||||
dispatch({
|
||||
@ -227,29 +238,38 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
})
|
||||
}, [dispatch])
|
||||
|
||||
const onUserInput = useCallback((field: Field, typedValue: string) => {
|
||||
dispatch({ type: SwapAction.TYPE, payload: { field, typedValue } })
|
||||
}, [dispatch])
|
||||
const onUserInput = useCallback(
|
||||
(field: Field, typedValue: string) => {
|
||||
dispatch({ type: SwapAction.TYPE, payload: { field, typedValue } })
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const onMaxInput = useCallback((typedValue: string) => {
|
||||
dispatch({
|
||||
type: SwapAction.TYPE,
|
||||
payload: {
|
||||
field: Field.INPUT,
|
||||
typedValue
|
||||
}
|
||||
})
|
||||
}, [dispatch])
|
||||
const onMaxInput = useCallback(
|
||||
(typedValue: string) => {
|
||||
dispatch({
|
||||
type: SwapAction.TYPE,
|
||||
payload: {
|
||||
field: Field.INPUT,
|
||||
typedValue
|
||||
}
|
||||
})
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const onMaxOutput = useCallback((typedValue: string) => {
|
||||
dispatch({
|
||||
type: SwapAction.TYPE,
|
||||
payload: {
|
||||
field: Field.OUTPUT,
|
||||
typedValue
|
||||
}
|
||||
})
|
||||
}, [dispatch])
|
||||
const onMaxOutput = useCallback(
|
||||
(typedValue: string) => {
|
||||
dispatch({
|
||||
type: SwapAction.TYPE,
|
||||
payload: {
|
||||
field: Field.OUTPUT,
|
||||
typedValue
|
||||
}
|
||||
})
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
// reset field if sending with with swap is cancled
|
||||
useEffect(() => {
|
||||
@ -269,11 +289,10 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
WETH[chainId] &&
|
||||
JSBI.greaterThan(userBalances[Field.INPUT].raw, isWETH(tokens[Field.INPUT]) ? MIN_ETHER.raw : JSBI.BigInt(0))
|
||||
? isWETH(tokens[Field.INPUT])
|
||||
? userBalances[Field.INPUT].subtract(MIN_ETHER)
|
||||
: userBalances[Field.INPUT]
|
||||
? userBalances[Field.INPUT].subtract(MIN_ETHER)
|
||||
: userBalances[Field.INPUT]
|
||||
: undefined
|
||||
} catch {
|
||||
}
|
||||
} catch {}
|
||||
|
||||
const atMaxAmountInput: boolean =
|
||||
!!maxAmountInput && !!parsedAmounts[Field.INPUT]
|
||||
@ -323,17 +342,28 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
Field.INPUT === independentField
|
||||
? parsedAmounts[Field.INPUT]
|
||||
: calculateSlippageAmount(parsedAmounts[Field.INPUT])?.[0] &&
|
||||
new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.INPUT])?.[1]),
|
||||
new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.INPUT])?.[1]),
|
||||
[Field.OUTPUT]:
|
||||
Field.OUTPUT === independentField
|
||||
? parsedAmounts[Field.OUTPUT]
|
||||
: calculateSlippageAmount(parsedAmounts[Field.OUTPUT])?.[0] &&
|
||||
new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.OUTPUT])?.[0])
|
||||
new TokenAmount(tokens[Field.INPUT], calculateSlippageAmount(parsedAmounts[Field.OUTPUT])?.[0])
|
||||
}
|
||||
|
||||
const showInputApprove: boolean =
|
||||
parsedAmounts[Field.INPUT] && inputApproval && JSBI.greaterThan(parsedAmounts[Field.INPUT].raw, inputApproval.raw)
|
||||
|
||||
// reset modal state when closed
|
||||
function resetModal() {
|
||||
// clear input if txn submitted
|
||||
if (!pendingConfirmation) {
|
||||
onUserInput(Field.INPUT, '')
|
||||
}
|
||||
setPendingConfirmation(true)
|
||||
setAttemptingTxn(false)
|
||||
setShowAdvanced(false)
|
||||
}
|
||||
|
||||
// function for a pure send
|
||||
async function onSend() {
|
||||
setAttemptingTxn(true)
|
||||
@ -349,11 +379,11 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
addTransaction(
|
||||
response,
|
||||
'Send ' +
|
||||
parsedAmounts[Field.INPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' to ' +
|
||||
recipient
|
||||
parsedAmounts[Field.INPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' to ' +
|
||||
recipient
|
||||
)
|
||||
setPendingConfirmation(false)
|
||||
})
|
||||
@ -376,11 +406,11 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
addTransaction(
|
||||
response,
|
||||
'Send ' +
|
||||
parsedAmounts[Field.INPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' to ' +
|
||||
recipient
|
||||
parsedAmounts[Field.INPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' to ' +
|
||||
recipient
|
||||
)
|
||||
setPendingConfirmation(false)
|
||||
})
|
||||
@ -487,13 +517,13 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
addTransaction(
|
||||
response,
|
||||
'Swap ' +
|
||||
slippageAdjustedAmounts?.[Field.INPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' for ' +
|
||||
slippageAdjustedAmounts?.[Field.OUTPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.OUTPUT]?.symbol
|
||||
slippageAdjustedAmounts?.[Field.INPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' for ' +
|
||||
slippageAdjustedAmounts?.[Field.OUTPUT]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.OUTPUT]?.symbol
|
||||
)
|
||||
setPendingConfirmation(false)
|
||||
})
|
||||
@ -625,17 +655,6 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
const warningHigh: boolean =
|
||||
slippageFromTrade && parseFloat(slippageFromTrade.toFixed(4)) > ALLOWED_SLIPPAGE_HIGH / 100
|
||||
|
||||
// reset modal state when closed
|
||||
function resetModal() {
|
||||
// clear input if txn submitted
|
||||
if (!pendingConfirmation) {
|
||||
onUserInput(Field.INPUT, '')
|
||||
}
|
||||
setPendingConfirmation(true)
|
||||
setAttemptingTxn(false)
|
||||
setShowAdvanced(false)
|
||||
}
|
||||
|
||||
function modalHeader() {
|
||||
if (sending && !sendingWithSwap) {
|
||||
return (
|
||||
@ -644,7 +663,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<Text fontSize={36} fontWeight={500}>
|
||||
{parsedAmounts[Field.INPUT]?.toSignificant(6)} {tokens[Field.INPUT]?.symbol}
|
||||
</Text>
|
||||
<TokenLogo address={tokens[Field.INPUT]?.address} size={'30px'}/>
|
||||
<TokenLogo address={tokens[Field.INPUT]?.address} size={'30px'} />
|
||||
</RowBetween>
|
||||
<TYPE.darkGray fontSize={20}>To</TYPE.darkGray>
|
||||
{ENS ? (
|
||||
@ -656,7 +675,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
{recipient?.slice(0, 8)}...{recipient?.slice(34, 42)}↗
|
||||
</TYPE.blue>
|
||||
</Link>
|
||||
<Copy toCopy={recipient}/>
|
||||
<Copy toCopy={recipient} />
|
||||
</AutoRow>
|
||||
</AutoColumn>
|
||||
) : (
|
||||
@ -666,7 +685,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
{recipient?.slice(0, 6)}...{recipient?.slice(36, 42)}↗
|
||||
</TYPE.blue>
|
||||
</Link>
|
||||
<Copy toCopy={recipient}/>
|
||||
<Copy toCopy={recipient} />
|
||||
</AutoRow>
|
||||
)}
|
||||
</AutoColumn>
|
||||
@ -678,7 +697,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<AutoColumn gap="lg" style={{ marginTop: '40px' }}>
|
||||
<AutoColumn gap="sm">
|
||||
<AutoRow gap="10px">
|
||||
<TokenLogo address={tokens[Field.OUTPUT]?.address} size={'30px'}/>
|
||||
<TokenLogo address={tokens[Field.OUTPUT]?.address} size={'30px'} />
|
||||
<Text fontSize={36} fontWeight={500}>
|
||||
{slippageAdjustedAmounts[Field.OUTPUT]?.toSignificant(4)} {tokens[Field.OUTPUT]?.symbol}
|
||||
</Text>
|
||||
@ -706,14 +725,14 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
{/* {!!slippageAdjustedAmounts[Field.INPUT] && slippageAdjustedAmounts[Field.INPUT].toSignificant(6)} */}
|
||||
</TruncatedText>
|
||||
<RowFixed gap="4px">
|
||||
<TokenLogo address={tokens[Field.INPUT]?.address} size={'24px'}/>
|
||||
<TokenLogo address={tokens[Field.INPUT]?.address} size={'24px'} />
|
||||
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
|
||||
{tokens[Field.INPUT]?.symbol || ''}
|
||||
</Text>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowFixed>
|
||||
<ArrowDown size="16" color={theme(isDark).text2}/>
|
||||
<ArrowDown size="16" color={theme(isDark).text2} />
|
||||
</RowFixed>
|
||||
<RowBetween align="flex-end">
|
||||
<TruncatedText fontSize={24} fontWeight={500} color={warningHigh ? theme(isDark).red1 : ''}>
|
||||
@ -722,7 +741,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
{/* {!!slippageAdjustedAmounts[Field.OUTPUT] && slippageAdjustedAmounts[Field.OUTPUT].toSignificant(6)} */}
|
||||
</TruncatedText>
|
||||
<RowFixed gap="4px">
|
||||
<TokenLogo address={tokens[Field.OUTPUT]?.address} size={'24px'}/>
|
||||
<TokenLogo address={tokens[Field.OUTPUT]?.address} size={'24px'} />
|
||||
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
|
||||
{tokens[Field.OUTPUT]?.symbol || ''}
|
||||
</Text>
|
||||
@ -782,17 +801,17 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
>
|
||||
{trade && showInverted
|
||||
? (trade?.executionPrice?.invert()?.toSignificant(6) ?? '') +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' / ' +
|
||||
tokens[Field.OUTPUT]?.symbol
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' / ' +
|
||||
tokens[Field.OUTPUT]?.symbol
|
||||
: (trade?.executionPrice?.toSignificant(6) ?? '') +
|
||||
' ' +
|
||||
tokens[Field.OUTPUT]?.symbol +
|
||||
' / ' +
|
||||
tokens[Field.INPUT]?.symbol}
|
||||
' ' +
|
||||
tokens[Field.OUTPUT]?.symbol +
|
||||
' / ' +
|
||||
tokens[Field.INPUT]?.symbol}
|
||||
<StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}>
|
||||
<Repeat size={14}/>
|
||||
<Repeat size={14} />
|
||||
</StyledBalanceMaxMini>
|
||||
</Text>
|
||||
</RowBetween>
|
||||
@ -802,8 +821,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<TYPE.black fontSize={14} fontWeight={400}>
|
||||
{independentField === Field.INPUT ? (sending ? 'Min sent' : 'Minimum received') : 'Maximum sold'}
|
||||
</TYPE.black>
|
||||
<QuestionHelper
|
||||
text="A boundary is set so you are protected from large price movements after you submit your trade."/>
|
||||
<QuestionHelper text="A boundary is set so you are protected from large price movements after you submit your trade." />
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
<TYPE.black fontSize={14}>
|
||||
@ -814,10 +832,10 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
: slippageAdjustedAmounts[Field.OUTPUT]?.toFixed(5)
|
||||
: '-'
|
||||
: slippageAdjustedAmounts[Field.INPUT]
|
||||
? slippageAdjustedAmounts[Field.INPUT]?.toFixed(5) === '0.00000'
|
||||
? '<0.00001'
|
||||
: slippageAdjustedAmounts[Field.INPUT]?.toFixed(5)
|
||||
: '-'}
|
||||
? slippageAdjustedAmounts[Field.INPUT]?.toFixed(5) === '0.00000'
|
||||
? '<0.00001'
|
||||
: slippageAdjustedAmounts[Field.INPUT]?.toFixed(5)
|
||||
: '-'}
|
||||
</TYPE.black>
|
||||
{parsedAmounts[Field.OUTPUT] && parsedAmounts[Field.INPUT] && (
|
||||
<TYPE.black fontSize={14} marginLeft={'4px'}>
|
||||
@ -833,7 +851,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<TYPE.black color={theme(isDark).text1} fontSize={14} fontWeight={400}>
|
||||
Price impact
|
||||
</TYPE.black>
|
||||
<QuestionHelper text="The difference between the market price and your price due to trade size."/>
|
||||
<QuestionHelper text="The difference between the market price and your price due to trade size." />
|
||||
</RowFixed>
|
||||
<ErrorText
|
||||
fontWeight={500}
|
||||
@ -854,8 +872,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<TYPE.black fontSize={14} fontWeight={400}>
|
||||
Liquidity Provider Fee
|
||||
</TYPE.black>
|
||||
<QuestionHelper
|
||||
text="A portion of each trade (0.3%) goes to liquidity providers to incentivize liquidity on the protocol."/>
|
||||
<QuestionHelper text="A portion of each trade (0.3%) goes to liquidity providers to incentivize liquidity on the protocol." />
|
||||
</RowFixed>
|
||||
<TYPE.black fontSize={14}>
|
||||
{feeTimesInputFormatted
|
||||
@ -877,7 +894,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
}
|
||||
}
|
||||
|
||||
const PriceBar = function () {
|
||||
const PriceBar = function() {
|
||||
return (
|
||||
<AutoRow justify="space-between">
|
||||
<AutoColumn justify="center">
|
||||
@ -924,7 +941,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
? `Sending ${parsedAmounts[Field.OUTPUT]?.toSignificant(6)} ${tokens[Field.OUTPUT]?.symbol} to ${recipient}`
|
||||
: `Sending ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${tokens[Field.INPUT]?.symbol} to ${recipient}`
|
||||
: ` Swapping ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${tokens[Field.INPUT]?.symbol} for ${parsedAmounts[
|
||||
Field.OUTPUT
|
||||
Field.OUTPUT
|
||||
]?.toSignificant(6)} ${tokens[Field.OUTPUT]?.symbol}`
|
||||
|
||||
function _onTokenSelect(address: string) {
|
||||
@ -979,7 +996,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
Max
|
||||
</MaxButton>
|
||||
)}
|
||||
<StyledNumerical value={formattedAmounts[Field.INPUT]} onUserInput={val => onUserInput(Field.INPUT, val)}/>
|
||||
<StyledNumerical value={formattedAmounts[Field.INPUT]} onUserInput={val => onUserInput(Field.INPUT, val)} />
|
||||
<CurrencyInputPanel
|
||||
field={Field.INPUT}
|
||||
value={formattedAmounts[Field.INPUT]}
|
||||
@ -1025,7 +1042,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<ColumnCenter>
|
||||
<RowBetween padding="0 12px">
|
||||
<ArrowWrapper onClick={onSwapTokens}>
|
||||
<ArrowDown size="16" color={theme(isDark).text2} onClick={onSwapTokens}/>
|
||||
<ArrowDown size="16" color={theme(isDark).text2} onClick={onSwapTokens} />
|
||||
</ArrowWrapper>
|
||||
<StyledBalanceMaxMini onClick={() => setSendingWithSwap(false)} style={{ marginRight: '0px' }}>
|
||||
<TYPE.blue>Remove Swap</TYPE.blue>
|
||||
@ -1063,7 +1080,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
/>
|
||||
{sendingWithSwap && (
|
||||
<RowBetween padding="0 12px">
|
||||
<ArrowDown size="16"/>
|
||||
<ArrowDown size="16" />
|
||||
</RowBetween>
|
||||
)}
|
||||
</>
|
||||
@ -1095,7 +1112,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
{!noRoute && tokens[Field.OUTPUT] && tokens[Field.INPUT] && (
|
||||
<Card padding={advanced ? '.25rem 1.25rem 0 .75rem' : '.25rem .7rem .25rem 1.25rem'} borderRadius={'20px'}>
|
||||
{advanced ? (
|
||||
<PriceBar/>
|
||||
<PriceBar />
|
||||
) : (
|
||||
<AutoColumn gap="4px">
|
||||
{' '}
|
||||
@ -1111,17 +1128,17 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
>
|
||||
{trade && showInverted
|
||||
? (trade?.executionPrice?.invert()?.toSignificant(6) ?? '') +
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' per ' +
|
||||
tokens[Field.OUTPUT]?.symbol
|
||||
' ' +
|
||||
tokens[Field.INPUT]?.symbol +
|
||||
' per ' +
|
||||
tokens[Field.OUTPUT]?.symbol
|
||||
: (trade?.executionPrice?.toSignificant(6) ?? '') +
|
||||
' ' +
|
||||
tokens[Field.OUTPUT]?.symbol +
|
||||
' per ' +
|
||||
tokens[Field.INPUT]?.symbol}
|
||||
' ' +
|
||||
tokens[Field.OUTPUT]?.symbol +
|
||||
' per ' +
|
||||
tokens[Field.INPUT]?.symbol}
|
||||
<StyledBalanceMaxMini onClick={() => setShowInverted(!showInverted)}>
|
||||
<Repeat size={14}/>
|
||||
<Repeat size={14} />
|
||||
</StyledBalanceMaxMini>
|
||||
</Text>
|
||||
</RowBetween>
|
||||
@ -1141,8 +1158,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
: priceSlippage.toFixed(4) + '%'
|
||||
: '-'}{' '}
|
||||
</ErrorText>
|
||||
<QuestionHelper
|
||||
text="The difference between the market price and your quoted price due to trade size."/>
|
||||
<QuestionHelper text="The difference between the market price and your quoted price due to trade size." />
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
)}
|
||||
@ -1189,9 +1205,12 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<Text fontSize={20} fontWeight={500}>
|
||||
{!account
|
||||
? 'Connect Wallet'
|
||||
: (generalError || inputError || outputError || recipientError || tradeError) ||
|
||||
(`${sending ? 'Send' : 'Swap'}${warningHigh ? ' Anyway' : ''}`)
|
||||
}
|
||||
: generalError ||
|
||||
inputError ||
|
||||
outputError ||
|
||||
recipientError ||
|
||||
tradeError ||
|
||||
`${sending ? 'Send' : 'Swap'}${warningHigh ? ' Anyway' : ''}`}
|
||||
</Text>
|
||||
</ButtonError>
|
||||
)}
|
||||
@ -1204,7 +1223,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<Text fontSize={16} fontWeight={500} style={{ userSelect: 'none' }}>
|
||||
Show Advanced
|
||||
</Text>
|
||||
<ChevronDown color={theme(isDark).text2}/>
|
||||
<ChevronDown color={theme(isDark).text2} />
|
||||
</RowBetween>
|
||||
</Hover>
|
||||
)}
|
||||
@ -1215,10 +1234,10 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<Text fontSize={16} color={theme(isDark).text2} fontWeight={500} style={{ userSelect: 'none' }}>
|
||||
Hide Advanced
|
||||
</Text>
|
||||
<ChevronUp color={theme(isDark).text2}/>
|
||||
<ChevronUp color={theme(isDark).text2} />
|
||||
</RowBetween>
|
||||
</Hover>
|
||||
<SectionBreak/>
|
||||
<SectionBreak />
|
||||
<AutoColumn style={{ padding: '0 20px' }}>
|
||||
<RowBetween>
|
||||
<RowFixed>
|
||||
@ -1233,8 +1252,8 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
text={
|
||||
independentField === Field.INPUT
|
||||
? sending
|
||||
? 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will send. A worse rate will cause your transaction to revert.'
|
||||
: 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will receive. A worse rate will cause your transaction to revert.'
|
||||
? 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will send. A worse rate will cause your transaction to revert.'
|
||||
: 'Price can change between when a transaction is submitted and when it is executed. This is the minimum amount you will receive. A worse rate will cause your transaction to revert.'
|
||||
: 'Price can change between when a transaction is submitted and when it is executed. This is the maximum amount you will pay. A worse rate will cause your transaction to revert.'
|
||||
}
|
||||
/>
|
||||
@ -1244,18 +1263,18 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
{independentField === Field.INPUT
|
||||
? slippageAdjustedAmounts[Field.OUTPUT]
|
||||
? slippageAdjustedAmounts[Field.OUTPUT]?.lessThan(
|
||||
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10000))
|
||||
)
|
||||
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10000))
|
||||
)
|
||||
? '<0.00001'
|
||||
: slippageAdjustedAmounts[Field.OUTPUT]?.toFixed(5)
|
||||
: '-'
|
||||
: slippageAdjustedAmounts[Field.INPUT]
|
||||
? slippageAdjustedAmounts[Field.INPUT]?.lessThan(
|
||||
? slippageAdjustedAmounts[Field.INPUT]?.lessThan(
|
||||
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10000))
|
||||
)
|
||||
? '<0.00001'
|
||||
: slippageAdjustedAmounts[Field.INPUT]?.toFixed(5)
|
||||
: '-'}
|
||||
? '<0.00001'
|
||||
: slippageAdjustedAmounts[Field.INPUT]?.toFixed(5)
|
||||
: '-'}
|
||||
</TYPE.black>
|
||||
{parsedAmounts[Field.OUTPUT] && parsedAmounts[Field.INPUT] && (
|
||||
<TYPE.black fontSize={14} marginLeft={'4px'} color={theme(isDark).text1}>
|
||||
@ -1271,8 +1290,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}>
|
||||
Price Impact
|
||||
</TYPE.black>
|
||||
<QuestionHelper
|
||||
text="The difference between the market price and your quoted price due to trade size."/>
|
||||
<QuestionHelper text="The difference between the market price and your quoted price due to trade size." />
|
||||
</RowFixed>
|
||||
<ErrorText
|
||||
fontWeight={500}
|
||||
@ -1293,8 +1311,7 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
<TYPE.black fontSize={14} fontWeight={400} color={theme(isDark).text1}>
|
||||
Liquidity Provider Fee
|
||||
</TYPE.black>
|
||||
<QuestionHelper
|
||||
text="A portion of each trade (0.03%) goes to liquidity providers to incentivize liquidity on the protocol."/>
|
||||
<QuestionHelper text="A portion of each trade (0.03%) goes to liquidity providers to incentivize liquidity on the protocol." />
|
||||
</RowFixed>
|
||||
<TYPE.black fontSize={14} color={theme(isDark).text1}>
|
||||
{feeTimesInputFormatted
|
||||
@ -1303,13 +1320,12 @@ function ExchangePage({ sendingInput = false, history, params }: ExchangePagePro
|
||||
</TYPE.black>
|
||||
</RowBetween>
|
||||
</AutoColumn>
|
||||
<SectionBreak/>
|
||||
<SectionBreak />
|
||||
<RowFixed padding={'0 20px'}>
|
||||
<TYPE.black fontWeight={400} fontSize={14} color={theme(isDark).text1}>
|
||||
Set front running resistance
|
||||
</TYPE.black>
|
||||
<QuestionHelper
|
||||
text="Your transaction will revert if the price changes more than this amount after you submit your trade."/>
|
||||
<QuestionHelper text="Your transaction will revert if the price changes more than this amount after you submit your trade." />
|
||||
</RowFixed>
|
||||
<SlippageTabs
|
||||
rawSlippage={allowedSlippage}
|
||||
|
@ -57,7 +57,7 @@ export const BottomGrouping = styled.div`
|
||||
|
||||
export const ErrorText = styled(Text)`
|
||||
color: ${({ theme, warningLow, warningMedium, warningHigh }) =>
|
||||
warningHigh ? theme.red1 : warningMedium ? theme.yellow2 : warningLow ? theme.green1 : theme.text1};
|
||||
warningHigh ? theme.red1 : warningMedium ? theme.yellow2 : warningLow ? theme.green1 : theme.text1};
|
||||
`
|
||||
|
||||
export const InputGroup = styled(AutoColumn)`
|
||||
@ -152,4 +152,4 @@ export const Dots = styled.span`
|
||||
content: '...';
|
||||
}
|
||||
}
|
||||
`
|
||||
`
|
||||
|
@ -19,7 +19,12 @@ export interface SwapState {
|
||||
}
|
||||
}
|
||||
|
||||
export function initializeSwapState({ inputTokenAddress, outputTokenAddress, typedValue, independentField }): SwapState {
|
||||
export function initializeSwapState({
|
||||
inputTokenAddress,
|
||||
outputTokenAddress,
|
||||
typedValue,
|
||||
independentField
|
||||
}): SwapState {
|
||||
return {
|
||||
independentField: independentField,
|
||||
typedValue: typedValue,
|
||||
@ -110,21 +115,21 @@ export function useSwapStateReducer(params: QueryParams) {
|
||||
typedValue:
|
||||
params.inputTokenAddress && !params.outputTokenAddress
|
||||
? params.inputTokenAmount
|
||||
? params.inputTokenAmount
|
||||
: ''
|
||||
? params.inputTokenAmount
|
||||
: ''
|
||||
: !params.inputTokenAddress && params.outputTokenAddress
|
||||
? params.outputTokenAmount
|
||||
? params.outputTokenAmount
|
||||
: ''
|
||||
: params.inputTokenAddress && params.outputTokenAddress
|
||||
? params.inputTokenAmount
|
||||
? params.inputTokenAmount
|
||||
? params.inputTokenAmount
|
||||
: ''
|
||||
: ''
|
||||
? ''
|
||||
: ''
|
||||
? ''
|
||||
: ''
|
||||
: ''
|
||||
? ''
|
||||
: ''
|
||||
? ''
|
||||
: ''
|
||||
},
|
||||
initializeSwapState
|
||||
)
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
|
||||
import Row from '../Row'
|
||||
import Menu from '../Menu'
|
||||
@ -64,7 +63,7 @@ const TitleText = styled(Row)`
|
||||
`};
|
||||
`
|
||||
|
||||
const AccountElement = styled.div<{active: boolean;}>`
|
||||
const AccountElement = styled.div<{ active: boolean }>`
|
||||
display: flex;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@ -107,7 +106,7 @@ const Alpha = styled(GreyCard)`
|
||||
font-weight: 600;
|
||||
`
|
||||
|
||||
const UniIcon = styled.div<{href: string}>`
|
||||
const UniIcon = styled.div<{ href: string }>`
|
||||
transition: transform 0.3s ease;
|
||||
:hover {
|
||||
transform: rotate(-5deg);
|
||||
@ -133,7 +132,7 @@ const MigrateBanner = styled(AutoColumn)`
|
||||
`};
|
||||
`
|
||||
|
||||
function Header({ history }) {
|
||||
export default function Header() {
|
||||
const { account, chainId } = useWeb3React()
|
||||
|
||||
const userEthBalance = useAddressBalance(account, WETH[chainId])
|
||||
@ -196,5 +195,3 @@ function Header({ history }) {
|
||||
</HeaderFrame>
|
||||
)
|
||||
}
|
||||
|
||||
export default withRouter(Header)
|
||||
|
@ -24,5 +24,5 @@ export default function Identicon() {
|
||||
}
|
||||
}, [account])
|
||||
|
||||
return <StyledIdenticon ref={ref}/>
|
||||
return <StyledIdenticon ref={ref} />
|
||||
}
|
||||
|
@ -11,5 +11,5 @@ const SpinnerWrapper = styled(Spinner)<{ size: string }>`
|
||||
`
|
||||
|
||||
export default function Loader({ size }: { size: string }) {
|
||||
return <SpinnerWrapper src={Circle} alt="loader" size={size}/>
|
||||
return <SpinnerWrapper src={Circle} alt="loader" size={size} />
|
||||
}
|
||||
|
@ -78,9 +78,9 @@ const MenuItem = styled(Link)`
|
||||
}
|
||||
`
|
||||
|
||||
const CODE_LINK = !!process.env.REACT_APP_GIT_COMMIT_HASH ?
|
||||
`https://github.com/Uniswap/uniswap-frontend/tree/${process.env.REACT_APP_GIT_COMMIT_HASH}`:
|
||||
'https://github.com/Uniswap/uniswap-frontend'
|
||||
const CODE_LINK = !!process.env.REACT_APP_GIT_COMMIT_HASH
|
||||
? `https://github.com/Uniswap/uniswap-frontend/tree/${process.env.REACT_APP_GIT_COMMIT_HASH}`
|
||||
: 'https://github.com/Uniswap/uniswap-frontend'
|
||||
|
||||
export default function Menu() {
|
||||
const node = useRef<HTMLDivElement>()
|
||||
|
@ -22,8 +22,8 @@ const StyledDialogOverlay = styled(WrappedDialogOverlay).attrs({
|
||||
background-color: ${({ theme }) => 'transparent'};
|
||||
|
||||
${({ mobile }) =>
|
||||
mobile &&
|
||||
css`
|
||||
mobile &&
|
||||
css`
|
||||
align-items: flex-end;
|
||||
`}
|
||||
|
||||
@ -56,13 +56,13 @@ const StyledDialogContent = styled(FilteredDialogContent)`
|
||||
|
||||
max-width: 420px;
|
||||
${({ maxHeight }) =>
|
||||
maxHeight &&
|
||||
css`
|
||||
maxHeight &&
|
||||
css`
|
||||
max-height: ${maxHeight}vh;
|
||||
`}
|
||||
${({ minHeight }) =>
|
||||
minHeight &&
|
||||
css`
|
||||
minHeight &&
|
||||
css`
|
||||
min-height: ${minHeight}vh;
|
||||
`}
|
||||
display: flex;
|
||||
@ -77,7 +77,7 @@ const StyledDialogContent = styled(FilteredDialogContent)`
|
||||
width: 85vw;
|
||||
max-height: 66vh;
|
||||
${mobile &&
|
||||
css`
|
||||
css`
|
||||
width: 100vw;
|
||||
border-radius: 20px;
|
||||
border-bottom-left-radius: 0;
|
||||
@ -105,13 +105,13 @@ interface ModalProps {
|
||||
}
|
||||
|
||||
export default function Modal({
|
||||
isOpen,
|
||||
onDismiss,
|
||||
minHeight = false,
|
||||
maxHeight = 50,
|
||||
initialFocusRef = null,
|
||||
children
|
||||
}: ModalProps) {
|
||||
isOpen,
|
||||
onDismiss,
|
||||
minHeight = false,
|
||||
maxHeight = 50,
|
||||
initialFocusRef = null,
|
||||
children
|
||||
}: ModalProps) {
|
||||
const transitions = useTransition(isOpen, null, {
|
||||
config: { duration: 200 },
|
||||
from: { opacity: 0 },
|
||||
@ -163,7 +163,9 @@ export default function Modal({
|
||||
{props => (
|
||||
<animated.div
|
||||
{...bind()}
|
||||
style={{ transform: (xy as any).interpolate((x, y) => `translate3d(${0}px,${y > 0 ? y : 0}px,0)`) }}
|
||||
style={{
|
||||
transform: (xy as any).interpolate((x, y) => `translate3d(${0}px,${y > 0 ? y : 0}px,0)`)
|
||||
}}
|
||||
>
|
||||
<StyledDialogContent
|
||||
style={props}
|
||||
@ -172,7 +174,7 @@ export default function Modal({
|
||||
maxHeight={maxHeight}
|
||||
mobile={isMobile}
|
||||
>
|
||||
<HiddenCloseButton onClick={onDismiss}/>
|
||||
<HiddenCloseButton onClick={onDismiss} />
|
||||
{children}
|
||||
</StyledDialogContent>
|
||||
</animated.div>
|
||||
@ -203,7 +205,7 @@ export default function Modal({
|
||||
isOpen={isOpen}
|
||||
mobile={isMobile}
|
||||
>
|
||||
<HiddenCloseButton onClick={onDismiss}/>
|
||||
<HiddenCloseButton onClick={onDismiss} />
|
||||
{children}
|
||||
</StyledDialogContent>
|
||||
</StyledDialogOverlay>
|
||||
|
@ -1,15 +1,15 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { darken } from 'polished';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { withRouter, NavLink, Link as HistoryLink, RouteComponentProps } from 'react-router-dom';
|
||||
import React, { useCallback } from 'react'
|
||||
import styled from 'styled-components'
|
||||
import { darken } from 'polished'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { withRouter, NavLink, Link as HistoryLink, RouteComponentProps } from 'react-router-dom'
|
||||
|
||||
import { Hover } from '../../theme';
|
||||
import { ArrowLeft } from 'react-feather';
|
||||
import { RowBetween } from '../Row';
|
||||
import QuestionHelper from '../Question';
|
||||
import { Hover } from '../../theme'
|
||||
import { ArrowLeft } from 'react-feather'
|
||||
import { RowBetween } from '../Row'
|
||||
import QuestionHelper from '../Question'
|
||||
|
||||
import { useBodyKeyDown } from '../../hooks';
|
||||
import { useBodyKeyDown } from '../../hooks'
|
||||
|
||||
const tabOrder = [
|
||||
{
|
||||
@ -27,16 +27,16 @@ const tabOrder = [
|
||||
textKey: 'pool',
|
||||
regex: /\/pool/
|
||||
}
|
||||
];
|
||||
]
|
||||
|
||||
const Tabs = styled.div`
|
||||
${({ theme }) => theme.flexRowNoWrap}
|
||||
align-items: center;
|
||||
border-radius: 3rem;
|
||||
margin-bottom: 20px;
|
||||
`;
|
||||
`
|
||||
|
||||
const activeClassName = 'ACTIVE';
|
||||
const activeClassName = 'ACTIVE'
|
||||
|
||||
const StyledNavLink = styled(NavLink).attrs({
|
||||
activeClassName
|
||||
@ -65,41 +65,41 @@ const StyledNavLink = styled(NavLink).attrs({
|
||||
:focus {
|
||||
color: ${({ theme }) => darken(0.1, theme.text1)};
|
||||
}
|
||||
`;
|
||||
`
|
||||
|
||||
const ActiveText = styled.div`
|
||||
font-weight: 500;
|
||||
font-size: 20px;
|
||||
`;
|
||||
`
|
||||
|
||||
const ArrowLink = styled(ArrowLeft)`
|
||||
color: ${({ theme }) => theme.text1};
|
||||
`;
|
||||
`
|
||||
|
||||
function NavigationTabs({ location: { pathname }, history }: RouteComponentProps<{}>) {
|
||||
const { t } = useTranslation();
|
||||
const { t } = useTranslation()
|
||||
|
||||
const navigate = useCallback(
|
||||
direction => {
|
||||
const tabIndex = tabOrder.findIndex(({ regex }) => pathname.match(regex));
|
||||
history.push(tabOrder[ (tabIndex + tabOrder.length + direction) % tabOrder.length ].path);
|
||||
const tabIndex = tabOrder.findIndex(({ regex }) => pathname.match(regex))
|
||||
history.push(tabOrder[(tabIndex + tabOrder.length + direction) % tabOrder.length].path)
|
||||
},
|
||||
[pathname, history]
|
||||
);
|
||||
)
|
||||
const navigateRight = useCallback(() => {
|
||||
navigate(1);
|
||||
}, [navigate]);
|
||||
navigate(1)
|
||||
}, [navigate])
|
||||
const navigateLeft = useCallback(() => {
|
||||
navigate(-1);
|
||||
}, [navigate]);
|
||||
navigate(-1)
|
||||
}, [navigate])
|
||||
|
||||
useBodyKeyDown('ArrowRight', navigateRight);
|
||||
useBodyKeyDown('ArrowLeft', navigateLeft);
|
||||
useBodyKeyDown('ArrowRight', navigateRight)
|
||||
useBodyKeyDown('ArrowLeft', navigateLeft)
|
||||
|
||||
const adding = pathname.match('/add');
|
||||
const removing = pathname.match('/remove');
|
||||
const finding = pathname.match('/find');
|
||||
const creating = pathname.match('/create');
|
||||
const adding = pathname.match('/add')
|
||||
const removing = pathname.match('/remove')
|
||||
const finding = pathname.match('/find')
|
||||
const creating = pathname.match('/create')
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -107,7 +107,7 @@ function NavigationTabs({ location: { pathname }, history }: RouteComponentProps
|
||||
<Tabs>
|
||||
<RowBetween style={{ padding: '1rem 1rem 0 1rem' }}>
|
||||
<Hover onClick={() => history.goBack()}>
|
||||
<ArrowLink/>
|
||||
<ArrowLink />
|
||||
</Hover>
|
||||
<ActiveText>{adding ? 'Add' : 'Remove'} Liquidity</ActiveText>
|
||||
<QuestionHelper
|
||||
@ -123,20 +123,20 @@ function NavigationTabs({ location: { pathname }, history }: RouteComponentProps
|
||||
<Tabs>
|
||||
<RowBetween style={{ padding: '1rem' }}>
|
||||
<HistoryLink to="/pool">
|
||||
<ArrowLink/>
|
||||
<ArrowLink />
|
||||
</HistoryLink>
|
||||
<ActiveText>Import Pool</ActiveText>
|
||||
<QuestionHelper text={'Use this tool to find pairs that don\'t automatically appear in the interface.'}/>
|
||||
<QuestionHelper text={"Use this tool to find pairs that don't automatically appear in the interface."} />
|
||||
</RowBetween>
|
||||
</Tabs>
|
||||
) : creating ? (
|
||||
<Tabs>
|
||||
<RowBetween style={{ padding: '1rem' }}>
|
||||
<HistoryLink to="/pool">
|
||||
<ArrowLink/>
|
||||
<ArrowLink />
|
||||
</HistoryLink>
|
||||
<ActiveText>Create Pool</ActiveText>
|
||||
<QuestionHelper text={'Use this interface to create a new pool.'}/>
|
||||
<QuestionHelper text={'Use this interface to create a new pool.'} />
|
||||
</RowBetween>
|
||||
</Tabs>
|
||||
) : (
|
||||
@ -149,7 +149,7 @@ function NavigationTabs({ location: { pathname }, history }: RouteComponentProps
|
||||
</Tabs>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
export default withRouter(NavigationTabs);
|
||||
export default withRouter(NavigationTabs)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const StyledInput = styled.input<{error?: boolean; fontSize?: string; align?: string}>`
|
||||
const StyledInput = styled.input<{ error?: boolean; fontSize?: string; align?: string }>`
|
||||
color: ${({ error, theme }) => error && theme.red1};
|
||||
color: ${({ theme }) => theme.text1};
|
||||
width: 0;
|
||||
@ -45,8 +45,20 @@ function escapeRegExp(string: string): string {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
|
||||
}
|
||||
|
||||
export const Input = React.memo(({ value, onUserInput, placeHolder = null, ...rest }: any) => {
|
||||
function enforcer(nextUserInput: string) {
|
||||
export const Input = React.memo(function InnerInput({
|
||||
value,
|
||||
onUserInput,
|
||||
placeHolder,
|
||||
...rest
|
||||
}: {
|
||||
value: string | number
|
||||
onUserInput: (string) => void
|
||||
placeHolder?: string
|
||||
align?: 'right' | 'left'
|
||||
id?: string
|
||||
onClick?: () => void
|
||||
}) {
|
||||
const enforcer = (nextUserInput: string) => {
|
||||
if (nextUserInput === '' || inputRegex.test(escapeRegExp(nextUserInput))) {
|
||||
onUserInput(nextUserInput)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom'
|
||||
import { TokenAmount, JSBI, Token, Pair } from '@uniswap/sdk'
|
||||
|
||||
import Row from '../Row'
|
||||
@ -21,7 +21,7 @@ import { useWeb3React } from '@web3-react/core'
|
||||
import { useAddressBalance } from '../../contexts/Balances'
|
||||
import { usePair, useAllPairs } from '../../contexts/Pairs'
|
||||
|
||||
function PoolFinder({ history }) {
|
||||
function PoolFinder({ history }: RouteComponentProps) {
|
||||
const Fields = {
|
||||
TOKEN0: 0,
|
||||
TOKEN1: 1
|
||||
@ -65,20 +65,20 @@ function PoolFinder({ history }) {
|
||||
function endSearch() {
|
||||
history.goBack() // return to previous page
|
||||
newLiquidity &&
|
||||
addPopup(
|
||||
<AutoColumn gap={'10px'}>
|
||||
<Text fontSize={20} fontWeight={500}>
|
||||
Pool Imported
|
||||
</Text>
|
||||
<Row>
|
||||
<DoubleTokenLogo a0={token0Address || ''} a1={token1Address || ''} margin={true}/>
|
||||
<Text fontSize={16} fotnWeight={500}>
|
||||
UNI {token0?.symbol} / {token1?.symbol}
|
||||
addPopup(
|
||||
<AutoColumn gap={'10px'}>
|
||||
<Text fontSize={20} fontWeight={500}>
|
||||
Pool Imported
|
||||
</Text>
|
||||
</Row>
|
||||
<Link>View on Uniswap Info.</Link>
|
||||
</AutoColumn>
|
||||
)
|
||||
<Row>
|
||||
<DoubleTokenLogo a0={token0Address || ''} a1={token1Address || ''} margin={true} />
|
||||
<Text fontSize={16} fotnWeight={500}>
|
||||
UNI {token0?.symbol} / {token1?.symbol}
|
||||
</Text>
|
||||
</Row>
|
||||
<Link>View on Uniswap Info.</Link>
|
||||
</AutoColumn>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -101,7 +101,7 @@ function PoolFinder({ history }) {
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
<TokenLogo address={token0Address}/>
|
||||
<TokenLogo address={token0Address} />
|
||||
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
||||
{token0?.symbol}
|
||||
</Text>
|
||||
@ -109,7 +109,7 @@ function PoolFinder({ history }) {
|
||||
</ButtonDropwdownLight>
|
||||
)}
|
||||
<ColumnCenter>
|
||||
<Plus size="16" color="#888D9B"/>
|
||||
<Plus size="16" color="#888D9B" />
|
||||
</ColumnCenter>
|
||||
{!token1Address ? (
|
||||
<ButtonDropwdown
|
||||
@ -128,7 +128,7 @@ function PoolFinder({ history }) {
|
||||
}}
|
||||
>
|
||||
<Row>
|
||||
<TokenLogo address={token1Address}/>
|
||||
<TokenLogo address={token1Address} />
|
||||
<Text fontWeight={500} fontSize={20} marginLeft={'12px'}>
|
||||
{token1?.symbol}
|
||||
</Text>
|
||||
@ -137,7 +137,8 @@ function PoolFinder({ history }) {
|
||||
)}
|
||||
{allowImport && (
|
||||
<ColumnCenter
|
||||
style={{ justifyItems: 'center', backgroundColor: '', padding: '12px 0px', borderRadius: '12px' }}>
|
||||
style={{ justifyItems: 'center', backgroundColor: '', padding: '12px 0px', borderRadius: '12px' }}
|
||||
>
|
||||
<Text textAlign="center" fontWeight={500} color="">
|
||||
{newLiquidity ? 'Pool Found!' : 'Pool already imported.'}
|
||||
</Text>
|
||||
|
@ -79,7 +79,7 @@ export default function App() {
|
||||
{activePopups.map(item => {
|
||||
return (
|
||||
<Popup key={item.key}>
|
||||
<StyledClose color="#888D9B" onClick={() => removePopup(item.key)}/>
|
||||
<StyledClose color="#888D9B" onClick={() => removePopup(item.key)} />
|
||||
{React.cloneElement(item.content, { popKey: item.key })}
|
||||
</Popup>
|
||||
)
|
||||
@ -98,7 +98,7 @@ export default function App() {
|
||||
.map(item => {
|
||||
return (
|
||||
<Popup key={item.key}>
|
||||
<StyledClose color="#888D9B" onClick={() => removePopup(item.key)}/>
|
||||
<StyledClose color="#888D9B" onClick={() => removePopup(item.key)} />
|
||||
{React.cloneElement(item.content, { popKey: item.key })}
|
||||
</Popup>
|
||||
)
|
||||
|
@ -31,7 +31,7 @@ const HoverCard = styled(Card)`
|
||||
`
|
||||
|
||||
interface PositionCardProps extends RouteComponentProps<{}> {
|
||||
pairAddress: string;
|
||||
pairAddress: string
|
||||
token0: Token
|
||||
token1: Token
|
||||
minimal?: boolean
|
||||
@ -86,7 +86,7 @@ function PositionCard({ pairAddress, token0, token1, history, border, minimal =
|
||||
</FixedHeightRow>
|
||||
<FixedHeightRow onClick={() => setShowMore(!showMore)}>
|
||||
<RowFixed>
|
||||
<DoubleLogo a0={token0?.address || ''} a1={token1?.address || ''} margin={true} size={20}/>
|
||||
<DoubleLogo a0={token0?.address || ''} a1={token1?.address || ''} margin={true} size={20} />
|
||||
<Text fontWeight={500} fontSize={20}>
|
||||
{token0?.symbol}:{token1?.symbol}
|
||||
</Text>
|
||||
@ -104,7 +104,7 @@ function PositionCard({ pairAddress, token0, token1, history, border, minimal =
|
||||
</Text>
|
||||
{token0Deposited ? (
|
||||
<RowFixed>
|
||||
{!minimal && <TokenLogo address={token0?.address || ''}/>}
|
||||
{!minimal && <TokenLogo address={token0?.address || ''} />}
|
||||
<Text color="#888D9B" fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||
{token0Deposited?.toFixed(8)}
|
||||
</Text>
|
||||
@ -119,7 +119,7 @@ function PositionCard({ pairAddress, token0, token1, history, border, minimal =
|
||||
</Text>
|
||||
{token1Deposited ? (
|
||||
<RowFixed>
|
||||
{!minimal && <TokenLogo address={token1?.address || ''}/>}
|
||||
{!minimal && <TokenLogo address={token1?.address || ''} />}
|
||||
<Text color="#888D9B" fontSize={16} fontWeight={500} marginLeft={'6px'}>
|
||||
{token1Deposited?.toFixed(8)}
|
||||
</Text>
|
||||
@ -140,16 +140,16 @@ function PositionCard({ pairAddress, token0, token1, history, border, minimal =
|
||||
<AutoColumn gap="12px">
|
||||
<FixedHeightRow onClick={() => setShowMore(!showMore)} style={{ cursor: 'pointer' }}>
|
||||
<RowFixed>
|
||||
<DoubleLogo a0={token0?.address || ''} a1={token1?.address || ''} margin={true} size={20}/>
|
||||
<DoubleLogo a0={token0?.address || ''} a1={token1?.address || ''} margin={true} size={20} />
|
||||
<Text fontWeight={500} fontSize={20}>
|
||||
{token0?.symbol}:{token1?.symbol}
|
||||
</Text>
|
||||
</RowFixed>
|
||||
<RowFixed>
|
||||
{showMore ? (
|
||||
<ChevronUp size="20" style={{ marginLeft: '10px' }}/>
|
||||
<ChevronUp size="20" style={{ marginLeft: '10px' }} />
|
||||
) : (
|
||||
<ChevronDown size="20" style={{ marginLeft: '10px' }}/>
|
||||
<ChevronDown size="20" style={{ marginLeft: '10px' }} />
|
||||
)}
|
||||
</RowFixed>
|
||||
</FixedHeightRow>
|
||||
@ -167,7 +167,7 @@ function PositionCard({ pairAddress, token0, token1, history, border, minimal =
|
||||
{token0Deposited?.toFixed(8)}
|
||||
</Text>
|
||||
{!minimal && (
|
||||
<TokenLogo size="20px" style={{ marginLeft: '8px' }} address={token0?.address || ''}/>
|
||||
<TokenLogo size="20px" style={{ marginLeft: '8px' }} address={token0?.address || ''} />
|
||||
)}
|
||||
</RowFixed>
|
||||
) : (
|
||||
@ -187,7 +187,7 @@ function PositionCard({ pairAddress, token0, token1, history, border, minimal =
|
||||
{token1Deposited?.toFixed(8)}
|
||||
</Text>
|
||||
{!minimal && (
|
||||
<TokenLogo size="20px" style={{ marginLeft: '8px' }} address={token1?.address || ''}/>
|
||||
<TokenLogo size="20px" style={{ marginLeft: '8px' }} address={token1?.address || ''} />
|
||||
)}
|
||||
</RowFixed>
|
||||
) : (
|
||||
|
@ -62,7 +62,7 @@ const Popup = styled.div`
|
||||
`}
|
||||
`
|
||||
|
||||
export default function QuestionHelper({ text }) {
|
||||
export default function QuestionHelper({ text }: { text: string }) {
|
||||
const [showPopup, setPopup] = useState(false)
|
||||
|
||||
return (
|
||||
|
@ -154,18 +154,18 @@ interface SearchModalProps extends RouteComponentProps<{}> {
|
||||
}
|
||||
|
||||
function SearchModal({
|
||||
history,
|
||||
isOpen,
|
||||
onDismiss,
|
||||
onTokenSelect,
|
||||
urlAddedTokens,
|
||||
filterType,
|
||||
hiddenToken,
|
||||
showSendWithSwap,
|
||||
otherSelectedTokenAddress,
|
||||
otherSelectedText,
|
||||
showCommonBases = false
|
||||
}: SearchModalProps) {
|
||||
history,
|
||||
isOpen,
|
||||
onDismiss,
|
||||
onTokenSelect,
|
||||
urlAddedTokens,
|
||||
filterType,
|
||||
hiddenToken,
|
||||
showSendWithSwap,
|
||||
otherSelectedTokenAddress,
|
||||
otherSelectedText,
|
||||
showCommonBases = false
|
||||
}: SearchModalProps) {
|
||||
const { t } = useTranslation()
|
||||
const { account, chainId } = useWeb3React()
|
||||
const theme = useContext(ThemeContext)
|
||||
@ -377,7 +377,7 @@ function SearchModal({
|
||||
}}
|
||||
>
|
||||
<RowFixed>
|
||||
<DoubleTokenLogo a0={token0?.address || ''} a1={token1?.address || ''} size={24} margin={true}/>
|
||||
<DoubleTokenLogo a0={token0?.address || ''} a1={token1?.address || ''} size={24} margin={true} />
|
||||
<Text fontWeight={500} fontSize={16}>{`${token0?.symbol}/${token1?.symbol}`}</Text>
|
||||
</RowFixed>
|
||||
{/* <Text fontWeight={500} fontSize={16}>
|
||||
@ -418,7 +418,7 @@ function SearchModal({
|
||||
}}
|
||||
>
|
||||
<RowFixed>
|
||||
<TokenLogo address={temporaryToken.address} size={'24px'} style={{ marginRight: '14px' }}/>
|
||||
<TokenLogo address={temporaryToken.address} size={'24px'} style={{ marginRight: '14px' }} />
|
||||
<Column>
|
||||
<Text fontWeight={500}>{temporaryToken.symbol}</Text>
|
||||
<FadedSpan>(Found by search)</FadedSpan>
|
||||
@ -431,16 +431,16 @@ function SearchModal({
|
||||
return <TokenModalInfo>{t('noToken')}</TokenModalInfo>
|
||||
}
|
||||
}
|
||||
// TODO is this the right place to link to create exchange?
|
||||
// else if (isAddress(searchQuery) && tokenAddress === ethers.constants.AddressZero) {
|
||||
// return (
|
||||
// <>
|
||||
// <TokenModalInfo>{t('noToken')}</TokenModalInfo>
|
||||
// <TokenModalInfo>
|
||||
// <Link to={`/create-exchange/${searchQuery}`}>{t('createExchange')}</Link>
|
||||
// </TokenModalInfo>
|
||||
// </>
|
||||
// )
|
||||
// TODO is this the right place to link to create exchange?
|
||||
// else if (isAddress(searchQuery) && tokenAddress === ethers.constants.AddressZero) {
|
||||
// return (
|
||||
// <>
|
||||
// <TokenModalInfo>{t('noToken')}</TokenModalInfo>
|
||||
// <TokenModalInfo>
|
||||
// <Link to={`/create-exchange/${searchQuery}`}>{t('createExchange')}</Link>
|
||||
// </TokenModalInfo>
|
||||
// </>
|
||||
// )
|
||||
// }
|
||||
else {
|
||||
return filteredTokenList
|
||||
@ -453,8 +453,8 @@ function SearchModal({
|
||||
? -1
|
||||
: 1
|
||||
: sortDirection
|
||||
? 1
|
||||
: -1
|
||||
? 1
|
||||
: -1
|
||||
})
|
||||
.map(({ address, symbol, balance }) => {
|
||||
const urlAdded = urlAddedTokens && urlAddedTokens.hasOwnProperty(address)
|
||||
@ -467,13 +467,12 @@ function SearchModal({
|
||||
return (
|
||||
<MenuItem
|
||||
key={address}
|
||||
onClick={() => (hiddenToken && hiddenToken === address ? () => {
|
||||
} : _onTokenSelect(address))}
|
||||
onClick={() => (hiddenToken && hiddenToken === address ? () => {} : _onTokenSelect(address))}
|
||||
disabled={hiddenToken && hiddenToken === address}
|
||||
selected={otherSelectedTokenAddress === address}
|
||||
>
|
||||
<RowFixed>
|
||||
<TokenLogo address={address} size={'24px'} style={{ marginRight: '14px' }}/>
|
||||
<TokenLogo address={address} size={'24px'} style={{ marginRight: '14px' }} />
|
||||
<Column>
|
||||
<Text fontWeight={500}>
|
||||
{symbol}
|
||||
@ -500,9 +499,7 @@ function SearchModal({
|
||||
{balance ? (
|
||||
<Text>
|
||||
{zeroBalance && showSendWithSwap ? (
|
||||
<ColumnCenter
|
||||
style={{ backgroundColor: theme.bg2, padding: '8px', borderRadius: '12px' }}
|
||||
>
|
||||
<ColumnCenter style={{ backgroundColor: theme.bg2, padding: '8px', borderRadius: '12px' }}>
|
||||
<Text textAlign="center" fontWeight={500} color={theme.blue1}>
|
||||
Send With Swap
|
||||
</Text>
|
||||
@ -514,7 +511,7 @@ function SearchModal({
|
||||
)}
|
||||
</Text>
|
||||
) : account ? (
|
||||
<SpinnerWrapper src={Circle} alt="loader"/>
|
||||
<SpinnerWrapper src={Circle} alt="loader" />
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
@ -569,7 +566,7 @@ function SearchModal({
|
||||
Import A Token
|
||||
</Text>
|
||||
</RowFixed>
|
||||
<CloseIcon onClick={onDismiss}/>
|
||||
<CloseIcon onClick={onDismiss} />
|
||||
</RowBetween>
|
||||
<TYPE.body style={{ marginTop: '10px' }}>
|
||||
To import a custom token, paste token address in the search bar.
|
||||
@ -589,7 +586,7 @@ function SearchModal({
|
||||
<Text fontWeight={500} fontSize={16}>
|
||||
{filterType === 'tokens' ? 'Select A Token' : 'Select A Pool'}
|
||||
</Text>
|
||||
<CloseIcon onClick={onDismiss}/>
|
||||
<CloseIcon onClick={onDismiss} />
|
||||
</RowBetween>
|
||||
<Input
|
||||
type={'text'}
|
||||
@ -604,7 +601,7 @@ function SearchModal({
|
||||
<Text fontWeight={500} fontSize={16}>
|
||||
Common Bases
|
||||
</Text>
|
||||
<QuestionHelper text="These tokens are commonly used in pairs."/>
|
||||
<QuestionHelper text="These tokens are commonly used in pairs." />
|
||||
</AutoRow>
|
||||
<AutoRow gap="10px">
|
||||
{COMMON_BASES[chainId]?.map(token => {
|
||||
@ -615,7 +612,7 @@ function SearchModal({
|
||||
disable={hiddenToken === token.address}
|
||||
key={token.address}
|
||||
>
|
||||
<TokenLogo address={token.address}/>
|
||||
<TokenLogo address={token.address} />
|
||||
<Text fontWeight={500} fontSize={16}>
|
||||
{token.symbol}
|
||||
</Text>
|
||||
@ -637,16 +634,16 @@ function SearchModal({
|
||||
</RowBetween>
|
||||
</PaddedColumn>
|
||||
)}
|
||||
{!showTokenImport && <div style={{ width: '100%', height: '1px', backgroundColor: theme.bg2 }}/>}
|
||||
{!showTokenImport && <div style={{ width: '100%', height: '1px', backgroundColor: theme.bg2 }} />}
|
||||
{!showTokenImport && <TokenList>{filterType === 'tokens' ? renderTokenList() : renderPairsList()}</TokenList>}
|
||||
{!showTokenImport && <div style={{ width: '100%', height: '1px', backgroundColor: theme.bg2 }}/>}
|
||||
{!showTokenImport && <div style={{ width: '100%', height: '1px', backgroundColor: theme.bg2 }} />}
|
||||
{!showTokenImport && (
|
||||
<Card>
|
||||
<AutoRow justify={'center'}>
|
||||
<div>
|
||||
{filterType !== 'tokens' && (
|
||||
<Text fontWeight={500}>
|
||||
{!isMobile && 'Don\'t see a pool? '}
|
||||
{!isMobile && "Don't see a pool? "}
|
||||
<StyledLink
|
||||
onClick={() => {
|
||||
history.push('/find')
|
||||
@ -658,7 +655,7 @@ function SearchModal({
|
||||
)}
|
||||
{filterType === 'tokens' && (
|
||||
<Text fontWeight={500} color={theme.text2} fontSize={14}>
|
||||
{!isMobile && 'Don\'t see a token? '}
|
||||
{!isMobile && "Don't see a token? "}
|
||||
|
||||
<StyledLink
|
||||
onClick={() => {
|
||||
|
@ -58,12 +58,15 @@ export default function InputSlider({ value, onChange, override }: InputSliderPr
|
||||
const [internalVal, setInternalVal] = useState<number>(value)
|
||||
const debouncedInternalValue = useDebounce(internalVal, 100)
|
||||
|
||||
const handleChange = useCallback((e, val) => {
|
||||
setInternalVal(val)
|
||||
if (val !== debouncedInternalValue) {
|
||||
onChange(val)
|
||||
}
|
||||
}, [setInternalVal, onChange, debouncedInternalValue])
|
||||
const handleChange = useCallback(
|
||||
(e, val) => {
|
||||
setInternalVal(val)
|
||||
if (val !== debouncedInternalValue) {
|
||||
onChange(val)
|
||||
}
|
||||
},
|
||||
[setInternalVal, onChange, debouncedInternalValue]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (override) {
|
||||
|
@ -61,21 +61,21 @@ const Input = styled.input<{ active?: boolean }>`
|
||||
color: ${({ theme }) => theme.text1};
|
||||
text-align: left;
|
||||
${({ active }) =>
|
||||
active &&
|
||||
css`
|
||||
active &&
|
||||
css`
|
||||
color: initial;
|
||||
cursor: initial;
|
||||
text-align: right;
|
||||
`}
|
||||
${({ placeholder }) =>
|
||||
placeholder !== 'Custom' &&
|
||||
css`
|
||||
placeholder !== 'Custom' &&
|
||||
css`
|
||||
text-align: right;
|
||||
color: ${({ theme }) => theme.text1};
|
||||
`}
|
||||
${({ color }) =>
|
||||
color === 'red' &&
|
||||
css`
|
||||
color === 'red' &&
|
||||
css`
|
||||
color: ${({ theme }) => theme.red1};
|
||||
`}
|
||||
`
|
||||
@ -84,8 +84,8 @@ const BottomError = styled(Text)`
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
${({ show }) =>
|
||||
show &&
|
||||
css`
|
||||
show &&
|
||||
css`
|
||||
padding-top: 12px;
|
||||
`}
|
||||
`
|
||||
@ -94,9 +94,10 @@ const OptionCustom = styled(FancyButton)<{ active?: boolean; warning?: boolean }
|
||||
height: 2rem;
|
||||
position: relative;
|
||||
padding: 0 0.75rem;
|
||||
border: ${({ theme, active, warning }) => active && `1px solid ${(warning ? theme.red1 : theme.blue1)}`};
|
||||
border: ${({ theme, active, warning }) => active && `1px solid ${warning ? theme.red1 : theme.blue1}`};
|
||||
:hover {
|
||||
border: ${({ theme, active, warning }) => active && `1px solid ${(warning ? darken(0.1, theme.red1) : darken(0.1, theme.blue1))}`};
|
||||
border: ${({ theme, active, warning }) =>
|
||||
active && `1px solid ${warning ? darken(0.1, theme.red1) : darken(0.1, theme.blue1)}`};
|
||||
}
|
||||
|
||||
input {
|
||||
@ -116,12 +117,12 @@ const Percent = styled.div`
|
||||
font-size: 0, 8rem;
|
||||
flex-grow: 0;
|
||||
${({ color, theme }) =>
|
||||
(color === 'faded' &&
|
||||
css`
|
||||
(color === 'faded' &&
|
||||
css`
|
||||
color: ${theme.bg1};
|
||||
`) ||
|
||||
(color === 'red' &&
|
||||
css`
|
||||
(color === 'red' &&
|
||||
css`
|
||||
color: ${theme.red1};
|
||||
`)};
|
||||
`
|
||||
@ -133,7 +134,12 @@ interface TransactionDetailsProps {
|
||||
setDeadline: (deadline: number) => void
|
||||
}
|
||||
|
||||
export default function TransactionDetails({ setRawSlippage, rawSlippage, deadline, setDeadline }: TransactionDetailsProps) {
|
||||
export default function TransactionDetails({
|
||||
setRawSlippage,
|
||||
rawSlippage,
|
||||
deadline,
|
||||
setDeadline
|
||||
}: TransactionDetailsProps) {
|
||||
const [activeIndex, setActiveIndex] = useState(2)
|
||||
|
||||
const [warningType, setWarningType] = useState(WARNING_TYPE.none)
|
||||
@ -147,26 +153,10 @@ export default function TransactionDetails({ setRawSlippage, rawSlippage, deadli
|
||||
|
||||
const [deadlineInput, setDeadlineInput] = useState(deadline / 60)
|
||||
|
||||
function parseCustomDeadline(e) {
|
||||
let val = e.target.value
|
||||
const acceptableValues = [/^$/, /^\d+$/]
|
||||
if (acceptableValues.some(re => re.test(val))) {
|
||||
setDeadlineInput(val)
|
||||
setDeadline(val * 60)
|
||||
}
|
||||
}
|
||||
|
||||
const setFromCustom = () => {
|
||||
setActiveIndex(4)
|
||||
inputRef.current.focus()
|
||||
// if there's a value, evaluate the bounds
|
||||
checkBounds(debouncedInput)
|
||||
}
|
||||
|
||||
const updateSlippage = useCallback(
|
||||
newSlippage => {
|
||||
// round to 2 decimals to prevent ethers error
|
||||
let numParsed = newSlippage * 100
|
||||
const numParsed = newSlippage * 100
|
||||
|
||||
// set both slippage values in parents
|
||||
setRawSlippage(numParsed)
|
||||
@ -174,39 +164,6 @@ export default function TransactionDetails({ setRawSlippage, rawSlippage, deadli
|
||||
[setRawSlippage]
|
||||
)
|
||||
|
||||
// used for slippage presets
|
||||
const setFromFixed = useCallback(
|
||||
(index, slippage) => {
|
||||
// update slippage in parent, reset errors and input state
|
||||
updateSlippage(slippage)
|
||||
setWarningType(WARNING_TYPE.none)
|
||||
setActiveIndex(index)
|
||||
},
|
||||
[updateSlippage]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
switch (initialSlippage) {
|
||||
case 10:
|
||||
setFromFixed(1, 0.1)
|
||||
break
|
||||
case 50:
|
||||
setFromFixed(2, 0.5)
|
||||
break
|
||||
case 100:
|
||||
setFromFixed(3, 1)
|
||||
break
|
||||
default:
|
||||
// restrict to 2 decimal places
|
||||
let acceptableValues = [/^$/, /^\d{1,2}$/, /^\d{0,2}\.\d{0,2}$/]
|
||||
// if its within accepted decimal limit, update the input state
|
||||
if (acceptableValues.some(val => val.test('' + (initialSlippage / 100)))) {
|
||||
setUserInput('' + (initialSlippage / 100))
|
||||
setActiveIndex(4)
|
||||
}
|
||||
}
|
||||
}, [initialSlippage, setFromFixed])
|
||||
|
||||
const checkBounds = useCallback(
|
||||
slippageValue => {
|
||||
setWarningType(WARNING_TYPE.none)
|
||||
@ -231,12 +188,60 @@ export default function TransactionDetails({ setRawSlippage, rawSlippage, deadli
|
||||
[updateSlippage]
|
||||
)
|
||||
|
||||
function parseCustomDeadline(e) {
|
||||
const val = e.target.value
|
||||
const acceptableValues = [/^$/, /^\d+$/]
|
||||
if (acceptableValues.some(re => re.test(val))) {
|
||||
setDeadlineInput(val)
|
||||
setDeadline(val * 60)
|
||||
}
|
||||
}
|
||||
const setFromCustom = () => {
|
||||
setActiveIndex(4)
|
||||
inputRef.current.focus()
|
||||
// if there's a value, evaluate the bounds
|
||||
checkBounds(debouncedInput)
|
||||
}
|
||||
|
||||
// used for slippage presets
|
||||
const setFromFixed = useCallback(
|
||||
(index, slippage) => {
|
||||
// update slippage in parent, reset errors and input state
|
||||
updateSlippage(slippage)
|
||||
setWarningType(WARNING_TYPE.none)
|
||||
setActiveIndex(index)
|
||||
},
|
||||
[updateSlippage]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
switch (initialSlippage) {
|
||||
case 10:
|
||||
setFromFixed(1, 0.1)
|
||||
break
|
||||
case 50:
|
||||
setFromFixed(2, 0.5)
|
||||
break
|
||||
case 100:
|
||||
setFromFixed(3, 1)
|
||||
break
|
||||
default:
|
||||
// restrict to 2 decimal places
|
||||
const acceptableValues = [/^$/, /^\d{1,2}$/, /^\d{0,2}\.\d{0,2}$/]
|
||||
// if its within accepted decimal limit, update the input state
|
||||
if (acceptableValues.some(val => val.test('' + initialSlippage / 100))) {
|
||||
setUserInput('' + initialSlippage / 100)
|
||||
setActiveIndex(4)
|
||||
}
|
||||
}
|
||||
}, [initialSlippage, setFromFixed])
|
||||
|
||||
// check that the theyve entered number and correct decimal
|
||||
const parseInput = e => {
|
||||
let input = e.target.value
|
||||
const input = e.target.value
|
||||
|
||||
// restrict to 2 decimal places
|
||||
let acceptableValues = [/^$/, /^\d{1,2}$/, /^\d{0,2}\.\d{0,2}$/]
|
||||
const acceptableValues = [/^$/, /^\d{1,2}$/, /^\d{0,2}\.\d{0,2}$/]
|
||||
// if its within accepted decimal limit, update the input state
|
||||
if (acceptableValues.some(a => a.test(input))) {
|
||||
setUserInput(input)
|
||||
@ -313,8 +318,8 @@ export default function TransactionDetails({ setRawSlippage, rawSlippage, deadli
|
||||
placeholder={
|
||||
activeIndex === 4
|
||||
? !!userInput
|
||||
? ''
|
||||
: '0'
|
||||
? ''
|
||||
: '0'
|
||||
: activeIndex !== 4 && userInput !== ''
|
||||
? userInput
|
||||
: 'Custom'
|
||||
@ -352,8 +357,8 @@ export default function TransactionDetails({ setRawSlippage, rawSlippage, deadli
|
||||
: warningType !== WARNING_TYPE.none && warningType !== WARNING_TYPE.riskyEntryLow
|
||||
? 'red'
|
||||
: warningType === WARNING_TYPE.riskyEntryLow
|
||||
? '#F3841E'
|
||||
: ''
|
||||
? '#F3841E'
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{warningType === WARNING_TYPE.emptyInput && 'Enter a slippage percentage'}
|
||||
@ -366,12 +371,16 @@ export default function TransactionDetails({ setRawSlippage, rawSlippage, deadli
|
||||
<AutoColumn gap="sm">
|
||||
<RowFixed padding={'0 20px'}>
|
||||
<TYPE.body fontSize={14}>Deadline</TYPE.body>
|
||||
<QuestionHelper text="Deadline in minutes. If your transaction takes longer than this it will revert."/>
|
||||
<QuestionHelper text="Deadline in minutes. If your transaction takes longer than this it will revert." />
|
||||
</RowFixed>
|
||||
<RowFixed padding={'0 20px'}>
|
||||
<OptionCustom style={{ width: '80px' }}>
|
||||
<Input tabIndex={-1} placeholder={'' + deadlineInput} value={deadlineInput}
|
||||
onChange={parseCustomDeadline}/>
|
||||
<Input
|
||||
tabIndex={-1}
|
||||
placeholder={'' + deadlineInput}
|
||||
value={deadlineInput}
|
||||
onChange={parseCustomDeadline}
|
||||
/>
|
||||
</OptionCustom>
|
||||
<TYPE.body style={{ paddingLeft: '8px' }} fontSize={14}>
|
||||
minutes
|
||||
|
@ -20,7 +20,7 @@ const Image = styled.img<{ size: string }>`
|
||||
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.075);
|
||||
`
|
||||
|
||||
const Emoji = styled.span<{size?:string}>`
|
||||
const Emoji = styled.span<{ size?: string }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -30,7 +30,7 @@ const Emoji = styled.span<{size?:string}>`
|
||||
margin-bottom: -4px;
|
||||
`
|
||||
|
||||
const StyledEthereumLogo = styled(EthereumLogo)<{size: string}>`
|
||||
const StyledEthereumLogo = styled(EthereumLogo)<{ size: string }>`
|
||||
width: ${({ size }) => size};
|
||||
height: ${({ size }) => size};
|
||||
`
|
||||
|
@ -28,7 +28,7 @@ const delay = 100
|
||||
|
||||
export default function TxnPopup({ hash, success, summary, popKey }) {
|
||||
const { chainId } = useWeb3React()
|
||||
let [count, setCount] = useState(1)
|
||||
const [count, setCount] = useState(1)
|
||||
|
||||
const [isRunning, setIsRunning] = useState(true)
|
||||
const [, , removePopup] = usePopups()
|
||||
@ -44,9 +44,9 @@ export default function TxnPopup({ hash, success, summary, popKey }) {
|
||||
return (
|
||||
<AutoRow onMouseEnter={() => setIsRunning(false)} onMouseLeave={() => setIsRunning(true)}>
|
||||
{success ? (
|
||||
<CheckCircle color={'#27AE60'} size={24} style={{ paddingRight: '24px' }}/>
|
||||
<CheckCircle color={'#27AE60'} size={24} style={{ paddingRight: '24px' }} />
|
||||
) : (
|
||||
<AlertCircle color={'#FF6871'} size={24} style={{ paddingRight: '24px' }}/>
|
||||
<AlertCircle color={'#FF6871'} size={24} style={{ paddingRight: '24px' }} />
|
||||
)}
|
||||
<AutoColumn gap="8px">
|
||||
<TYPE.body fontWeight={500}>
|
||||
@ -54,7 +54,7 @@ export default function TxnPopup({ hash, success, summary, popKey }) {
|
||||
</TYPE.body>
|
||||
<Link href={getEtherscanLink(chainId, hash, 'transaction')}>View on Etherscan</Link>
|
||||
</AutoColumn>
|
||||
<Fader count={count}/>
|
||||
<Fader count={count} />
|
||||
</AutoRow>
|
||||
)
|
||||
}
|
||||
|
@ -88,16 +88,16 @@ const IconWrapper = styled.div<{ size?: number }>`
|
||||
`
|
||||
|
||||
export default function Option({
|
||||
link = null,
|
||||
clickable = true,
|
||||
size = null,
|
||||
onClick = null,
|
||||
color,
|
||||
header,
|
||||
subheader = null,
|
||||
icon,
|
||||
active = false
|
||||
}) {
|
||||
link = null,
|
||||
clickable = true,
|
||||
size = null,
|
||||
onClick = null,
|
||||
color,
|
||||
header,
|
||||
subheader = null,
|
||||
icon,
|
||||
active = false
|
||||
}) {
|
||||
const content = (
|
||||
<OptionCardClickable onClick={onClick} clickable={clickable && !active} active={active}>
|
||||
<OptionCardLeft>
|
||||
@ -106,7 +106,7 @@ export default function Option({
|
||||
{active ? (
|
||||
<CircleWrapper>
|
||||
<GreenCircle>
|
||||
<div/>
|
||||
<div />
|
||||
</GreenCircle>
|
||||
</CircleWrapper>
|
||||
) : (
|
||||
@ -117,7 +117,7 @@ export default function Option({
|
||||
{subheader && <SubHeader>{subheader}</SubHeader>}
|
||||
</OptionCardLeft>
|
||||
<IconWrapper size={size}>
|
||||
<img src={icon} alt={'Icon'}/>
|
||||
<img src={icon} alt={'Icon'} />
|
||||
</IconWrapper>
|
||||
</OptionCardClickable>
|
||||
)
|
||||
|
@ -75,10 +75,10 @@ export default function PendingView({ uri = '', size, connector, error = false,
|
||||
|
||||
return (
|
||||
<PendingSection>
|
||||
{!error && connector === walletconnect && <WalletConnectData size={size} uri={uri}/>}
|
||||
{!error && connector === walletconnect && <WalletConnectData size={size} uri={uri} />}
|
||||
<LoadingMessage error={error}>
|
||||
<LoadingWrapper>
|
||||
{!error && <SpinnerWrapper src={Circle}/>}
|
||||
{!error && <SpinnerWrapper src={Circle} />}
|
||||
{error ? (
|
||||
<ErrorGroup>
|
||||
<div>Error connecting.</div>
|
||||
|
@ -21,7 +21,7 @@ export default function WalletConnectData({ uri = '', size }: WalletConnectDataP
|
||||
return (
|
||||
<QRCodeWrapper>
|
||||
{uri && (
|
||||
<QRCode size={size} value={uri} bgColor={isDark ? '#333639' : 'white'} fgColor={isDark ? 'white' : 'black'}/>
|
||||
<QRCode size={size} value={uri} bgColor={isDark ? '#333639' : 'white'} fgColor={isDark ? 'white' : 'black'} />
|
||||
)}
|
||||
</QRCodeWrapper>
|
||||
)
|
||||
|
@ -286,7 +286,7 @@ export default function WalletModal({ pendingTransactions, confirmedTransactions
|
||||
return (
|
||||
<UpperSection>
|
||||
<CloseIcon onClick={toggleWalletModal}>
|
||||
<CloseColor/>
|
||||
<CloseColor />
|
||||
</CloseIcon>
|
||||
<HeaderRow>{error instanceof UnsupportedChainIdError ? 'Wrong Network' : 'Error connecting'}</HeaderRow>
|
||||
<ContentWrapper>
|
||||
@ -313,7 +313,7 @@ export default function WalletModal({ pendingTransactions, confirmedTransactions
|
||||
return (
|
||||
<UpperSection>
|
||||
<CloseIcon onClick={toggleWalletModal}>
|
||||
<CloseColor/>
|
||||
<CloseColor />
|
||||
</CloseIcon>
|
||||
{walletView !== WALLET_VIEWS.ACCOUNT ? (
|
||||
<HeaderRow color="blue">
|
||||
@ -358,12 +358,7 @@ export default function WalletModal({ pendingTransactions, confirmedTransactions
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={walletModalOpen}
|
||||
onDismiss={toggleWalletModal}
|
||||
minHeight={null}
|
||||
maxHeight={90}
|
||||
>
|
||||
<Modal isOpen={walletModalOpen} onDismiss={toggleWalletModal} minHeight={null} maxHeight={90}>
|
||||
<Wrapper>{getModalContent()}</Wrapper>
|
||||
</Modal>
|
||||
)
|
||||
|
@ -76,8 +76,8 @@ const Web3StatusConnect = styled(Web3StatusGeneric)`
|
||||
}
|
||||
|
||||
${({ faded }) =>
|
||||
faded &&
|
||||
css`
|
||||
faded &&
|
||||
css`
|
||||
background-color: ${({ theme }) => theme.blue5};
|
||||
border: 1px solid ${({ theme }) => theme.blue5};
|
||||
color: ${({ theme }) => theme.buttonSecondaryText};
|
||||
@ -140,29 +140,29 @@ export default function Web3Status() {
|
||||
// handle the logo we want to show with the account
|
||||
function getStatusIcon() {
|
||||
if (connector === injected) {
|
||||
return <Identicon/>
|
||||
return <Identicon />
|
||||
} else if (connector === walletconnect) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={WalletConnectIcon} alt={''}/>
|
||||
<img src={WalletConnectIcon} alt={''} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === walletlink) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={CoinbaseWalletIcon} alt={''}/>
|
||||
<img src={CoinbaseWalletIcon} alt={''} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === fortmatic) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={FortmaticIcon} alt={''}/>
|
||||
<img src={FortmaticIcon} alt={''} />
|
||||
</IconWrapper>
|
||||
)
|
||||
} else if (connector === portis) {
|
||||
return (
|
||||
<IconWrapper size={16}>
|
||||
<img src={PortisIcon} alt={''}/>
|
||||
<img src={PortisIcon} alt={''} />
|
||||
</IconWrapper>
|
||||
)
|
||||
}
|
||||
@ -174,7 +174,7 @@ export default function Web3Status() {
|
||||
<Web3StatusConnected onClick={toggleWalletModal} pending={hasPendingTransactions}>
|
||||
{hasPendingTransactions ? (
|
||||
<RowBetween>
|
||||
<Text>{pending?.length} Pending</Text> <SpinnerWrapper src={LightCircle} alt="loader"/>
|
||||
<Text>{pending?.length} Pending</Text> <SpinnerWrapper src={LightCircle} alt="loader" />
|
||||
</RowBetween>
|
||||
) : (
|
||||
<Text>{ENSName || shortenAddress(account)}</Text>
|
||||
@ -185,7 +185,7 @@ export default function Web3Status() {
|
||||
} else if (error) {
|
||||
return (
|
||||
<Web3StatusError onClick={toggleWalletModal}>
|
||||
<NetworkIcon/>
|
||||
<NetworkIcon />
|
||||
<Text>{error instanceof UnsupportedChainIdError ? 'Wrong Network' : 'Error'}</Text>
|
||||
</Web3StatusError>
|
||||
)
|
||||
@ -205,7 +205,7 @@ export default function Web3Status() {
|
||||
return (
|
||||
<>
|
||||
{getWeb3Status()}
|
||||
<WalletModal ENSName={ENSName} pendingTransactions={pending} confirmedTransactions={confirmed}/>
|
||||
<WalletModal ENSName={ENSName} pendingTransactions={pending} confirmedTransactions={confirmed} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -14,10 +14,7 @@ export class FortmaticConnector extends FortmaticConnectorCore {
|
||||
if (!this.fortmatic) {
|
||||
const { default: Fortmatic } = await import('fortmatic')
|
||||
const { apiKey, chainId } = this as any
|
||||
this.fortmatic = new Fortmatic(
|
||||
apiKey,
|
||||
chainId === 1 || chainId === 4 ? undefined : chainIdToNetwork[chainId]
|
||||
)
|
||||
this.fortmatic = new Fortmatic(apiKey, chainId === 1 || chainId === 4 ? undefined : chainIdToNetwork[chainId])
|
||||
}
|
||||
|
||||
const provider = this.fortmatic.getProvider()
|
||||
|
@ -3,13 +3,13 @@ import { NetworkConnector as NetworkConnectorCore } from '@web3-react/network-co
|
||||
export class NetworkConnector extends NetworkConnectorCore {
|
||||
pause() {
|
||||
if ((this as any).active) {
|
||||
(this as any).providers[(this as any).currentChainId].stop()
|
||||
;(this as any).providers[(this as any).currentChainId].stop()
|
||||
}
|
||||
}
|
||||
|
||||
resume() {
|
||||
if ((this as any).active) {
|
||||
(this as any).providers[(this as any).currentChainId].start()
|
||||
;(this as any).providers[(this as any).currentChainId].start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,27 @@
|
||||
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
|
||||
import { Token, TokenAmount, WETH } from '@uniswap/sdk'
|
||||
import { BigintIsh, Token, TokenAmount, WETH } from '@uniswap/sdk'
|
||||
import { BigNumber } from 'ethers/utils'
|
||||
import React, { createContext, useCallback, useContext, useEffect, useMemo, useReducer } from 'react'
|
||||
|
||||
import { useWeb3React } from '../hooks'
|
||||
import { safeAccess, isAddress, getTokenAllowance } from '../utils'
|
||||
import { getTokenAllowance, isAddress } from '../utils'
|
||||
import { useBlockNumber } from './Application'
|
||||
|
||||
const UPDATE = 'UPDATE'
|
||||
|
||||
const AllowancesContext = createContext([])
|
||||
interface AllowancesState {
|
||||
[chainId: number]: {
|
||||
[address: string]: {
|
||||
[tokenAddress: string]: {
|
||||
[spenderAddress: string]: {
|
||||
value: BigintIsh
|
||||
blockNumber: BigNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const AllowancesContext = createContext<[AllowancesState, any]>([{}, {}])
|
||||
|
||||
function useAllowancesContext() {
|
||||
return useContext(AllowancesContext)
|
||||
@ -20,11 +34,11 @@ function reducer(state, { type, payload }) {
|
||||
return {
|
||||
...state,
|
||||
[networkId]: {
|
||||
...(safeAccess(state, [networkId]) || {}),
|
||||
...state?.[networkId],
|
||||
[address]: {
|
||||
...(safeAccess(state, [networkId, address]) || {}),
|
||||
...state?.[networkId]?.[address],
|
||||
[tokenAddress]: {
|
||||
...(safeAccess(state, [networkId, address, tokenAddress]) || {}),
|
||||
...state?.[networkId]?.[address]?.[tokenAddress],
|
||||
[spenderAddress]: {
|
||||
value,
|
||||
blockNumber
|
||||
@ -34,9 +48,8 @@ function reducer(state, { type, payload }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
default:
|
||||
throw Error(`Unexpected action type in AllowancesContext reducer: '${type}'.`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +73,7 @@ export function useAddressAllowance(address: string, token: Token, spenderAddres
|
||||
const globalBlockNumber = useBlockNumber()
|
||||
|
||||
const [state, { update }] = useAllowancesContext()
|
||||
const { value, blockNumber } = safeAccess(state, [chainId, address, token?.address, spenderAddress]) || {}
|
||||
const { value, blockNumber } = state?.[chainId]?.[address]?.[token?.address]?.[spenderAddress] ?? {}
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@ -92,6 +105,5 @@ export function useAddressAllowance(address: string, token: Token, spenderAddres
|
||||
}
|
||||
}, [address, token, spenderAddress, value, blockNumber, globalBlockNumber, chainId, library, update])
|
||||
|
||||
const newTokenAmount: TokenAmount = value ? new TokenAmount(token, value) : null
|
||||
return newTokenAmount
|
||||
return value ? new TokenAmount(token, value) : null
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react'
|
||||
|
||||
import { useWeb3React } from '../hooks'
|
||||
import { safeAccess } from '../utils'
|
||||
|
||||
const BLOCK_NUMBER = 'BLOCK_NUMBER'
|
||||
const USD_PRICE = 'USD_PRICE'
|
||||
@ -17,22 +16,25 @@ const USER_ADVANCED = 'USER_ADVANCED'
|
||||
const TOGGLE_USER_ADVANCED = 'TOGGLE_USER_ADVANCED'
|
||||
|
||||
interface ApplicationState {
|
||||
BLOCK_NUMBER: {},
|
||||
USD_PRICE: {},
|
||||
POPUP_LIST: Array<{ key: number; show: boolean; content: React.ReactElement }>,
|
||||
POPUP_KEY: number,
|
||||
WALLET_MODAL_OPEN: boolean,
|
||||
BLOCK_NUMBER: {}
|
||||
USD_PRICE: {}
|
||||
POPUP_LIST: Array<{ key: number; show: boolean; content: React.ReactElement }>
|
||||
POPUP_KEY: number
|
||||
WALLET_MODAL_OPEN: boolean
|
||||
USER_ADVANCED: boolean
|
||||
}
|
||||
|
||||
const ApplicationContext = createContext<[ApplicationState, { [updater: string]: (...args: any[]) => void }]>([{
|
||||
[BLOCK_NUMBER]: {},
|
||||
[USD_PRICE]: {},
|
||||
[POPUP_LIST]: [],
|
||||
[POPUP_KEY]: 0,
|
||||
[WALLET_MODAL_OPEN]: false,
|
||||
[USER_ADVANCED]: false
|
||||
}, {}])
|
||||
const ApplicationContext = createContext<[ApplicationState, { [updater: string]: (...args: any[]) => void }]>([
|
||||
{
|
||||
[BLOCK_NUMBER]: {},
|
||||
[USD_PRICE]: {},
|
||||
[POPUP_LIST]: [],
|
||||
[POPUP_KEY]: 0,
|
||||
[WALLET_MODAL_OPEN]: false,
|
||||
[USER_ADVANCED]: false
|
||||
},
|
||||
{}
|
||||
])
|
||||
|
||||
function useApplicationContext() {
|
||||
return useContext(ApplicationContext)
|
||||
@ -45,7 +47,7 @@ function reducer(state: ApplicationState, { type, payload }): ApplicationState {
|
||||
return {
|
||||
...state,
|
||||
[BLOCK_NUMBER]: {
|
||||
...(safeAccess(state, [BLOCK_NUMBER]) || {}),
|
||||
...state?.[BLOCK_NUMBER],
|
||||
[networkId]: blockNumber
|
||||
}
|
||||
}
|
||||
@ -80,9 +82,12 @@ export default function Provider({ children }) {
|
||||
[USER_ADVANCED]: false
|
||||
})
|
||||
|
||||
const updateBlockNumber = useCallback((networkId, blockNumber) => {
|
||||
dispatch({ type: UPDATE_BLOCK_NUMBER, payload: { networkId, blockNumber } })
|
||||
}, [dispatch])
|
||||
const updateBlockNumber = useCallback(
|
||||
(networkId, blockNumber) => {
|
||||
dispatch({ type: UPDATE_BLOCK_NUMBER, payload: { networkId, blockNumber } })
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
const toggleWalletModal = useCallback(() => {
|
||||
dispatch({ type: TOGGLE_WALLET_MODAL, payload: null })
|
||||
@ -92,9 +97,12 @@ export default function Provider({ children }) {
|
||||
dispatch({ type: TOGGLE_USER_ADVANCED, payload: null })
|
||||
}, [dispatch])
|
||||
|
||||
const setPopups = useCallback(newList => {
|
||||
dispatch({ type: ADD_POPUP, payload: { newList } })
|
||||
}, [dispatch])
|
||||
const setPopups = useCallback(
|
||||
newList => {
|
||||
dispatch({ type: ADD_POPUP, payload: { newList } })
|
||||
},
|
||||
[dispatch]
|
||||
)
|
||||
|
||||
return (
|
||||
<ApplicationContext.Provider
|
||||
@ -154,7 +162,7 @@ export function useBlockNumber() {
|
||||
|
||||
const [state] = useApplicationContext()
|
||||
|
||||
return safeAccess(state, [BLOCK_NUMBER, chainId])
|
||||
return state?.[BLOCK_NUMBER]?.[chainId]
|
||||
}
|
||||
|
||||
export function useWalletModalOpen() {
|
||||
@ -180,7 +188,11 @@ export function useToggleUserAdvanced() {
|
||||
return toggleUserAdvanced
|
||||
}
|
||||
|
||||
export function usePopups(): [ApplicationState['POPUP_LIST'], (content: React.ReactElement) => void, (key: number) => void] {
|
||||
export function usePopups(): [
|
||||
ApplicationState['POPUP_LIST'],
|
||||
(content: React.ReactElement) => void,
|
||||
(key: number) => void
|
||||
] {
|
||||
const [state, { setPopups }] = useApplicationContext()
|
||||
|
||||
const index = state[POPUP_KEY]
|
||||
|
@ -411,7 +411,7 @@ export function useAllBalances(): Array<TokenAmount> {
|
||||
if (!state || !state[chainId]) {
|
||||
return {}
|
||||
} else {
|
||||
let newBalances = {}
|
||||
const newBalances = {}
|
||||
Object.keys(state[chainId]).map(address => {
|
||||
return Object.keys(state[chainId][address]).map(tokenAddress => {
|
||||
if (state[chainId][address][tokenAddress].value) {
|
||||
|
@ -3,21 +3,23 @@ import React, { createContext, useContext, useReducer, useMemo, useCallback, use
|
||||
import TxnPopup from '../components/TxnPopup'
|
||||
|
||||
import { useWeb3React } from '../hooks'
|
||||
import { safeAccess } from '../utils'
|
||||
import { useBlockNumber, usePopups } from './Application'
|
||||
|
||||
const RESPONSE = 'response'
|
||||
const CUSTOM_DATA = 'CUSTOM_DATA'
|
||||
const BLOCK_NUMBER_CHECKED = 'BLOCK_NUMBER_CHECKED'
|
||||
const RECEIPT = 'receipt'
|
||||
const SUMMARY = 'summary'
|
||||
|
||||
const ADD = 'ADD'
|
||||
const CHECK = 'CHECK'
|
||||
const FINALIZE = 'FINALIZE'
|
||||
|
||||
interface TransactionState {
|
||||
|
||||
[chainId: number]: {
|
||||
[txHash: string]: {
|
||||
blockNumberChecked: any
|
||||
response: {
|
||||
customData?: any
|
||||
summary: any
|
||||
}
|
||||
receipt: any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TransactionsContext = createContext<[TransactionState, { [updater: string]: (...args: any[]) => void }]>([{}, {}])
|
||||
@ -26,21 +28,21 @@ export function useTransactionsContext() {
|
||||
return useContext(TransactionsContext)
|
||||
}
|
||||
|
||||
function reducer(state, { type, payload }) {
|
||||
function reducer(state: TransactionState, { type, payload }): TransactionState {
|
||||
switch (type) {
|
||||
case ADD: {
|
||||
const { networkId, hash, response } = payload
|
||||
|
||||
if (safeAccess(state, [networkId, hash]) !== null) {
|
||||
if (state[networkId]?.[hash]) {
|
||||
throw Error('Attempted to add existing transaction.')
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
[networkId]: {
|
||||
...(safeAccess(state, [networkId]) || {}),
|
||||
...state[networkId],
|
||||
[hash]: {
|
||||
[RESPONSE]: response
|
||||
response
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,17 +50,17 @@ function reducer(state, { type, payload }) {
|
||||
case CHECK: {
|
||||
const { networkId, hash, blockNumber } = payload
|
||||
|
||||
if (safeAccess(state, [networkId, hash]) === null) {
|
||||
if (!state[networkId]?.[hash]) {
|
||||
throw Error('Attempted to check non-existent transaction.')
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
[networkId]: {
|
||||
...(safeAccess(state, [networkId]) || {}),
|
||||
...state[networkId],
|
||||
[hash]: {
|
||||
...(safeAccess(state, [networkId, hash]) || {}),
|
||||
[BLOCK_NUMBER_CHECKED]: blockNumber
|
||||
...state[networkId]?.[hash],
|
||||
blockNumberChecked: blockNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,17 +68,17 @@ function reducer(state, { type, payload }) {
|
||||
case FINALIZE: {
|
||||
const { networkId, hash, receipt } = payload
|
||||
|
||||
if (safeAccess(state, [networkId, hash]) === null) {
|
||||
if (!state[networkId]?.[hash]) {
|
||||
throw Error('Attempted to finalize non-existent transaction.')
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
[networkId]: {
|
||||
...(safeAccess(state, [networkId]) || {}),
|
||||
...state[networkId],
|
||||
[hash]: {
|
||||
...(safeAccess(state, [networkId, hash]) || {}),
|
||||
[RECEIPT]: receipt
|
||||
...state[networkId]?.[hash],
|
||||
receipt
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,7 +117,7 @@ export function Updater() {
|
||||
const globalBlockNumber = useBlockNumber()
|
||||
|
||||
const [state, { check, finalize }] = useTransactionsContext()
|
||||
const allTransactions = safeAccess(state, [chainId]) || {}
|
||||
const allTransactions = state[chainId] ?? {}
|
||||
|
||||
// show popup on confirm
|
||||
const [, addPopup] = usePopups()
|
||||
@ -125,7 +127,7 @@ export function Updater() {
|
||||
let stale = false
|
||||
Object.keys(allTransactions)
|
||||
.filter(
|
||||
hash => !allTransactions[hash][RECEIPT] && allTransactions[hash][BLOCK_NUMBER_CHECKED] !== globalBlockNumber
|
||||
hash => !allTransactions[hash].receipt && allTransactions[hash].blockNumberChecked !== globalBlockNumber
|
||||
)
|
||||
.forEach(hash => {
|
||||
library
|
||||
@ -138,12 +140,22 @@ export function Updater() {
|
||||
finalize(chainId, hash, receipt)
|
||||
// add success or failure popup
|
||||
if (receipt.status === 1) {
|
||||
addPopup(<TxnPopup popKey={1} hash={hash} success={true}
|
||||
summary={allTransactions[hash]?.response?.summary}/>)
|
||||
addPopup(
|
||||
<TxnPopup
|
||||
popKey={1}
|
||||
hash={hash}
|
||||
success={true}
|
||||
summary={allTransactions[hash]?.response?.summary}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
addPopup(
|
||||
<TxnPopup popKey={2} hash={hash} success={false}
|
||||
summary={allTransactions[hash]?.response?.summary}/>
|
||||
<TxnPopup
|
||||
popKey={2}
|
||||
hash={hash}
|
||||
success={false}
|
||||
summary={allTransactions[hash]?.response?.summary}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -173,11 +185,11 @@ export function useTransactionAdder() {
|
||||
if (!(chainId || chainId === 0)) {
|
||||
throw Error(`Invalid networkId '${chainId}`)
|
||||
}
|
||||
const hash = safeAccess(response, ['hash'])
|
||||
const hash = response?.hash
|
||||
if (!hash) {
|
||||
throw Error('No transaction hash found.')
|
||||
}
|
||||
add(chainId, hash, { ...response, [CUSTOM_DATA]: customData, [SUMMARY]: summary })
|
||||
add(chainId, hash, { ...response, customData: customData, summary })
|
||||
},
|
||||
[chainId, add]
|
||||
)
|
||||
@ -188,18 +200,18 @@ export function useAllTransactions() {
|
||||
|
||||
const [state] = useTransactionsContext()
|
||||
|
||||
return safeAccess(state, [chainId]) || {}
|
||||
return state[chainId] || {}
|
||||
}
|
||||
|
||||
export function usePendingApproval(tokenAddress) {
|
||||
const allTransactions = useAllTransactions()
|
||||
return (
|
||||
Object.keys(allTransactions).filter(hash => {
|
||||
if (allTransactions[hash][RECEIPT]) {
|
||||
if (allTransactions[hash]?.receipt) {
|
||||
return false
|
||||
} else if (!allTransactions[hash][RESPONSE]) {
|
||||
} else if (!allTransactions[hash]?.response) {
|
||||
return false
|
||||
} else if (allTransactions[hash][RESPONSE][CUSTOM_DATA].approval !== tokenAddress) {
|
||||
} else if (allTransactions[hash]?.response?.customData?.approval !== tokenAddress) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
|
@ -6,8 +6,6 @@ export default function useInterval(callback: () => void, delay: null | number)
|
||||
// Remember the latest callback.
|
||||
useEffect(() => {
|
||||
savedCallback.current = callback
|
||||
return () => {
|
||||
}
|
||||
}, [callback])
|
||||
|
||||
// Set up the interval.
|
||||
@ -17,10 +15,8 @@ export default function useInterval(callback: () => void, delay: null | number)
|
||||
}
|
||||
|
||||
if (delay !== null) {
|
||||
let id = setInterval(tick, delay)
|
||||
const id = setInterval(tick, delay)
|
||||
return () => clearInterval(id)
|
||||
}
|
||||
return () => {
|
||||
}
|
||||
}, [delay])
|
||||
}
|
||||
}
|
||||
|
@ -99,21 +99,21 @@ export default function App() {
|
||||
<BrowserRouter>
|
||||
<AppWrapper>
|
||||
<HeaderWrapper>
|
||||
<Header/>
|
||||
<Header />
|
||||
</HeaderWrapper>
|
||||
<BodyWrapper>
|
||||
<Popups/>
|
||||
<Popups />
|
||||
<Body>
|
||||
<Web3ReactManager>
|
||||
<NavigationTabs/>
|
||||
<NavigationTabs />
|
||||
{/* this Suspense is for route code-splitting */}
|
||||
<Switch>
|
||||
<Route exact strict path="/" render={() => <Redirect to="/swap"/>}/>
|
||||
<Route exact strict path="/swap" component={() => <Swap params={params}/>}/>
|
||||
<Route exact strict path="/send" component={() => <Send params={params}/>}/>
|
||||
<Route exact strict path="/find" component={() => <Find/>}/>
|
||||
<Route exact strict path="/create" component={() => <Create/>}/>
|
||||
<Route exact strict path="/pool" component={() => <Pool/>}/>
|
||||
<Route exact strict path="/" render={() => <Redirect to="/swap" />} />
|
||||
<Route exact strict path="/swap" component={() => <Swap params={params} />} />
|
||||
<Route exact strict path="/send" component={() => <Send params={params} />} />
|
||||
<Route exact strict path="/find" component={() => <Find />} />
|
||||
<Route exact strict path="/create" component={() => <Create />} />
|
||||
<Route exact strict path="/pool" component={() => <Pool />} />
|
||||
<Route
|
||||
exact
|
||||
strict
|
||||
@ -127,7 +127,7 @@ export default function App() {
|
||||
if (t0 && t1) {
|
||||
return <Add token0={t0} token1={t1} />
|
||||
} else {
|
||||
return <Redirect to="/pool"/>
|
||||
return <Redirect to="/pool" />
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@ -142,19 +142,19 @@ export default function App() {
|
||||
const t1 =
|
||||
tokens?.[1] === 'ETH' ? 'ETH' : isAddress(tokens?.[1]) ? isAddress(tokens[1]) : undefined
|
||||
if (t0 && t1) {
|
||||
return <Remove token0={t0} token1={t1}/>
|
||||
return <Remove token0={t0} token1={t1} />
|
||||
} else {
|
||||
return <Redirect to="/pool"/>
|
||||
return <Redirect to="/pool" />
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Redirect to="/"/>
|
||||
<Redirect to="/" />
|
||||
</Switch>
|
||||
</Web3ReactManager>
|
||||
</Body>
|
||||
<Footer/>
|
||||
<Footer />
|
||||
</BodyWrapper>
|
||||
<StyledRed/>
|
||||
<StyledRed />
|
||||
</AppWrapper>
|
||||
</BrowserRouter>
|
||||
</Suspense>
|
||||
|
@ -675,7 +675,7 @@ function AddLiquidity({ token0, token1 }: AddLiquidityProps) {
|
||||
)
|
||||
}
|
||||
|
||||
const pendingText: string = `Supplying ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${
|
||||
const pendingText = `Supplying ${parsedAmounts[Field.INPUT]?.toSignificant(6)} ${
|
||||
tokens[Field.INPUT]?.symbol
|
||||
} ${'and'} ${parsedAmounts[Field.OUTPUT]?.toSignificant(6)} ${tokens[Field.OUTPUT]?.symbol}`
|
||||
|
||||
|
@ -179,15 +179,15 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
|
||||
const TokensDeposited: { [field: number]: TokenAmount } = {
|
||||
[Field.TOKEN0]:
|
||||
pair &&
|
||||
totalPoolTokens &&
|
||||
userLiquidity &&
|
||||
pair.getLiquidityValue(tokens[Field.TOKEN0], totalPoolTokens, userLiquidity, false),
|
||||
pair &&
|
||||
totalPoolTokens &&
|
||||
userLiquidity &&
|
||||
pair.getLiquidityValue(tokens[Field.TOKEN0], totalPoolTokens, userLiquidity, false),
|
||||
[Field.TOKEN1]:
|
||||
pair &&
|
||||
totalPoolTokens &&
|
||||
userLiquidity &&
|
||||
pair.getLiquidityValue(tokens[Field.TOKEN1], totalPoolTokens, userLiquidity, false)
|
||||
pair &&
|
||||
totalPoolTokens &&
|
||||
userLiquidity &&
|
||||
pair.getLiquidityValue(tokens[Field.TOKEN1], totalPoolTokens, userLiquidity, false)
|
||||
}
|
||||
|
||||
const route: Route = pair
|
||||
@ -282,7 +282,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
)
|
||||
}
|
||||
|
||||
const handleSliderChange = (newPercent) => {
|
||||
const handleSliderChange = newPercent => {
|
||||
onUserInput(
|
||||
Field.LIQUIDITY,
|
||||
new TokenAmount(
|
||||
@ -425,6 +425,13 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
})
|
||||
}
|
||||
|
||||
function resetModalState() {
|
||||
setSigned(false)
|
||||
setSigInputs(null)
|
||||
setAttemptedRemoval(false)
|
||||
setPendingConfirmation(true)
|
||||
}
|
||||
|
||||
async function onRemove() {
|
||||
setAttemptedRemoval(true)
|
||||
const router = getRouterContract(chainId, library, account)
|
||||
@ -482,13 +489,13 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
addTransaction(
|
||||
response,
|
||||
'Remove ' +
|
||||
parsedAmounts[Field.TOKEN0]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.TOKEN0]?.symbol +
|
||||
' and ' +
|
||||
parsedAmounts[Field.TOKEN1]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.TOKEN1]?.symbol
|
||||
parsedAmounts[Field.TOKEN0]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.TOKEN0]?.symbol +
|
||||
' and ' +
|
||||
parsedAmounts[Field.TOKEN1]?.toSignificant(3) +
|
||||
' ' +
|
||||
tokens[Field.TOKEN1]?.symbol
|
||||
)
|
||||
})
|
||||
)
|
||||
@ -499,13 +506,6 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
})
|
||||
}
|
||||
|
||||
function resetModalState() {
|
||||
setSigned(false)
|
||||
setSigInputs(null)
|
||||
setAttemptedRemoval(false)
|
||||
setPendingConfirmation(true)
|
||||
}
|
||||
|
||||
function modalHeader() {
|
||||
return (
|
||||
<AutoColumn gap={'sm'} style={{ marginTop: '20px' }}>
|
||||
@ -514,21 +514,21 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
{!!parsedAmounts[Field.TOKEN0] && parsedAmounts[Field.TOKEN0].toSignificant(6)}
|
||||
</Text>
|
||||
<RowFixed gap="4px">
|
||||
<TokenLogo address={tokens[Field.TOKEN0]?.address} size={'24px'}/>
|
||||
<TokenLogo address={tokens[Field.TOKEN0]?.address} size={'24px'} />
|
||||
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
|
||||
{tokens[Field.TOKEN0]?.symbol || ''}
|
||||
</Text>
|
||||
</RowFixed>
|
||||
</RowBetween>
|
||||
<RowFixed>
|
||||
<Plus size="16" color={'#888D9B'}/>
|
||||
<Plus size="16" color={'#888D9B'} />
|
||||
</RowFixed>
|
||||
<RowBetween align="flex-end">
|
||||
<Text fontSize={24} fontWeight={600}>
|
||||
{!!parsedAmounts[Field.TOKEN1] && parsedAmounts[Field.TOKEN1].toSignificant(6)}
|
||||
</Text>
|
||||
<RowFixed gap="4px">
|
||||
<TokenLogo address={tokens[Field.TOKEN1]?.address} size={'24px'}/>
|
||||
<TokenLogo address={tokens[Field.TOKEN1]?.address} size={'24px'} />
|
||||
<Text fontSize={24} fontWeight={500} style={{ marginLeft: '10px' }}>
|
||||
{tokens[Field.TOKEN1]?.symbol || ''}
|
||||
</Text>
|
||||
@ -596,7 +596,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
)
|
||||
}
|
||||
|
||||
const pendingText: string = `Removing ${parsedAmounts[Field.TOKEN0]?.toSignificant(6)} ${
|
||||
const pendingText = `Removing ${parsedAmounts[Field.TOKEN0]?.toSignificant(6)} ${
|
||||
tokens[Field.TOKEN0]?.symbol
|
||||
} and ${parsedAmounts[Field.TOKEN1]?.toSignificant(6)} ${tokens[Field.TOKEN1]?.symbol}`
|
||||
|
||||
@ -637,7 +637,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
</Text>
|
||||
</Row>
|
||||
{!showAdvanced && (
|
||||
<Slider value={parseFloat(derivedPerecent)} onChange={handleSliderChange} override={override}/>
|
||||
<Slider value={parseFloat(derivedPerecent)} onChange={handleSliderChange} override={override} />
|
||||
)}
|
||||
{!showAdvanced && (
|
||||
<RowBetween>
|
||||
@ -660,7 +660,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
{!showAdvanced && (
|
||||
<>
|
||||
<ColumnCenter>
|
||||
<ArrowDown size="16" color="#888D9B"/>
|
||||
<ArrowDown size="16" color="#888D9B" />
|
||||
</ColumnCenter>{' '}
|
||||
<LightCard>
|
||||
<AutoColumn gap="10px">
|
||||
@ -669,7 +669,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
{formattedAmounts[Field.TOKEN0] ? formattedAmounts[Field.TOKEN0] : '-'}
|
||||
</Text>
|
||||
<RowFixed>
|
||||
<TokenLogo address={tokens[Field.TOKEN0]?.address || ''} style={{ marginRight: '12px' }}/>
|
||||
<TokenLogo address={tokens[Field.TOKEN0]?.address || ''} style={{ marginRight: '12px' }} />
|
||||
<Text fontSize={24} fontWeight={500}>
|
||||
{tokens[Field.TOKEN0]?.symbol}
|
||||
</Text>
|
||||
@ -680,7 +680,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
{formattedAmounts[Field.TOKEN1] ? formattedAmounts[Field.TOKEN1] : '-'}
|
||||
</Text>
|
||||
<RowFixed>
|
||||
<TokenLogo address={tokens[Field.TOKEN1]?.address || ''} style={{ marginRight: '12px' }}/>
|
||||
<TokenLogo address={tokens[Field.TOKEN1]?.address || ''} style={{ marginRight: '12px' }} />
|
||||
<Text fontSize={24} fontWeight={500}>
|
||||
{tokens[Field.TOKEN1]?.symbol}
|
||||
</Text>
|
||||
@ -706,7 +706,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
inputId="liquidityAmount"
|
||||
/>
|
||||
<ColumnCenter>
|
||||
<ArrowDown size="16" color="#888D9B"/>
|
||||
<ArrowDown size="16" color="#888D9B" />
|
||||
</ColumnCenter>
|
||||
<CurrencyInputPanel
|
||||
field={Field.TOKEN0}
|
||||
@ -720,7 +720,7 @@ export default function RemoveLiquidity({ token0, token1 }) {
|
||||
inputId="removeLiquidityToken0"
|
||||
/>
|
||||
<ColumnCenter>
|
||||
<Plus size="16" color="#888D9B"/>
|
||||
<Plus size="16" color="#888D9B" />
|
||||
</ColumnCenter>
|
||||
<CurrencyInputPanel
|
||||
field={Field.TOKEN1}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState, useContext } from 'react'
|
||||
import styled, { ThemeContext } from 'styled-components'
|
||||
import { JSBI } from '@uniswap/sdk'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom'
|
||||
|
||||
import Question from '../../components/Question'
|
||||
import SearchModal from '../../components/SearchModal'
|
||||
@ -29,7 +29,7 @@ const FixedBottom = styled.div`
|
||||
width: 100%;
|
||||
`
|
||||
|
||||
function Supply({ history }) {
|
||||
function Supply({ history }: RouteComponentProps) {
|
||||
const { account } = useWeb3React()
|
||||
const [showPoolSearch, setShowPoolSearch] = useState(false)
|
||||
|
||||
@ -42,7 +42,7 @@ function Supply({ history }) {
|
||||
useAccountLPBalances(account)
|
||||
|
||||
const filteredExchangeList = Object.keys(allPairs)
|
||||
.filter((pairAddress, i) => {
|
||||
.filter(pairAddress => {
|
||||
return (
|
||||
allBalances &&
|
||||
allBalances[account] &&
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import ExchangePage from '../../components/ExchangePage'
|
||||
import { QueryParams } from '../../utils'
|
||||
|
||||
export default function Swap({ params }) {
|
||||
export default function Swap({ params }: { params: QueryParams }) {
|
||||
return <ExchangePage sendingInput={false} params={params} />
|
||||
}
|
||||
|
@ -2,10 +2,9 @@ import styled, { keyframes } from 'styled-components'
|
||||
import { darken } from 'polished'
|
||||
import { X } from 'react-feather'
|
||||
|
||||
export const Button = styled.button.attrs<{ warning: boolean }, { backgroundColor: string }>(
|
||||
({ warning, theme }) => ({
|
||||
backgroundColor: warning ? theme.red1 : theme.blue1
|
||||
}))`
|
||||
export const Button = styled.button.attrs<{ warning: boolean }, { backgroundColor: string }>(({ warning, theme }) => ({
|
||||
backgroundColor: warning ? theme.red1 : theme.blue1
|
||||
}))`
|
||||
padding: 1rem 2rem 1rem 2rem;
|
||||
border-radius: 3rem;
|
||||
cursor: pointer;
|
||||
@ -33,7 +32,7 @@ export const Button = styled.button.attrs<{ warning: boolean }, { backgroundColo
|
||||
}
|
||||
`
|
||||
|
||||
export const CloseIcon = styled(X)<{ onClick: () => void}>`
|
||||
export const CloseIcon = styled(X)<{ onClick: () => void }>`
|
||||
cursor: pointer;
|
||||
`
|
||||
|
||||
|
@ -3,12 +3,12 @@ import styled, {
|
||||
ThemeProvider as StyledComponentsThemeProvider,
|
||||
createGlobalStyle,
|
||||
css,
|
||||
DefaultTheme
|
||||
} from 'styled-components'
|
||||
import { getQueryParam, checkSupportedTheme } from '../utils'
|
||||
import { SUPPORTED_THEMES } from '../constants'
|
||||
import { useDarkModeManager } from '../contexts/LocalStorage'
|
||||
import { Text } from 'rebass'
|
||||
import { UniswapTheme } from './styled'
|
||||
|
||||
export * from './components'
|
||||
|
||||
@ -19,20 +19,95 @@ const MEDIA_WIDTHS = {
|
||||
upToLarge: 1280
|
||||
}
|
||||
|
||||
const mediaWidthTemplates: { [width in keyof typeof MEDIA_WIDTHS]: typeof css } =
|
||||
Object.keys(MEDIA_WIDTHS)
|
||||
.reduce((accumulator, size) => {
|
||||
accumulator[size] = (a, b, c) => css`
|
||||
@media (max-width: ${MEDIA_WIDTHS[size]}px) {
|
||||
${css(a, b, c)}
|
||||
}
|
||||
`
|
||||
return accumulator
|
||||
}, {}) as any
|
||||
const mediaWidthTemplates: { [width in keyof typeof MEDIA_WIDTHS]: typeof css } = Object.keys(MEDIA_WIDTHS).reduce(
|
||||
(accumulator, size) => {
|
||||
accumulator[size] = (a, b, c) => css`
|
||||
@media (max-width: ${MEDIA_WIDTHS[size]}px) {
|
||||
${css(a, b, c)}
|
||||
}
|
||||
`
|
||||
return accumulator
|
||||
},
|
||||
{}
|
||||
) as any
|
||||
|
||||
const white = '#FFFFFF'
|
||||
const black = '#000000'
|
||||
|
||||
export function theme(darkMode: boolean): DefaultTheme {
|
||||
return {
|
||||
// base
|
||||
white,
|
||||
black,
|
||||
|
||||
// text
|
||||
text1: darkMode ? '#FFFFFF' : '#000000',
|
||||
text2: darkMode ? '#CED0D9' : '#565A69',
|
||||
text3: darkMode ? '#6C7284' : '#888D9B',
|
||||
text4: darkMode ? '#565A69' : '#C3C5CB',
|
||||
text5: '#EDEEF2',
|
||||
|
||||
// backgrounds / greys
|
||||
bg1: darkMode ? '#212429' : '#FFFFFF',
|
||||
bg2: darkMode ? '#2C2F36' : '#F7F8FA',
|
||||
bg3: darkMode ? '#40444F' : '#EDEEF2',
|
||||
bg4: darkMode ? '#565A69' : '#CED0D9',
|
||||
bg5: darkMode ? '#565A69' : '#888D9B',
|
||||
|
||||
modalBG: darkMode ? 'rgba(0,0,0,0.85)' : 'rgba(0,0,0,0.6)',
|
||||
advancedBG: darkMode ? 'rgba(0,0,0,0.15)' : 'rgba(255,255,255,0.6)',
|
||||
|
||||
//blues
|
||||
blue1: darkMode ? '#2172E5' : '#ff007a',
|
||||
blue2: darkMode ? '#3680E7' : '#1966D2',
|
||||
blue3: darkMode ? '#4D8FEA' : '#165BBB',
|
||||
// blue4: darkMode ? '#153d6f70' : '#C4D9F8',
|
||||
// blue5: darkMode ? '#153d6f70' : '#EBF4FF',
|
||||
blue4: darkMode ? '#153d6f70' : '#F6DDE8',
|
||||
blue5: darkMode ? '#153d6f70' : '#FDEAF1',
|
||||
|
||||
buttonSecondaryText: darkMode ? '#6da8ff' : '#ff007a',
|
||||
|
||||
// blue1: '#ff007a',
|
||||
// blue4: '#F6DDE8',
|
||||
// blue5: '#FDEAF1',
|
||||
|
||||
// pinks
|
||||
pink1: '#DC6BE5',
|
||||
pink2: darkMode ? '#2172E5' : '#ff007a',
|
||||
pink3: darkMode ? '#17000b26' : '#F6DDE8',
|
||||
pink4: darkMode ? '#17000b26' : '#FDEAF1',
|
||||
|
||||
// other
|
||||
red1: '#FF6871',
|
||||
green1: '#27AE60',
|
||||
yellow1: '#FFE270',
|
||||
yellow2: '#F3841E',
|
||||
|
||||
grids: {
|
||||
sm: 8,
|
||||
md: 12,
|
||||
lg: 24
|
||||
},
|
||||
|
||||
//shadows
|
||||
shadow1: darkMode ? '#000' : '#2F80ED',
|
||||
|
||||
// media queries
|
||||
mediaWidth: mediaWidthTemplates,
|
||||
|
||||
// css snippets
|
||||
flexColumnNoWrap: css`
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
`,
|
||||
flexRowNoWrap: css`
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
export default function ThemeProvider({ children }) {
|
||||
const [darkMode, toggleDarkMode] = useDarkModeManager()
|
||||
const themeURL = checkSupportedTheme(getQueryParam(window.location, 'theme'))
|
||||
@ -40,8 +115,8 @@ export default function ThemeProvider({ children }) {
|
||||
? themeURL.toUpperCase() === SUPPORTED_THEMES.DARK
|
||||
? true
|
||||
: themeURL.toUpperCase() === SUPPORTED_THEMES.LIGHT
|
||||
? false
|
||||
: darkMode
|
||||
? false
|
||||
: darkMode
|
||||
: darkMode
|
||||
useEffect(() => {
|
||||
toggleDarkMode(themeToRender)
|
||||
@ -49,78 +124,6 @@ export default function ThemeProvider({ children }) {
|
||||
return <StyledComponentsThemeProvider theme={theme(themeToRender)}>{children}</StyledComponentsThemeProvider>
|
||||
}
|
||||
|
||||
export const theme: (darkMode: boolean) => UniswapTheme = darkMode => ({
|
||||
// base
|
||||
white,
|
||||
black,
|
||||
|
||||
// text
|
||||
text1: darkMode ? '#FFFFFF' : '#000000',
|
||||
text2: darkMode ? '#CED0D9' : '#565A69',
|
||||
text3: darkMode ? '#6C7284' : '#888D9B',
|
||||
text4: darkMode ? '#565A69' : '#C3C5CB',
|
||||
text5: '#EDEEF2',
|
||||
|
||||
// backgrounds / greys
|
||||
bg1: darkMode ? '#212429' : '#FFFFFF',
|
||||
bg2: darkMode ? '#2C2F36' : '#F7F8FA',
|
||||
bg3: darkMode ? '#40444F' : '#EDEEF2',
|
||||
bg4: darkMode ? '#565A69' : '#CED0D9',
|
||||
bg5: darkMode ? '#565A69' : '#888D9B',
|
||||
|
||||
modalBG: darkMode ? 'rgba(0,0,0,0.85)' : 'rgba(0,0,0,0.6)',
|
||||
advancedBG: darkMode ? 'rgba(0,0,0,0.15)' : 'rgba(255,255,255,0.6)',
|
||||
|
||||
//blues
|
||||
blue1: darkMode ? '#2172E5' : '#ff007a',
|
||||
blue2: darkMode ? '#3680E7' : '#1966D2',
|
||||
blue3: darkMode ? '#4D8FEA' : '#165BBB',
|
||||
// blue4: darkMode ? '#153d6f70' : '#C4D9F8',
|
||||
// blue5: darkMode ? '#153d6f70' : '#EBF4FF',
|
||||
blue4: darkMode ? '#153d6f70' : '#F6DDE8',
|
||||
blue5: darkMode ? '#153d6f70' : '#FDEAF1',
|
||||
|
||||
buttonSecondaryText: darkMode ? '#6da8ff' : '#ff007a',
|
||||
|
||||
// blue1: '#ff007a',
|
||||
// blue4: '#F6DDE8',
|
||||
// blue5: '#FDEAF1',
|
||||
|
||||
// pinks
|
||||
pink1: '#DC6BE5',
|
||||
pink2: darkMode ? '#2172E5' : '#ff007a',
|
||||
pink3: darkMode ? '#17000b26' : '#F6DDE8',
|
||||
pink4: darkMode ? '#17000b26' : '#FDEAF1',
|
||||
|
||||
// other
|
||||
red1: '#FF6871',
|
||||
green1: '#27AE60',
|
||||
yellow1: '#FFE270',
|
||||
yellow2: '#F3841E',
|
||||
|
||||
grids: {
|
||||
sm: 8,
|
||||
md: 12,
|
||||
lg: 24
|
||||
},
|
||||
|
||||
//shadows
|
||||
shadow1: darkMode ? '#000' : '#2F80ED',
|
||||
|
||||
// media queries
|
||||
mediaWidth: mediaWidthTemplates,
|
||||
|
||||
// css snippets
|
||||
flexColumnNoWrap: css`
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
`,
|
||||
flexRowNoWrap: css`
|
||||
display: flex;
|
||||
flex-flow: row nowrap;
|
||||
`
|
||||
})
|
||||
|
||||
const TextWrapper = styled(Text)`
|
||||
color = ${({ color, theme }) => theme[color]}
|
||||
`
|
||||
|
118
src/theme/styled.d.ts
vendored
118
src/theme/styled.d.ts
vendored
@ -1,66 +1,62 @@
|
||||
import { css, FlattenSimpleInterpolation } from 'styled-components'
|
||||
|
||||
export interface UniswapTheme {
|
||||
// base
|
||||
white: string
|
||||
black: string
|
||||
|
||||
// text
|
||||
text1: string
|
||||
text2: string
|
||||
text3: string
|
||||
text4: string
|
||||
text5: string
|
||||
|
||||
// backgrounds / greys
|
||||
bg1: string
|
||||
bg2: string
|
||||
bg3: string
|
||||
bg4: string
|
||||
bg5: string
|
||||
|
||||
modalBG: string
|
||||
advancedBG: string
|
||||
|
||||
//blues
|
||||
blue1: string
|
||||
blue2: string
|
||||
blue3: string
|
||||
blue4: string
|
||||
blue5: string
|
||||
|
||||
buttonSecondaryText: string
|
||||
|
||||
// pinks
|
||||
pink1: string
|
||||
pink2: string
|
||||
pink3: string
|
||||
pink4: string
|
||||
|
||||
// other
|
||||
red1: string
|
||||
green1: string
|
||||
yellow1: string
|
||||
yellow2: string
|
||||
|
||||
grids: {
|
||||
sm: number,
|
||||
md: number,
|
||||
lg: number
|
||||
},
|
||||
|
||||
// shadows
|
||||
shadow1: string
|
||||
|
||||
// media queries
|
||||
mediaWidth: { [width in keyof typeof MEDIA_WIDTHS]: typeof css },
|
||||
// css snippets
|
||||
flexColumnNoWrap: FlattenSimpleInterpolation
|
||||
flexRowNoWrap: FlattenSimpleInterpolation
|
||||
}
|
||||
|
||||
declare module 'styled-components' {
|
||||
export interface DefaultTheme extends UniswapTheme {
|
||||
export interface DefaultTheme {
|
||||
// base
|
||||
white: string
|
||||
black: string
|
||||
|
||||
// text
|
||||
text1: string
|
||||
text2: string
|
||||
text3: string
|
||||
text4: string
|
||||
text5: string
|
||||
|
||||
// backgrounds / greys
|
||||
bg1: string
|
||||
bg2: string
|
||||
bg3: string
|
||||
bg4: string
|
||||
bg5: string
|
||||
|
||||
modalBG: string
|
||||
advancedBG: string
|
||||
|
||||
//blues
|
||||
blue1: string
|
||||
blue2: string
|
||||
blue3: string
|
||||
blue4: string
|
||||
blue5: string
|
||||
|
||||
buttonSecondaryText: string
|
||||
|
||||
// pinks
|
||||
pink1: string
|
||||
pink2: string
|
||||
pink3: string
|
||||
pink4: string
|
||||
|
||||
// other
|
||||
red1: string
|
||||
green1: string
|
||||
yellow1: string
|
||||
yellow2: string
|
||||
|
||||
grids: {
|
||||
sm: number
|
||||
md: number
|
||||
lg: number
|
||||
}
|
||||
|
||||
// shadows
|
||||
shadow1: string
|
||||
|
||||
// media queries
|
||||
mediaWidth: { [width in keyof typeof MEDIA_WIDTHS]: typeof css }
|
||||
// css snippets
|
||||
flexColumnNoWrap: FlattenSimpleInterpolation
|
||||
flexRowNoWrap: FlattenSimpleInterpolation
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,4 +9,4 @@ describe('utils', () => {
|
||||
expect(getEtherscanLink(1, 'abc', 'address')).toEqual('https://etherscan.io/address/abc')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -12,20 +12,19 @@ import { ROUTER_ADDRESS, SUPPORTED_THEMES } from '../constants'
|
||||
import ERC20_ABI from '../constants/abis/erc20.json'
|
||||
import ERC20_BYTES32_ABI from '../constants/abis/erc20_bytes32.json'
|
||||
|
||||
export function isAddress(value: any): string | false {
|
||||
try {
|
||||
return getAddress(value.toLowerCase())
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export enum ERROR_CODES {
|
||||
TOKEN_SYMBOL = 1,
|
||||
TOKEN_DECIMALS = 2
|
||||
}
|
||||
|
||||
export function safeAccess(object, path) {
|
||||
return object
|
||||
? path.reduce(
|
||||
(accumulator, currentValue) => (accumulator && accumulator[currentValue] ? accumulator[currentValue] : null),
|
||||
object
|
||||
)
|
||||
: null
|
||||
}
|
||||
|
||||
const ETHERSCAN_PREFIXES = {
|
||||
1: '',
|
||||
3: 'ropsten.',
|
||||
@ -49,7 +48,7 @@ export function getEtherscanLink(networkId: 1 | 3 | 4 | 5 | 42 | any, data: stri
|
||||
}
|
||||
|
||||
export function getQueryParam(windowLocation, name) {
|
||||
var q = windowLocation.search.match(new RegExp('[?&]' + name + '=([^&#?]*)'))
|
||||
const q = windowLocation.search.match(new RegExp('[?&]' + name + '=([^&#?]*)'))
|
||||
return q && q[1]
|
||||
}
|
||||
|
||||
@ -122,18 +121,6 @@ export function shortenAddress(address, digits = 4) {
|
||||
return `${address.substring(0, digits + 2)}...${address.substring(42 - digits)}`
|
||||
}
|
||||
|
||||
export function shortenTransactionHash(hash, digits = 4) {
|
||||
return `${hash.substring(0, digits + 2)}...${hash.substring(66 - digits)}`
|
||||
}
|
||||
|
||||
export function isAddress(value: any): string | false {
|
||||
try {
|
||||
return getAddress(value.toLowerCase())
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function calculateGasMargin(value: BigNumber) {
|
||||
return value.mul(BigNumber.from(10000).add(BigNumber.from(1000))).div(BigNumber.from(10000)) // add 10%
|
||||
}
|
||||
|
@ -20,7 +20,8 @@
|
||||
"downlevelIteration": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"types": [
|
||||
"react-spring"
|
||||
"react-spring",
|
||||
"jest"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
|
39
yarn.lock
39
yarn.lock
@ -2630,7 +2630,7 @@
|
||||
dependencies:
|
||||
"@types/yargs-parser" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@^2.10.0":
|
||||
"@typescript-eslint/eslint-plugin@^2.10.0", "@typescript-eslint/eslint-plugin@^2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.31.0.tgz#942c921fec5e200b79593c71fafb1e3f57aa2e36"
|
||||
integrity sha512-iIC0Pb8qDaoit+m80Ln/aaeu9zKQdOLF4SHcGLarSeY1gurW6aU4JsOPMjKQwXlw70MvWKZQc6S2NamA8SJ/gg==
|
||||
@ -2650,7 +2650,7 @@
|
||||
eslint-scope "^5.0.0"
|
||||
eslint-utils "^2.0.0"
|
||||
|
||||
"@typescript-eslint/parser@^2.10.0":
|
||||
"@typescript-eslint/parser@^2.10.0", "@typescript-eslint/parser@^2.31.0":
|
||||
version "2.31.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.31.0.tgz#beddd4e8efe64995108b229b2862cd5752d40d6f"
|
||||
integrity sha512-uph+w6xUOlyV2DLSC6o+fBDzZ5i7+3/TxAsH4h3eC64tlga57oMb96vVlXoMwjR/nN+xyWlsnxtbDkB46M2EPQ==
|
||||
@ -6772,6 +6772,13 @@ escodegen@^1.11.0, escodegen@^1.9.1:
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
eslint-config-prettier@^6.11.0:
|
||||
version "6.11.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1"
|
||||
integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==
|
||||
dependencies:
|
||||
get-stdin "^6.0.0"
|
||||
|
||||
eslint-config-react-app@^5.2.1:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-5.2.1.tgz#698bf7aeee27f0cea0139eaef261c7bf7dd623df"
|
||||
@ -6846,12 +6853,19 @@ eslint-plugin-jsx-a11y@6.2.3:
|
||||
has "^1.0.3"
|
||||
jsx-ast-utils "^2.2.1"
|
||||
|
||||
eslint-plugin-prettier@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.3.tgz#ae116a0fc0e598fdae48743a4430903de5b4e6ca"
|
||||
integrity sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ==
|
||||
dependencies:
|
||||
prettier-linter-helpers "^1.0.0"
|
||||
|
||||
eslint-plugin-react-hooks@^1.6.1:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-1.7.0.tgz#6210b6d5a37205f0b92858f895a4e827020a7d04"
|
||||
integrity sha512-iXTCFcOmlWvw4+TOE8CLWj6yX1GwzT0Y6cUfHHZqWnSk144VmVIRcVGtUAzrLES7C798lmvnt02C7rxaOX1HNA==
|
||||
|
||||
eslint-plugin-react@7.19.0:
|
||||
eslint-plugin-react@7.19.0, eslint-plugin-react@^7.19.0:
|
||||
version "7.19.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666"
|
||||
integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==
|
||||
@ -6904,7 +6918,7 @@ eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
|
||||
integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
|
||||
|
||||
eslint@^6.6.0:
|
||||
eslint@^6.6.0, eslint@^6.8.0:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
|
||||
integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
|
||||
@ -7800,6 +7814,11 @@ fast-deep-equal@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
|
||||
integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
|
||||
|
||||
fast-diff@^1.1.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
||||
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
||||
|
||||
fast-glob@^2.0.2:
|
||||
version "2.2.7"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
|
||||
@ -8376,6 +8395,11 @@ get-own-enumerable-property-symbols@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
|
||||
integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
|
||||
|
||||
get-stdin@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
|
||||
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
|
||||
|
||||
get-stream@^2.2.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de"
|
||||
@ -13448,6 +13472,13 @@ prepend-http@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
|
||||
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
|
||||
|
||||
prettier-linter-helpers@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
|
||||
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
|
||||
dependencies:
|
||||
fast-diff "^1.1.2"
|
||||
|
||||
prettier@^1.17.0:
|
||||
version "1.19.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
|
||||
|
Loading…
Reference in New Issue
Block a user