refactor send ETH test

This commit is contained in:
mmv 2019-06-03 16:49:52 +04:00
parent 14ef2f9063
commit bf174d6f94
23 changed files with 311 additions and 184 deletions

View File

@ -138,7 +138,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.338Z",
"updatedAt": "2019-06-03T08:59:02.077Z",
"devdoc": {
"methods": {}
},

View File

@ -32319,7 +32319,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.349Z",
"updatedAt": "2019-06-03T08:59:02.114Z",
"devdoc": {
"author": "Alan Lu - <alan.lu@gnosis.pm>Stefan George - <stefan@gnosis.pm>",
"methods": {

View File

@ -5582,7 +5582,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.346Z",
"updatedAt": "2019-06-03T08:59:02.084Z",
"devdoc": {
"methods": {
"allowance(address,address)": {

View File

@ -1369,7 +1369,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.344Z",
"updatedAt": "2019-06-03T08:59:02.080Z",
"devdoc": {
"methods": {}
},

View File

@ -971,7 +971,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.362Z",
"updatedAt": "2019-06-03T08:59:02.136Z",
"devdoc": {
"author": "Alan Lu - <alan@gnosis.pm>",
"methods": {},

View File

@ -987,7 +987,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.362Z",
"updatedAt": "2019-06-03T08:59:02.137Z",
"devdoc": {
"author": "Stefan George - <stefan@gnosis.pm>",
"methods": {

View File

@ -5408,7 +5408,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.347Z",
"updatedAt": "2019-06-03T08:59:02.087Z",
"devdoc": {
"methods": {}
},

View File

@ -1854,7 +1854,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.363Z",
"updatedAt": "2019-06-03T08:59:02.139Z",
"devdoc": {
"methods": {},
"title": "Abstract token contract - Functions to be implemented by token contracts"

View File

@ -953,7 +953,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.345Z",
"updatedAt": "2019-06-03T08:59:02.081Z",
"devdoc": {
"methods": {
"allowance(address,address)": {

View File

@ -953,7 +953,7 @@
},
"networks": {},
"schemaVersion": "3.0.10",
"updatedAt": "2019-05-31T13:47:05.345Z",
"updatedAt": "2019-06-03T08:59:02.082Z",
"devdoc": {
"methods": {
"allowance(address,address)": {

View File

@ -38,7 +38,7 @@
"axios": "0.19.0",
"bignumber.js": "9.0.0",
"connected-react-router": "^6.3.1",
"final-form": "4.13.0",
"final-form": "4.13.1",
"history": "^4.7.2",
"immortal-db": "^1.0.2",
"immutable": "^4.0.0-rc.9",
@ -49,7 +49,7 @@
"react-dom": "^16.8.6",
"react-final-form": "6.0.1",
"react-final-form-listeners": "^1.0.2",
"react-hot-loader": "4.8.8",
"react-hot-loader": "4.9.0",
"react-infinite-scroll-component": "^4.5.2",
"react-redux": "7.0.3",
"react-router-dom": "^4.3.1",
@ -112,11 +112,12 @@
"ethereumjs-abi": "^0.6.7",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^3.0.1",
"flow-bin": "0.99.1",
"flow-bin": "0.100.0",
"fs-extra": "8.0.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.0.4",
"jest": "24.8.0",
"jest-dom": "^3.4.0",
"json-loader": "^0.5.7",
"mini-css-extract-plugin": "0.7.0",
"postcss-loader": "^3.0.0",
@ -135,7 +136,7 @@
"webpack": "4.32.2",
"webpack-bundle-analyzer": "3.3.2",
"webpack-cli": "3.3.2",
"webpack-dev-server": "3.4.1",
"webpack-dev-server": "3.5.1",
"webpack-manifest-plugin": "^2.0.0-rc.2"
}
}

View File

@ -2,7 +2,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import { logComponentStack, type Info } from '~/utils/logBoundaries'
import { SharedSnackbarConsumer, type Variant } from '~/components/SharedSnackBar/Context'
import { SharedSnackbarConsumer, type Variant } from '~/components/SharedSnackBar'
import { WALLET_ERROR_MSG } from '~/logic/wallets/store/actions'
import ProviderAccesible from './component/ProviderInfo/ProviderAccesible'
import UserDetails from './component/ProviderDetails/UserDetails'

View File

@ -1,67 +0,0 @@
// @flow
import * as React from 'react'
import SharedSnackBar from './index'
const SharedSnackbarContext = React.createContext({
openSnackbar: undefined,
closeSnackbar: undefined,
snackbarIsOpen: false,
message: '',
variant: 'info',
})
type Props = {
children: React$Node,
}
export type Variant = 'success' | 'error' | 'warning' | 'info'
type State = {
isOpen: boolean,
message: string,
variant: Variant,
}
export class SharedSnackbarProvider extends React.Component<Props, State> {
state = {
isOpen: false,
message: '',
variant: 'info',
}
openSnackbar = (message: string, variant: Variant) => {
this.setState({
message,
variant,
isOpen: true,
})
}
closeSnackbar = () => {
this.setState({
message: '',
isOpen: false,
})
}
render() {
const { children } = this.props
return (
<SharedSnackbarContext.Provider
value={{
openSnackbar: this.openSnackbar,
closeSnackbar: this.closeSnackbar,
snackbarIsOpen: this.state.isOpen,
message: this.state.message,
variant: this.state.variant,
}}
>
<SharedSnackBar />
{children}
</SharedSnackbarContext.Provider>
)
}
}
export const SharedSnackbarConsumer = SharedSnackbarContext.Consumer

View File

@ -2,9 +2,8 @@
import * as React from 'react'
import { Snackbar } from '@material-ui/core'
import SnackbarContent from '~/components/SnackbarContent'
import { SharedSnackbarConsumer } from './Context'
const SharedSnackbar = () => (
export const SharedSnackbar = () => (
<SharedSnackbarConsumer>
{(value) => {
const {
@ -32,4 +31,67 @@ const SharedSnackbar = () => (
</SharedSnackbarConsumer>
)
export default SharedSnackbar
const SharedSnackbarContext = React.createContext({
openSnackbar: undefined,
closeSnackbar: undefined,
snackbarIsOpen: false,
message: '',
variant: 'info',
})
type Props = {
children: React$Node,
}
export type Variant = 'success' | 'error' | 'warning' | 'info'
type State = {
isOpen: boolean,
message: string,
variant: Variant,
}
export class SharedSnackbarProvider extends React.Component<Props, State> {
state = {
isOpen: false,
message: '',
variant: 'info',
}
openSnackbar = (message: string, variant: Variant) => {
this.setState({
message,
variant,
isOpen: true,
})
}
closeSnackbar = () => {
this.setState({
message: '',
isOpen: false,
})
}
render() {
const { children } = this.props
const { message, variant, isOpen } = this.state
return (
<SharedSnackbarContext.Provider
value={{
openSnackbar: this.openSnackbar,
closeSnackbar: this.closeSnackbar,
snackbarIsOpen: isOpen,
message,
variant,
}}
>
<SharedSnackbar />
{children}
</SharedSnackbarContext.Provider>
)
}
}
export const SharedSnackbarConsumer = SharedSnackbarContext.Consumer

View File

@ -2,7 +2,7 @@
import React from 'react'
import Footer from '~/components/Footer'
import Header from '~/components/Header'
import { SharedSnackbarProvider } from '~/components/SharedSnackBar/Context'
import { SharedSnackbarProvider } from '~/components/SharedSnackBar'
import styles from './index.scss'
type Props = {

View File

@ -2,7 +2,7 @@
import React from 'react'
import OpenInNew from '@material-ui/icons/OpenInNew'
import { withStyles } from '@material-ui/core/styles'
import { SharedSnackbarConsumer } from '~/components/SharedSnackBar/Context'
import { SharedSnackbarConsumer } from '~/components/SharedSnackBar'
import Close from '@material-ui/icons/Close'
import IconButton from '@material-ui/core/IconButton'
import Paragraph from '~/components/layout/Paragraph'
@ -124,6 +124,7 @@ const ReviewTx = ({
variant="contained"
minWidth={140}
color="primary"
data-testid="submit-tx-btn"
>
SUBMIT
</Button>

View File

@ -161,7 +161,14 @@ const SendFunds = ({
<Button className={classes.button} minWidth={140} onClick={onClose}>
Cancel
</Button>
<Button type="submit" className={classes.button} variant="contained" minWidth={140} color="primary">
<Button
type="submit"
className={classes.button}
variant="contained"
minWidth={140}
color="primary"
data-testid="review-tx-btn"
>
Review
</Button>
</Row>

View File

@ -1,5 +1,5 @@
// @flow
import { createBrowserHistory } from 'history'
import { createBrowserHistory, createMemoryHistory } from 'history'
import { connectRouter, routerMiddleware } from 'connected-react-router'
import {
combineReducers, createStore, applyMiddleware, compose, type Reducer, type Store,
@ -14,7 +14,7 @@ import transactions, {
TRANSACTIONS_REDUCER_ID,
} from '~/routes/safe/store/reducer/transactions'
export const history = createBrowserHistory()
export const history = process.env.NODE_ENV === 'test' ? createMemoryHistory() : createBrowserHistory()
// eslint-disable-next-line
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
@ -29,15 +29,14 @@ export type GlobalState = {
export type GetState = () => GlobalState
// customHistory is passed in tests, check test/builder/safe.dom.utils.js
const reducers: Reducer<GlobalState> = (customHistory: any = history) => combineReducers({
router: connectRouter(customHistory),
const reducers: Reducer<GlobalState> = combineReducers({
router: connectRouter(history),
[PROVIDER_REDUCER_ID]: provider,
[SAFE_REDUCER_ID]: safe,
[TOKEN_REDUCER_ID]: tokens,
[TRANSACTIONS_REDUCER_ID]: transactions,
})
export const store: Store<GlobalState> = createStore(reducers(), finalCreateStore)
export const store: Store<GlobalState> = createStore(reducers, finalCreateStore)
export const aNewStore = (localState?: Object, customHistory: any = history): Store<GlobalState> => createStore(reducers(customHistory), localState, finalCreateStore)
export const aNewStore = (localState?: Object): Store<GlobalState> => createStore(reducers, localState, finalCreateStore)

View File

@ -1,21 +1,20 @@
// @flow
import * as React from 'react'
import TestUtils from 'react-dom/test-utils'
import { createMemoryHistory } from 'history'
import { type Store } from 'redux'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router'
import PageFrame from '~/components/layout/PageFrame'
import { render } from '@testing-library/react'
import ListItemText from '~/components/List/ListItemText/index'
import { SEE_MULTISIG_BUTTON_TEXT } from '~/routes/safe/components/Safe/MultisigTx'
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
import { sleep } from '~/utils/timer'
import { aNewStore, type GlobalState } from '~/store'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router'
import { history } from '~/store'
import AppRoutes from '~/routes'
import { SAFELIST_ADDRESS, SETTINS_ADDRESS } from '~/routes/routes'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
export const testHistory = createMemoryHistory
export const EXPAND_BALANCE_INDEX = 0
export const EXPAND_OWNERS_INDEX = 1
export const ADD_OWNERS_INDEX = 2
@ -100,35 +99,33 @@ const renderApp = (store: Store) => ({
...render(
<Provider store={store}>
<ConnectedRouter history={history}>
<React.Suspense fallback={<div />}>
<AppRoutes />
</React.Suspense>
<PageFrame>
<React.Suspense fallback={<div />}>
<AppRoutes />
</React.Suspense>
</PageFrame>
</ConnectedRouter>
</Provider>,
),
store,
history,
})
export const renderSafeView = (address: string) => {
export const renderSafeView = (store: Store<GlobalState>, address: string) => {
const app = renderApp(store)
const url = `${SAFELIST_ADDRESS}/${address}`
const history = createMemoryHistory({ initialEntries: [url] })
const store = aNewStore(history)
history.push(url)
return renderApp(store, history)
return app
}
export const travelToTokens = (address: string) => {
export const travelToTokens = (store: Store<GlobalState>, address: string) => {
const app = renderApp(store)
const url = `${SAFELIST_ADDRESS}/${address}${SETTINS_ADDRESS}`
const history = createMemoryHistory({ initialEntries: [url] })
const store = aNewStore(history)
history.push(url)
return renderApp(store, history)
}
export const createTestStore = (initialRoute = '/') => {
const history = createMemoryHistory({ initialEntries: [initialRoute] })
return aNewStore(history)
return app
}
const INTERVAL = 500

View File

@ -1,54 +1,67 @@
// @flow
import { render, fireEvent, cleanup } from '@testing-library/react'
import * as fetchBalancesAction from '~/logic/tokens/store/actions/fetchTokens'
import { fireEvent, cleanup } from '@testing-library/react'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { sendTokenTo, getFirstTokenContract } from '~/test/utils/tokenMovements'
import { EXPAND_BALANCE_INDEX, renderSafeView, createTestStore } from '~/test/builder/safe.dom.utils'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { sendTokenTo, getFirstTokenContract, sendEtherTo } from '~/test/utils/tokenMovements'
import { EXPAND_BALANCE_INDEX, renderSafeView } from '~/test/builder/safe.dom.utils'
import { getWeb3, getBalanceInEtherOf } from '~/logic/wallets/getWeb3'
import { sendMoveTokensForm, dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
import { sleep } from '~/utils/timer'
import { ETH_ADDRESS } from '~/logic/tokens/utils/tokenHelpers'
import { calculateBalanceOf } from '~/routes/safe/store/actions/fetchTokenBalances'
import 'jest-dom/extend-expect'
afterEach(cleanup)
describe('DOM > Feature > Funds', () => {
let store
let safeAddress: string
let accounts
beforeEach(async () => {
store = aNewStore()
safeAddress = await aMinedSafe(store)
accounts = await getWeb3().eth.getAccounts()
})
it('Sends ETH', async () => {
// GIVEN
const numTokens = '100'
const tokenAddress = await sendTokenTo(safeAddress, numTokens)
const SafeDom = await renderSafeView(safeAddress)
const { store } = SafeDom
await dispatchTknBalance(store, tokenAddress, safeAddress)
// const StandardToken = await fetchBalancesAction.getStandardTokenContract()
// const myToken = await StandardToken.at(tokenAddress)
// console.log(await myToken.allowance(safeAddress, accounts[2]))
// console.log(await myToken.balanceOf(safeAddress))
const ethAmount = '5'
await sendEtherTo(safeAddress, ethAmount)
const balanceAfterSendingEthToSafe = await getBalanceInEtherOf(accounts[0])
// WHEN
await sleep(1500)
console.log(SafeDom.history)
const SafeDom = renderSafeView(store, safeAddress)
await sleep(1000)
// Open send funds modal
const balanceRows = SafeDom.getAllByTestId('balance-row')
const buttons = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'button')
const expandBalance = buttons[EXPAND_BALANCE_INDEX]
const receiver = accounts[2]
await sendMoveTokensForm(SafeDom, expandBalance, 20, accounts[2])
expect(balanceRows[0]).toHaveTextContent(`${ethAmount} ETH`)
const sendButton = SafeDom.getByTestId('balance-send-btn')
fireEvent.click(sendButton)
// Fill first send funds screen
const recipientInput = SafeDom.getByPlaceholderText('Recipient*')
const amountInput = SafeDom.getByPlaceholderText('Amount*')
const reviewBtn = SafeDom.getByTestId('review-tx-btn')
fireEvent.change(recipientInput, { target: { value: accounts[0] } })
fireEvent.change(amountInput, { target: { value: ethAmount } })
await sleep(200)
fireEvent.click(reviewBtn)
// Submit the tx (Review Tx screen)
const submitBtn = SafeDom.getByTestId('submit-tx-btn')
fireEvent.click(submitBtn)
await sleep(1000)
// THEN
const safeFunds = await fetchBalancesAction.calculateBalanceOf(tokenAddress, safeAddress, 18)
expect(Number(safeFunds)).toBe(80)
const receiverFunds = await fetchBalancesAction.calculateBalanceOf(tokenAddress, receiver, 18)
expect(Number(receiverFunds)).toBe(20)
const safeFunds = await calculateBalanceOf(ETH_ADDRESS, safeAddress, 18)
expect(Number(safeFunds)).toBe(0)
const token = await getFirstTokenContract(getWeb3(), accounts[0])
const nativeSafeFunds = await token.balanceOf(safeAddress)
expect(Number(nativeSafeFunds.valueOf())).toEqual(80 * 10 ** 18)
const receiverFunds = await getBalanceInEtherOf(accounts[0])
const ESTIMATED_GASCOSTS = 0.1
expect(Number(parseInt(receiverFunds, 10) - parseInt(balanceAfterSendingEthToSafe, 10))).toBeGreaterThan(
parseInt(ethAmount, 10) - ESTIMATED_GASCOSTS,
)
})
it('Sends Tokens', async () => {

View File

@ -0,0 +1,73 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import * as fetchBalancesAction from '~/logic/tokens/store/actions/fetchTokens'
import { aNewStore } from '~/store'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { addTknTo, getFirstTokenContract } from '~/test/utils/tokenMovements'
import { EXPAND_BALANCE_INDEX, travelToSafe } from '~/test/builder/safe.dom.utils'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { sendMoveTokensForm, dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
import { sleep } from '~/utils/timer'
describe('DOM > Feature > SAFE ERC20 TOKENS', () => {
let accounts
beforeEach(async () => {
accounts = await getWeb3().eth.getAccounts()
})
it('sends ERC20 tokens', async () => {
// GIVEN
const store = aNewStore()
const safeAddress = await aMinedSafe(store)
const numTokens = '100'
const tokenAddress = await addTknTo(safeAddress, numTokens)
await dispatchTknBalance(store, tokenAddress, safeAddress)
// const StandardToken = await fetchBalancesAction.getStandardTokenContract()
// const myToken = await StandardToken.at(tokenAddress)
// console.log(await myToken.allowance(safeAddress, accounts[2]))
// console.log(await myToken.balanceOf(safeAddress))
// WHEN
const SafeDom = await travelToSafe(store, safeAddress)
await sleep(800)
// $FlowFixMe
const buttons = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'button')
const expandBalance = buttons[EXPAND_BALANCE_INDEX]
const receiver = accounts[2]
await sendMoveTokensForm(SafeDom, expandBalance, 20, accounts[2])
// THEN
const safeFunds = await fetchBalancesAction.calculateBalanceOf(tokenAddress, safeAddress, 18)
expect(Number(safeFunds)).toBe(80)
const receiverFunds = await fetchBalancesAction.calculateBalanceOf(tokenAddress, receiver, 18)
expect(Number(receiverFunds)).toBe(20)
const token = await getFirstTokenContract(getWeb3(), accounts[0])
const nativeSafeFunds = await token.balanceOf(safeAddress)
expect(Number(nativeSafeFunds.valueOf())).toEqual(80 * 10 ** 18)
})
it('disables send token button when balance is 0', async () => {
// GIVEN
const token = await getFirstTokenContract(getWeb3(), accounts[0])
await dispatchTknBalance(store, token.address, safeAddress)
// WHEN
const SafeDom = travelToSafe(store, safeAddress)
// $FlowFixMe
const buttons = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'button')
const expandBalance = buttons[EXPAND_BALANCE_INDEX]
TestUtils.Simulate.click(expandBalance)
await sleep(800)
// $FlowFixMe
const balanceButtons = TestUtils.scryRenderedDOMComponentsWithTag(SafeDom, 'button')
const tokenButton = balanceButtons[EXPAND_BALANCE_INDEX + 1] // expand button, and the next one is for sending
expect(tokenButton.hasAttribute('disabled')).toBe(true)
})
})

View File

@ -9,7 +9,8 @@ import TokenRDN from '../../../build/contracts/TokenRDN'
export const sendEtherTo = async (address: string, eth: string) => {
const web3 = getWeb3()
const accounts = await web3.eth.getAccounts()
const txData = { from: accounts[0], to: address, value: web3.utils.toWei(eth, 'ether') }
const { toBN, toWei } = web3.utils
const txData = { from: accounts[0], to: address, value: toBN(toWei(eth, 'ether')) }
return web3.eth.sendTransaction(txData)
}
@ -21,7 +22,9 @@ export const checkBalanceOf = async (addressToTest: string, value: string) => {
const createTokenOMGContract = async (web3: any, creator: string) => {
const token = contract(TokenOMG)
const { toBN } = web3.utils
const amount = toBN(50000).mul(toBN(10).pow(toBN(18))).toString()
const amount = toBN(50000)
.mul(toBN(10).pow(toBN(18)))
.toString()
token.setProvider(web3.currentProvider)
return token.new(amount, { from: creator })
@ -30,7 +33,9 @@ const createTokenOMGContract = async (web3: any, creator: string) => {
const createTokenRDNContract = async (web3: any, creator: string) => {
const token = contract(TokenRDN)
const { toBN } = web3.utils
const amount = toBN(50000).mul(toBN(10).pow(toBN(18))).toString()
const amount = toBN(50000)
.mul(toBN(10).pow(toBN(18)))
.toString()
token.setProvider(web3.currentProvider)
return token.new(amount, { from: creator })

104
yarn.lock
View File

@ -1282,12 +1282,6 @@
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.2.tgz#63985d3d8b02530e0869962f4da09142ee8e200e"
integrity sha512-n/VQ4mbfr81aqkx/XmVicOLjviMuy02eenSdJY33SVA7S2J42EU0P1H0mOogfYedb3wXA0d/LVtBrgTSm04WEA==
"@gnosis.pm/mock-contract@github:gnosis/mock-contract#sol_0_5_0":
version "2.0.2"
resolved "https://codeload.github.com/gnosis/mock-contract/tar.gz/2ec1266eeef1baf7514cdb65b3a3a1aef224f3f2"
dependencies:
ethereumjs-abi "^0.6.5"
"@gnosis.pm/safe-contracts@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@gnosis.pm/safe-contracts/-/safe-contracts-1.0.0.tgz#2b562b1e23a0da1047a9f38ef71a70f811e75dd9"
@ -5558,6 +5552,21 @@ css-what@2.1, css-what@^2.1.2:
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
css.escape@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
css@^2.2.3:
version "2.2.4"
resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==
dependencies:
inherits "^2.0.3"
source-map "^0.6.1"
source-map-resolve "^0.5.2"
urix "^0.1.0"
cssesc@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703"
@ -6869,7 +6878,7 @@ ethereumjs-abi@0.6.5:
bn.js "^4.10.0"
ethereumjs-util "^4.3.0"
ethereumjs-abi@^0.6.5, ethereumjs-abi@^0.6.7, "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
ethereumjs-abi@^0.6.7, "ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git":
version "0.6.7"
resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb"
dependencies:
@ -7252,7 +7261,7 @@ expect@^24.8.0:
jest-message-util "^24.8.0"
jest-regex-util "^24.3.0"
express@^4.14.0, express@^4.16.3, express@^4.17.0:
express@^4.14.0, express@^4.16.3, express@^4.17.1:
version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
@ -7574,10 +7583,10 @@ fill-range@^4.0.0:
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
final-form@4.13.0:
version "4.13.0"
resolved "https://registry.yarnpkg.com/final-form/-/final-form-4.13.0.tgz#ef2b36a850d6287cd968f328180590e5a64a57bb"
integrity sha512-JD/MPstXejGtQOryhbLHJoOtsvcCV37baoVuwK/+/mgbNir3QZjedhUJoSqgjwMxk/H1j/usdDwy7xfKMAq/dw==
final-form@4.13.1:
version "4.13.1"
resolved "https://registry.yarnpkg.com/final-form/-/final-form-4.13.1.tgz#5893b1fe490a36198b219b351eec135d7394cdcf"
integrity sha512-9bTIY68bKn6rIcyolFZlUqK1odlRXpi30C5CazJ5gUZpoMkeDAeb53FQ3gv37eX1zWtQtydgwD5ZAwZB5EGoGg==
dependencies:
"@babel/runtime" "^7.3.1"
@ -7664,10 +7673,10 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916"
integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==
flow-bin@0.99.1:
version "0.99.1"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.99.1.tgz#0d4f413ca84a3a95d0aa64214178684dd7c6a4c5"
integrity sha512-dipNwJlb4MsVt3IuDgPTymCNL4GFoq3pG+GbY6DmBbl0dJPWFSA383rCTmgbfFhoeJ1XCfYBan0BPryToSxiiQ==
flow-bin@0.100.0:
version "0.100.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.100.0.tgz#729902726658cfa0a81425d6401f9625cf9f5534"
integrity sha512-jcethhgrslBJukH7Z7883ohFFpzLrdsOEwHxvn5NwuTWbNaE71GAl55/PEBRJwYpDvYkRlqgcNkANTv0x5XjqA==
flush-write-stream@^1.0.0:
version "1.1.1"
@ -8913,7 +8922,7 @@ imurmurhash@^0.1.4:
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
indent-string@^3.1.0, indent-string@^3.2.0:
indent-string@^3.0.0, indent-string@^3.1.0, indent-string@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=
@ -9607,7 +9616,7 @@ jest-config@^24.8.0:
pretty-format "^24.8.0"
realpath-native "^1.1.0"
jest-diff@^24.8.0:
jest-diff@^24.0.0, jest-diff@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.8.0.tgz#146435e7d1e3ffdf293d53ff97e193f1d1546172"
integrity sha512-wxetCEl49zUpJ/bvUmIFjd/o52J+yWcoc5ZyPq4/W1LUKGEhRYDIbP1KcF6t+PvqNrGAFk4/JhtxDq/Nnzs66g==
@ -9624,6 +9633,20 @@ jest-docblock@^24.3.0:
dependencies:
detect-newline "^2.1.0"
jest-dom@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/jest-dom/-/jest-dom-3.4.0.tgz#46c21984a73a4841dc57bc8fc09ccd1d971a8447"
integrity sha512-fQR5ESaxTfNbZE02y+gtaQH7+sMwzrQtJo5OE0E3BNArjTL9GWNI+uPFr1yS24eodH1X62L+qncv106M/O98gQ==
dependencies:
chalk "^2.4.1"
css "^2.2.3"
css.escape "^1.5.1"
jest-diff "^24.0.0"
jest-matcher-utils "^24.0.0"
lodash "^4.17.11"
pretty-format "^24.0.0"
redent "^2.0.0"
jest-each@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.8.0.tgz#a05fd2bf94ddc0b1da66c6d13ec2457f35e52775"
@ -9711,7 +9734,7 @@ jest-leak-detector@^24.8.0:
dependencies:
pretty-format "^24.8.0"
jest-matcher-utils@^24.8.0:
jest-matcher-utils@^24.0.0, jest-matcher-utils@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.8.0.tgz#2bce42204c9af12bde46f83dc839efe8be832495"
integrity sha512-lex1yASY51FvUuHgm0GOVj7DCYEouWSlIYmCW7APSqB9v8mXmKSn5+sWVF0MhuASG0bnYY106/49JU1FZNl5hw==
@ -10697,7 +10720,7 @@ loglevel-colored-level-prefix@^1.0.0:
chalk "^1.1.3"
loglevel "^1.4.1"
loglevel@^1.4.1, loglevel@^1.6.1:
loglevel@^1.4.1, loglevel@^1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.2.tgz#668c77948a03dbd22502a3513ace1f62a80cc372"
integrity sha512-Jt2MHrCNdtIe1W6co3tF5KXGRkzF+TYffiQstfXa04mrss9IKXzAAXYWak8LbZseAQY03sH2GzMCMU0ZOUc9bg==
@ -12795,7 +12818,7 @@ pretty-format@^23.0.1:
ansi-regex "^3.0.0"
ansi-styles "^3.2.0"
pretty-format@^24.8.0:
pretty-format@^24.0.0, pretty-format@^24.8.0:
version "24.8.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2"
integrity sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw==
@ -13321,10 +13344,10 @@ react-helmet-async@^0.2.0:
react-fast-compare "^2.0.2"
shallowequal "^1.0.2"
react-hot-loader@4.8.8:
version "4.8.8"
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.8.8.tgz#71e3c7ba301556aa24c52cef2f6ed0af82395eea"
integrity sha512-58bgeS7So8V93MhhnKogbraor8xdrTncil+b6IoIXkTIr3blJNAE7bU4tn/iJvy2J7rjxQmKFRaxKrWdKUZpqg==
react-hot-loader@4.9.0:
version "4.9.0"
resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.9.0.tgz#498e5f76aae28bfd420efdabddf5af156745b4dd"
integrity sha512-1N6MWV9++qYWrrs41MRhxATwyx743tr8RpeyL1VOZ54zsU8fOx4slYreHZ8v2BDGVfy+dJ0myJZrJA9/26RlCA==
dependencies:
fast-levenshtein "^2.0.6"
global "^4.3.0"
@ -13700,6 +13723,14 @@ recursive-readdir@2.2.2:
dependencies:
minimatch "3.0.4"
redent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=
dependencies:
indent-string "^3.0.0"
strip-indent "^2.0.0"
reduce-reducers@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/reduce-reducers/-/reduce-reducers-0.4.3.tgz#8e052618801cd8fc2714b4915adaa8937eb6d66c"
@ -14498,7 +14529,7 @@ semver@5.5.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==
semver@^6.0.0, semver@^6.1.0:
semver@^6.0.0, semver@^6.1.0, semver@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.1.tgz#53f53da9b30b2103cd4f15eab3a18ecbcb210c9b"
integrity sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==
@ -14858,7 +14889,7 @@ source-list-map@^2.0.0:
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
source-map-resolve@^0.5.0:
source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
@ -15258,6 +15289,11 @@ strip-hex-prefix@1.0.0:
dependencies:
is-hex-prefixed "1.0.0"
strip-indent@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@ -17722,10 +17758,10 @@ webpack-dev-middleware@^3.5.1, webpack-dev-middleware@^3.7.0:
range-parser "^1.2.1"
webpack-log "^2.0.0"
webpack-dev-server@3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.4.1.tgz#a5fd8dec95dec410098e7d9a037ff9405395d51a"
integrity sha512-CRqZQX2ryMtrg0r3TXQPpNh76eM1HD3Wmu6zDBxIKi/d2y+4aa28Ia8weNT0bfgWpY6Vs3Oq/K8+DjfbR+tWYw==
webpack-dev-server@3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.5.1.tgz#4290ac709bb989dc7382c912899f79fd5677dabf"
integrity sha512-0IdMGddJcnK9zesZOeHWl4uAOVfypn7DSrdNWtclROkVBXy/TcBN+6eEG1wNfLT9dXVfaRZZsLTJt0mJtgTQgw==
dependencies:
ansi-html "0.0.7"
bonjour "^3.5.0"
@ -17734,19 +17770,19 @@ webpack-dev-server@3.4.1:
connect-history-api-fallback "^1.6.0"
debug "^4.1.1"
del "^4.1.1"
express "^4.17.0"
express "^4.17.1"
html-entities "^1.2.1"
http-proxy-middleware "^0.19.1"
import-local "^2.0.0"
internal-ip "^4.3.0"
ip "^1.1.5"
killable "^1.0.1"
loglevel "^1.6.1"
loglevel "^1.6.2"
opn "^5.5.0"
portfinder "^1.0.20"
schema-utils "^1.0.0"
selfsigned "^1.10.4"
semver "^6.0.0"
semver "^6.1.1"
serve-index "^1.9.1"
sockjs "0.3.19"
sockjs-client "1.3.0"