diff --git a/package.json b/package.json index 7ed1fb15ad..0995b6b61c 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "@reach/tooltip": "^0.2.0", "copy-to-clipboard": "^3.2.0", "escape-string-regexp": "^2.0.0", - "ethers": "^4.0.27", + "ethers": "^4.0.28", "i18next": "^15.0.9", "i18next-browser-languagedetector": "^3.0.1", "i18next-xhr-backend": "^2.0.1", diff --git a/public/locales/en.json b/public/locales/en.json index 1ae9ab30f5..81d36251ee 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -6,7 +6,9 @@ "installMetamask": "Please visit us after installing Metamask on Chrome or Brave.", "disconnected": "Disconnected", "swap": "Swap", + "swapAnyway": "Swap Anyway", "send": "Send", + "sendAnyway": "Send Anyway", "pool": "Pool", "betaWarning": "This project is in beta. Use at your own risk.", "input": "Input", @@ -28,6 +30,7 @@ "transactionDetails": "Transaction Details", "hideDetails": "Hide Details", "slippageWarning": "Slippage Warning", + "highSlippageWarning": "High Slippage Warning", "youAreSelling": "You are selling", "orTransFail": "or the transaction will fail.", "youWillReceive": "You will receive at least", diff --git a/src/components/ContextualInfoNew/index.js b/src/components/ContextualInfoNew/index.js index 3edf3fcf9c..ead9b6bade 100644 --- a/src/components/ContextualInfoNew/index.js +++ b/src/components/ContextualInfoNew/index.js @@ -1,5 +1,6 @@ import React, { useState } from 'react' -import styled from 'styled-components' +import styled, { css } from 'styled-components' +import { transparentize } from 'polished' import { ReactComponent as Dropup } from '../../assets/images/dropup-blue.svg' import { ReactComponent as Dropdown } from '../../assets/images/dropdown-blue.svg' @@ -23,10 +24,6 @@ const SummaryWrapperContainer = styled.div` justify-content: center; font-size: 0.75rem; - span { - margin-right: 12px; - } - img { height: 0.75rem; width: 0.75rem; @@ -42,13 +39,33 @@ const Details = styled.div` ` const ErrorSpan = styled.span` + margin-right: 12px; + color: ${({ isError, theme }) => isError && theme.salmonRed}; + ${({ slippageWarning, highSlippageWarning, theme }) => + highSlippageWarning + ? css` + color: ${theme.salmonRed}; + font-weight: 600; + ` + : slippageWarning && + css` + background-color: ${transparentize(0.6, theme.warningYellow)}; + font-weight: 600; + padding: 0.25rem; + `} ` const WrappedDropup = ({ isError, ...rest }) => const ColoredDropup = styled(WrappedDropup)` path { stroke: ${({ isError, theme }) => isError && theme.salmonRed}; + + ${({ highSlippageWarning, theme }) => + highSlippageWarning && + css` + stroke: ${theme.salmonRed}; + `} } ` @@ -56,6 +73,12 @@ const WrappedDropdown = ({ isError, ...rest }) => const ColoredDropdown = styled(WrappedDropdown)` path { stroke: ${({ isError, theme }) => isError && theme.salmonRed}; + + ${({ highSlippageWarning, theme }) => + highSlippageWarning && + css` + stroke: ${theme.salmonRed}; + `} } ` @@ -65,7 +88,9 @@ export default function ContextualInfo({ contextualInfo = '', allowExpand = false, renderTransactionDetails = () => {}, - isError = false + isError = false, + slippageWarning, + highSlippageWarning }) { const [showDetails, setShowDetails] = useState(false) @@ -75,10 +100,19 @@ export default function ContextualInfo({ <> setShowDetails(s => !s)}> <> - + + {(slippageWarning || highSlippageWarning) && ( + + ⚠️ + + )} {contextualInfo ? contextualInfo : showDetails ? closeDetailsText : openDetailsText} - {showDetails ? : } + {showDetails ? ( + + ) : ( + + )} {showDetails &&
{renderTransactionDetails()}
} diff --git a/src/components/CurrencyInputPanel/index.js b/src/components/CurrencyInputPanel/index.js index 5aba0f89d1..99defbd215 100644 --- a/src/components/CurrencyInputPanel/index.js +++ b/src/components/CurrencyInputPanel/index.js @@ -236,7 +236,7 @@ export default function CurrencyInputPanel({ gasLimit: calculateGasMargin(estimatedGas, GAS_MARGIN) }) .then(response => { - addTransaction(response) + addTransaction(response, { approval: selectedTokenAddress }) }) }} > diff --git a/src/components/NavigationTabs/index.js b/src/components/NavigationTabs/index.js index cb5adf0cd8..c5f755a50d 100644 --- a/src/components/NavigationTabs/index.js +++ b/src/components/NavigationTabs/index.js @@ -88,18 +88,14 @@ const StyledNavLink = styled(NavLink).attrs({ font-weight: 500; color: ${({ theme }) => theme.royalBlue}; :hover { - box-shadow: 0 0 0.5px 1px ${({ theme }) => darken(0.1, theme.mercuryGray)}; - } + box-shadow: 0 0 0.5px 1px ${({ theme }) => darken(0.1, theme.mercuryGray)}; + } } :hover, :focus { + font-weight: 500; color: ${({ theme }) => darken(0.1, theme.royalBlue)}; - /* box-shadow: 0 0 0.5px 0.5px ${({ theme }) => darken(0.2, theme.mercuryGray)}; */ - } - - :focus { - text-decoration: underline; } ` diff --git a/src/contexts/Allowances.js b/src/contexts/Allowances.js index f1e66dac36..1725e9d26f 100644 --- a/src/contexts/Allowances.js +++ b/src/contexts/Allowances.js @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useReducer, useCallback, useEffect } from 'react' +import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react' import { useWeb3Context } from 'web3-react' import { safeAccess, isAddress, getTokenAllowance } from '../utils' @@ -46,7 +46,11 @@ export default function Provider({ children }) { dispatch({ type: UPDATE, payload: { networkId, address, tokenAddress, spenderAddress, value, blockNumber } }) }, []) - return {children} + return ( + [state, { update }], [state, update])}> + {children} + + ) } export function useAddressAllowance(address, tokenAddress, spenderAddress) { diff --git a/src/contexts/Application.js b/src/contexts/Application.js index 6d2bc2ecb8..0edfa3eec6 100644 --- a/src/contexts/Application.js +++ b/src/contexts/Application.js @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useReducer, useCallback, useEffect } from 'react' +import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react' import { useWeb3Context } from 'web3-react' import { safeAccess } from '../utils' @@ -52,7 +52,13 @@ export default function Provider({ children }) { }, []) return ( - + [state, { dismissBetaMessage, updateBlockNumber }], [ + state, + dismissBetaMessage, + updateBlockNumber + ])} + > {children} ) diff --git a/src/contexts/Balances.js b/src/contexts/Balances.js index 3bbf8619f3..b5193e94a8 100644 --- a/src/contexts/Balances.js +++ b/src/contexts/Balances.js @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useReducer, useCallback, useEffect } from 'react' +import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react' import { useWeb3Context } from 'web3-react' import { safeAccess, isAddress, getEtherBalance, getTokenBalance } from '../utils' @@ -44,7 +44,11 @@ export default function Provider({ children }) { dispatch({ type: UPDATE, payload: { networkId, address, tokenAddress, value, blockNumber } }) }, []) - return {children} + return ( + [state, { update }], [state, update])}> + {children} + + ) } export function useAddressBalance(address, tokenAddress) { diff --git a/src/contexts/Tokens.js b/src/contexts/Tokens.js index c23d91f7af..6095db3795 100644 --- a/src/contexts/Tokens.js +++ b/src/contexts/Tokens.js @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useReducer, useCallback, useEffect } from 'react' +import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react' import { useWeb3Context } from 'web3-react' import { ethers } from 'ethers' @@ -59,6 +59,12 @@ const INITIAL_TOKENS_CONTEXT = { [DECIMALS]: 18, [EXCHANGE_ADDRESS]: '0xF7B5A4b934658025390ff69dB302BC7F2AC4a542' }, + '0xF5DCe57282A584D2746FaF1593d3121Fcac444dC': { + [NAME]: 'Compound Dai', + [SYMBOL]: 'cDAI', + [DECIMALS]: 8, + [EXCHANGE_ADDRESS]: '0x45A2FDfED7F7a2c791fb1bdF6075b83faD821ddE' + }, '0x41e5560054824eA6B0732E656E3Ad64E20e94E45': { [NAME]: 'Civic', [SYMBOL]: 'CVC', @@ -101,12 +107,6 @@ const INITIAL_TOKENS_CONTEXT = { [DECIMALS]: 12, [EXCHANGE_ADDRESS]: '0x4B17685b330307C751B47f33890c8398dF4Fe407' }, - '0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd': { - [NAME]: 'Gemini dollar', - [SYMBOL]: 'GUSD', - [DECIMALS]: 2, - [EXCHANGE_ADDRESS]: '0xD883264737Ed969d2696eE4B4cAF529c2Fc2A141' - }, '0x818Fc6C2Ec5986bc6E2CBf00939d90556aB12ce5': { [NAME]: 'Kin', [SYMBOL]: 'KIN', @@ -125,6 +125,12 @@ const INITIAL_TOKENS_CONTEXT = { [DECIMALS]: 18, [EXCHANGE_ADDRESS]: '0xF173214C720f58E03e194085B1DB28B50aCDeeaD' }, + '0xBBbbCA6A901c926F240b89EacB641d8Aec7AEafD': { + [NAME]: 'LoopringCoin V2', + [SYMBOL]: 'LRC', + [DECIMALS]: 18, + [EXCHANGE_ADDRESS]: '0xA539BAaa3aCA455c986bB1E25301CEF936CE1B65' + }, '0x6c6EE5e31d828De241282B9606C8e98Ea48526E2': { [NAME]: 'HoloToken', [SYMBOL]: 'HOT', @@ -233,12 +239,6 @@ const INITIAL_TOKENS_CONTEXT = { [DECIMALS]: 18, [EXCHANGE_ADDRESS]: '0x1aEC8F11A7E78dC22477e91Ed924Fab46e3A88Fd' }, - '0xEf8a2c1BC94e630463293F71bF5414d13e80F62D': { - [NAME]: 'Synthetix Network Token', - [SYMBOL]: 'SNX', - [DECIMALS]: 18, - [EXCHANGE_ADDRESS]: '0xd9025Ed64BAA7B9046E37fe94670C79fcCB2b5C8' - }, '0x42d6622deCe394b54999Fbd73D108123806f6a18': { [NAME]: 'SPANK', [SYMBOL]: 'SPANK', @@ -293,12 +293,6 @@ const INITIAL_TOKENS_CONTEXT = { [DECIMALS]: 18, [EXCHANGE_ADDRESS]: '0x8dE0d002DC83478f479dC31F76cB0a8aa7CcEa17' }, - '0x05f4a42e251f2d52b8ed15E9FEdAacFcEF1FAD27': { - [NAME]: 'Zilliqa', - [SYMBOL]: 'ZIL', - [DECIMALS]: 12, - [EXCHANGE_ADDRESS]: '0x7dc095A5CF7D6208CC680fA9866F80a53911041a' - }, '0xE41d2489571d322189246DaFA5ebDe1F4699F498': { [NAME]: '0x Protocol Token', [SYMBOL]: 'ZRX', @@ -344,7 +338,11 @@ export default function Provider({ children }) { dispatch({ type: UPDATE, payload: { networkId, tokenAddress, name, symbol, decimals, exchangeAddress } }) }, []) - return {children} + return ( + [state, { update }], [state, update])}> + {children} + + ) } export function useTokenDetails(tokenAddress) { diff --git a/src/contexts/Transactions.js b/src/contexts/Transactions.js index 2cf65a8bde..2d144db98e 100644 --- a/src/contexts/Transactions.js +++ b/src/contexts/Transactions.js @@ -1,11 +1,11 @@ -import React, { createContext, useContext, useReducer, useCallback, useEffect } from 'react' +import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react' import { useWeb3Context } from 'web3-react' -import { ethers } from 'ethers' import { safeAccess } from '../utils' import { useBlockNumber } from './Application' const RESPONSE = 'response' +const CUSTOM_DATA = 'CUSTOM_DATA' const BLOCK_NUMBER_CHECKED = 'BLOCK_NUMBER_CHECKED' const RECEIPT = 'receipt' @@ -94,7 +94,11 @@ export default function Provider({ children }) { }, []) return ( - {children} + [state, { add, check, finalize }], [state, add, check, finalize])} + > + {children} + ) } @@ -145,7 +149,7 @@ export function useTransactionAdder() { const [, { add }] = useTransactionsContext() return useCallback( - response => { + (response, customData = {}) => { if (!(networkId || networkId === 0)) { throw Error(`Invalid networkId '${networkId}`) } @@ -155,7 +159,7 @@ export function useTransactionAdder() { if (!hash) { throw Error('No transaction hash found.') } - add(networkId, hash, response) + add(networkId, hash, { ...response, [CUSTOM_DATA]: customData }) }, [networkId, add] ) @@ -178,12 +182,7 @@ export function usePendingApproval(tokenAddress) { return false } else if (!allTransactions[hash][RESPONSE]) { return false - } else if (allTransactions[hash][RESPONSE].to !== tokenAddress) { - return false - } else if ( - allTransactions[hash][RESPONSE].data.substring(0, 10) !== - ethers.utils.id('approve(address,uint256)').substring(0, 10) - ) { + } else if (allTransactions[hash][RESPONSE][CUSTOM_DATA].approval !== tokenAddress) { return false } else { return true diff --git a/src/pages/Pool/AddLiquidity.js b/src/pages/Pool/AddLiquidity.js index fb1039124c..ad7a6be8d3 100644 --- a/src/pages/Pool/AddLiquidity.js +++ b/src/pages/Pool/AddLiquidity.js @@ -305,7 +305,7 @@ export default function AddLiquidity() { <>
{t('youAreAdding')} {b(`${amountFormatter(inputValueParsed, 18, 4)} ETH`)} {t('and')} {'at most'}{' '} - {b(`${amountFormatter(outputValueMax, 18, 4)} ${symbol}`)} {t('intoPool')} + {b(`${amountFormatter(outputValueMax, decimals, 4)} ${symbol}`)} {t('intoPool')}
{t('youWillMint')} {b(amountFormatter(liquidityMinted, 18, 4))} {t('liquidityTokens')} @@ -405,7 +405,7 @@ export default function AddLiquidity() { // parse input value useEffect(() => { - if (isNewExchange === false && inputValue && marketRate && lastEditedField === INPUT) { + if (isNewExchange === false && inputValue && marketRate && lastEditedField === INPUT && decimals) { try { const parsedValue = ethers.utils.parseUnits(inputValue, 18) @@ -418,10 +418,12 @@ export default function AddLiquidity() { const currencyAmount = marketRate .mul(parsedValue) .div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(18))) + .div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(18 - decimals))) + setOutputValueParsed(currencyAmount) dispatchAddLiquidityState({ type: 'UPDATE_DEPENDENT_VALUE', - payload: { field: OUTPUT, value: amountFormatter(currencyAmount, 18, 4, false) } + payload: { field: OUTPUT, value: amountFormatter(currencyAmount, decimals, 4, false) } }) return () => { @@ -437,13 +439,13 @@ export default function AddLiquidity() { setOutputError(t('inputNotValid')) } } - }, [inputValue, isNewExchange, lastEditedField, marketRate, t]) + }, [inputValue, isNewExchange, lastEditedField, marketRate, decimals, t]) // parse output value useEffect(() => { - if (isNewExchange === false && outputValue && marketRateInverted && lastEditedField === OUTPUT) { + if (isNewExchange === false && outputValue && marketRateInverted && lastEditedField === OUTPUT && decimals) { try { - const parsedValue = ethers.utils.parseUnits(outputValue, 18) + const parsedValue = ethers.utils.parseUnits(outputValue, decimals) if (parsedValue.lte(ethers.constants.Zero) || parsedValue.gte(ethers.constants.MaxUint256)) { throw Error() @@ -453,7 +455,8 @@ export default function AddLiquidity() { const currencyAmount = marketRateInverted .mul(parsedValue) - .div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(18))) + .div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(decimals))) + setInputValueParsed(currencyAmount) dispatchAddLiquidityState({ type: 'UPDATE_DEPENDENT_VALUE', @@ -473,7 +476,7 @@ export default function AddLiquidity() { setInputError(t('inputNotValid')) } } - }, [outputValue, isNewExchange, lastEditedField, marketRateInverted, t]) + }, [outputValue, isNewExchange, lastEditedField, marketRateInverted, decimals, t]) // input validation useEffect(() => { @@ -485,14 +488,14 @@ export default function AddLiquidity() { } } - if (outputValueParsed && outputBalance) { - if (outputValueParsed.gt(outputBalance)) { + if (outputValueMax && outputBalance) { + if (outputValueMax.gt(outputBalance)) { setOutputError(t('insufficientBalance')) } else { setOutputError(null) } } - }, [inputValueParsed, inputBalance, outputValueParsed, outputBalance, t]) + }, [inputValueParsed, inputBalance, outputValueMax, outputBalance, t]) const allowance = useAddressAllowance(account, outputCurrency, exchangeAddress) const [showUnlock, setShowUnlock] = useState(false) @@ -590,7 +593,7 @@ export default function AddLiquidity() { {renderSummary()} - diff --git a/src/pages/Pool/CreateExchange.js b/src/pages/Pool/CreateExchange.js index 262edf17b6..903e664a80 100644 --- a/src/pages/Pool/CreateExchange.js +++ b/src/pages/Pool/CreateExchange.js @@ -142,7 +142,7 @@ function CreateExchange({ history, location }) { {errorMessage ? errorMessage : t('enterTokenCont')} - diff --git a/src/pages/Pool/RemoveLiquidity.js b/src/pages/Pool/RemoveLiquidity.js index fee5d499fd..f06291ecf1 100644 --- a/src/pages/Pool/RemoveLiquidity.js +++ b/src/pages/Pool/RemoveLiquidity.js @@ -206,13 +206,13 @@ export default function RemoveLiquidity() { : undefined const ethWithdrawn = - ETHPer && - valueParsed && - ETHPer.mul(valueParsed).div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(18))) + ETHPer && valueParsed + ? ETHPer.mul(valueParsed).div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(18))) + : undefined const tokenWithdrawn = - tokenPer && - valueParsed && - tokenPer.mul(valueParsed).div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(18))) + tokenPer && valueParsed + ? tokenPer.mul(valueParsed).div(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(18))) + : undefined const ethWithdrawnMin = ethWithdrawn ? calculateSlippageBounds(ethWithdrawn).minimum : undefined const tokenWithdrawnMin = tokenWithdrawn ? calculateSlippageBounds(tokenWithdrawn).minimum : undefined @@ -348,17 +348,17 @@ export default function RemoveLiquidity() { - ethWithdrawn && tokenWithdrawn ? ( + ethWithdrawnMin && tokenWithdrawnMin ? ( - {`${amountFormatter(ethWithdrawn, 18, 4, false)} ETH`} + {`${amountFormatter(ethWithdrawnMin, 18, 4, false)} ETH`} + - {`${amountFormatter(tokenWithdrawn, decimals, Math.min(4, decimals))} ${symbol}`} + {`${amountFormatter(tokenWithdrawnMin, decimals, Math.min(4, decimals))} ${symbol}`} ) : ( @@ -406,7 +406,7 @@ export default function RemoveLiquidity() { {renderSummary()} - diff --git a/src/pages/Send/index.js b/src/pages/Send/index.js index 73345f99ab..22280164d2 100644 --- a/src/pages/Send/index.js +++ b/src/pages/Send/index.js @@ -486,7 +486,11 @@ export default function Swap() { .sub(ethers.utils.bigNumberify(3).mul(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(15)))) : undefined const percentSlippageFormatted = percentSlippage && amountFormatter(percentSlippage, 16, 2) - const slippageWarning = percentSlippage && percentSlippage.gte(ethers.utils.parseEther('.1')) // 10% + const slippageWarning = + percentSlippage && + percentSlippage.gte(ethers.utils.parseEther('.05')) && + percentSlippage.lt(ethers.utils.parseEther('.2')) // [5% - 20%) + const highSlippageWarning = percentSlippage && percentSlippage.gte(ethers.utils.parseEther('.2')) // [20+% const isValid = exchangeRate && inputError === null && independentError === null && recipientError === null @@ -529,6 +533,11 @@ export default function Swap() { {t('orTransFail')} + {(slippageWarning || highSlippageWarning) && ( + + ⚠️ + + )} {t('priceChange')} {b(`${percentSlippageFormatted}%`)}.
@@ -586,13 +595,21 @@ export default function Swap() { isError = true } + const slippageWarningText = highSlippageWarning + ? t('highSlippageWarning') + : slippageWarning + ? t('slippageWarning') + : '' + return ( ) @@ -755,8 +772,8 @@ export default function Swap() { {renderSummary()} - diff --git a/src/pages/Swap/index.js b/src/pages/Swap/index.js index 1c2336b40a..7719637898 100644 --- a/src/pages/Swap/index.js +++ b/src/pages/Swap/index.js @@ -481,7 +481,11 @@ export default function Swap() { .sub(ethers.utils.bigNumberify(3).mul(ethers.utils.bigNumberify(10).pow(ethers.utils.bigNumberify(15)))) : undefined const percentSlippageFormatted = percentSlippage && amountFormatter(percentSlippage, 16, 2) - const slippageWarning = percentSlippage && percentSlippage.gte(ethers.utils.parseEther('.1')) // 10% + const slippageWarning = + percentSlippage && + percentSlippage.gte(ethers.utils.parseEther('.05')) && + percentSlippage.lt(ethers.utils.parseEther('.2')) // [5% - 20%) + const highSlippageWarning = percentSlippage && percentSlippage.gte(ethers.utils.parseEther('.2')) // [20+% const isValid = exchangeRate && inputError === null && independentError === null @@ -524,6 +528,11 @@ export default function Swap() { {t('orTransFail')} + {(slippageWarning || highSlippageWarning) && ( + + ⚠️ + + )} {t('priceChange')} {b(`${percentSlippageFormatted}%`)}. @@ -577,13 +586,21 @@ export default function Swap() { isError = true } + const slippageWarningText = highSlippageWarning + ? t('highSlippageWarning') + : slippageWarning + ? t('slippageWarning') + : '' + return ( ) @@ -726,8 +743,8 @@ export default function Swap() { {renderSummary()} - diff --git a/src/theme/components.js b/src/theme/components.js index b5ba861b16..a043f4d07a 100644 --- a/src/theme/components.js +++ b/src/theme/components.js @@ -1,7 +1,9 @@ import styled from 'styled-components' import { lighten, darken } from 'polished' -export const Button = styled.button` +export const Button = styled.button.attrs({ + backgroundColor: ({ warning, theme }) => (warning ? theme.salmonRed : theme.royalBlue) +})` padding: 1rem 2rem 1rem 2rem; border-radius: 3rem; cursor: pointer; @@ -9,18 +11,18 @@ export const Button = styled.button` font-size: 1rem; border: none; outline: none; - background-color: ${({ theme }) => theme.royalBlue}; + background-color: ${({ backgroundColor }) => backgroundColor}; color: ${({ theme }) => theme.white}; transition: background-color 125ms ease-in-out; width: 100%; :hover, :focus { - background-color: ${({ theme }) => lighten(0.05, theme.royalBlue)}; + background-color: ${({ backgroundColor }) => lighten(0.05, backgroundColor)}; } :active { - background-color: ${({ theme }) => darken(0.05, theme.royalBlue)}; + background-color: ${({ backgroundColor }) => darken(0.05, backgroundColor)}; } :disabled { diff --git a/src/theme/index.js b/src/theme/index.js index 57a3f6e964..04d0e0622d 100644 --- a/src/theme/index.js +++ b/src/theme/index.js @@ -57,6 +57,8 @@ const theme = { salmonRed: '#FF6871', // orange pizazzOrange: '#FF8F05', + // yellows + warningYellow: '#FFE270', // pink uniswapPink: '#DC6BE5', connectedGreen: '#27AE60', diff --git a/src/utils/index.js b/src/utils/index.js index 3d39a0ee7b..13a5d80e85 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -6,6 +6,8 @@ import ERC20_ABI from '../constants/abis/erc20' import ERC20_BYTES32_ABI from '../constants/abis/erc20_bytes32' import { FACTORY_ADDRESSES } from '../constants' +import UncheckedJsonRpcSigner from './signer' + export const ERROR_CODES = ['TOKEN_NAME', 'TOKEN_SYMBOL', 'TOKEN_DECIMALS'].reduce( (accumulator, currentValue, currentIndex) => { accumulator[currentValue] = currentIndex @@ -93,7 +95,7 @@ export function calculateGasMargin(value, margin) { // account is optional export function getProviderOrSigner(library, account) { - return account ? library.getSigner(account) : library + return account ? new UncheckedJsonRpcSigner(library.getSigner(account)) : library } // account is optional diff --git a/src/utils/signer.js b/src/utils/signer.js new file mode 100644 index 0000000000..738b6e797c --- /dev/null +++ b/src/utils/signer.js @@ -0,0 +1,36 @@ +import * as ethers from 'ethers' + +export default class UncheckedJsonRpcSigner extends ethers.Signer { + constructor(signer) { + super() + ethers.utils.defineReadOnly(this, 'signer', signer) + ethers.utils.defineReadOnly(this, 'provider', signer.provider) + } + + getAddress() { + return this.signer.getAddress() + } + + sendTransaction(transaction) { + return this.signer.sendUncheckedTransaction(transaction).then(hash => { + return { + hash: hash, + nonce: null, + gasLimit: null, + gasPrice: null, + data: null, + value: null, + chainId: null, + confirmations: 0, + from: null, + wait: confirmations => { + return this.signer.provider.waitForTransaction(hash, confirmations) + } + } + }) + } + + signMessage(message) { + return this.signer.signMessage(message) + } +} diff --git a/yarn.lock b/yarn.lock index 21b937dd1e..3a17f4cfc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4715,7 +4715,23 @@ ethereumjs-wallet@0.6.2: utf8 "^3.0.0" uuid "^3.3.2" -ethers@^4.0.27, ethers@~4.0.4: +ethers@^4.0.28: + version "4.0.28" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.28.tgz#74d9acb57f4ede3337c8d60476b38d0fe646af01" + integrity sha512-5JTHrPoFLqf+xCAI3pKwXSOgWBSJJoAUdPtPLr1ZlKbSKiIFMkPlRNovmZS3jhIw5sHW1YoVWOaJ6ZR2gKRbwg== + dependencies: + "@types/node" "^10.3.2" + aes-js "3.0.0" + bn.js "^4.4.0" + elliptic "6.3.3" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.4" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethers@~4.0.4: version "4.0.27" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.27.tgz#e570b0da9d805ad65c83d81919abe02b2264c6bf" dependencies: