Merge pull request #104 from gnosis/83-tokens

#83 Adding custom tokens
This commit is contained in:
Mikhail Mikheev 2019-04-26 18:22:34 +04:00 committed by GitHub
commit 659075d745
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 916 additions and 416 deletions

View File

@ -117,10 +117,10 @@
"@babel/preset-flow": "^7.0.0-beta.40",
"@babel/preset-react": "^7.0.0-beta.40",
"@sambego/storybook-state": "^1.0.7",
"@storybook/addon-actions": "5.0.9",
"@storybook/addon-knobs": "5.0.9",
"@storybook/addon-links": "5.0.9",
"@storybook/react": "5.0.9",
"@storybook/addon-actions": "5.0.10",
"@storybook/addon-knobs": "5.0.10",
"@storybook/addon-links": "5.0.10",
"@storybook/react": "5.0.10",
"autoprefixer": "9.5.1",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
@ -158,13 +158,13 @@
"storybook-host": "^5.0.3",
"storybook-router": "^0.3.3",
"style-loader": "^0.23.1",
"truffle": "5.0.12",
"truffle-contract": "^4.0.11",
"truffle-solidity-loader": "0.1.12",
"truffle": "5.0.13",
"truffle-contract": "4.0.12",
"truffle-solidity-loader": "0.1.13",
"uglifyjs-webpack-plugin": "^2.1.2",
"webpack": "^4.1.1",
"webpack-bundle-analyzer": "3.3.2",
"webpack-cli": "^3.2.3",
"webpack-cli": "3.3.1",
"webpack-dev-server": "3.3.1",
"webpack-manifest-plugin": "^2.0.0-rc.2"
}

View File

@ -36,7 +36,9 @@ type Props = {
class GnoTableHead extends React.PureComponent<Props> {
changeSort = (property: string, orderAttr: boolean) => () => {
this.props.onSort(property, orderAttr)
const { onSort } = this.props
onSort(property, orderAttr)
}
render() {

View File

@ -1,5 +1,6 @@
// @flow
import React from 'react'
import cn from 'classnames'
import MuiTextField, { TextFieldProps } from '@material-ui/core/TextField'
import { withStyles } from '@material-ui/core/styles'
import { lg } from '~/theme/variables'
@ -16,6 +17,9 @@ const styles = () => ({
paddingBottom: '12px',
lineHeight: 0,
},
input: {
borderRadius: '5px',
},
})
class TextField extends React.PureComponent<TextFieldProps> {
@ -37,7 +41,7 @@ class TextField extends React.PureComponent<TextFieldProps> {
const inputRoot = helperText ? classes.root : undefined
const inputProps = { ...restInput, autoComplete: 'off' }
const inputRootProps = { ...inputAdornment, disableUnderline: !underline, className: inputRoot }
const inputRootProps = { ...inputAdornment, disableUnderline: !underline, className: cn(inputRoot, classes.input) }
return (
<MuiTextField

View File

@ -52,6 +52,8 @@ export const mustBeEthereumAddress = (address: Field) => {
return isAddress ? undefined : 'Address should be a valid Ethereum address'
}
export const minMaxLength = (minLen: string | number, maxLen: string | number) => (value: string) => (value.length >= +minLen && value.length <= +maxLen ? undefined : `Should be ${minLen} to ${maxLen} symbols`)
export const ADDRESS_REPEATED_ERROR = 'Address already introduced'
export const uniqueAddress = (addresses: string[]) => (value: string) => (addresses.includes(value) ? ADDRESS_REPEATED_ERROR : undefined)

View File

@ -10,7 +10,7 @@ const cx = classNames.bind(styles)
type Props = {
margin?: Size,
padding?: Size,
align?: 'center' | 'right',
align?: 'center' | 'right' | 'left',
children: React$Node,
className?: string,
}

View File

@ -1,5 +1,4 @@
.block {
}
.xs {
@ -7,19 +6,19 @@
}
.sm {
margin-bottom: $sm;
margin-bottom: $sm;
}
.md {
margin-bottom: $md;
margin-bottom: $md;
}
.lg {
margin-bottom: $lg;
margin-bottom: $lg;
}
.xl {
margin-bottom: $xl;
margin-bottom: $xl;
}
.paddingXs {
@ -48,8 +47,13 @@
justify-content: center;
}
.left {
display: flex;
align-items: center;
}
.right {
display: flex;
align-items: center;
justify-content: flex-end;
}
}

View File

@ -10,7 +10,7 @@ const styles = {
}
type Props = {
minWidth?: number
minWidth?: number,
}
const calculateStyleBased = minWidth => ({

View File

@ -8,6 +8,7 @@ const cx = classNames.bind(styles)
type Props = {
align?: 'right' | 'center' | 'left',
noMargin?: boolean,
noPadding?: boolean,
weight?: 'light' | 'regular' | 'bolder' | 'bold',
size?: 'sm' | 'md' | 'lg' | 'xl' | 'xxl',
color?: 'soft' | 'medium' | 'dark' | 'white' | 'fancy' | 'primary' | 'secondary' | 'warning' | 'disabled',
@ -25,7 +26,7 @@ class Paragraph extends React.PureComponent<Props> {
return (
<p
className={cx(styles.paragraph, className, weight, { noMargin }, { dot }, size, color, transform, align)}
className={cx(styles.paragraph, className, weight, { noMargin, dot }, size, color, transform, align)}
{...props}
>
{children}

View File

@ -40,19 +40,19 @@
}
.capitalize {
text-transform: capitalize
text-transform: capitalize;
}
.lowercase {
text-transform: lowercase
text-transform: lowercase;
}
.uppercase {
text-transform: uppercase
text-transform: uppercase;
}
.noMargin{
margin: 0;
.noMargin {
margin: 0;
}
.center {

View File

@ -0,0 +1,16 @@
// @flow
import axios from 'axios'
import { getRelayUrl } from '~/config/index'
const fetchToken = (tokenAddress: string) => {
const apiUrl = getRelayUrl()
const url = `${apiUrl}/tokens/`
return axios.get(url, {
params: {
address: tokenAddress,
},
})
}
export default fetchToken

View File

@ -0,0 +1,12 @@
// @flow
import axios from 'axios'
import { getRelayUrl } from '~/config/index'
const fetchTokenList = () => {
const apiUrl = getRelayUrl()
const url = `${apiUrl}/tokens`
return axios.get(url)
}
export default fetchTokenList

View File

@ -0,0 +1,3 @@
// @flow
export { default as fetchTokenList } from './fetchTokenList'
export { default as fetchToken } from './fetchToken'

View File

@ -1,14 +1,10 @@
// @flow
import { createAction } from 'redux-actions'
import { type Token } from '~/logic/tokens/store/model/token'
import { saveActiveTokens, getActiveTokens, setToken } from '~/logic/tokens/utils/tokensStorage'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/'
export const ADD_TOKEN = 'ADD_TOKEN'
type AddTokenProps = {
safeAddress: string,
token: Token,
}
@ -18,13 +14,3 @@ export const addToken = createAction<string, *, *>(
token,
}),
)
const saveToken = (safeAddress: string, token: Token) => async (dispatch: ReduxDispatch<GlobalState>) => {
dispatch(addToken(token))
const activeTokens = await getActiveTokens(safeAddress)
await saveActiveTokens(safeAddress, activeTokens.push(token.toJS()))
setToken(safeAddress, token)
}
export default saveToken

View File

@ -1,16 +1,15 @@
// @flow
import { List } from 'immutable'
import contract from 'truffle-contract'
import axios from 'axios'
import type { Dispatch as ReduxDispatch } from 'redux'
import StandardToken from '@gnosis.pm/util-contracts/build/contracts/GnosisStandardToken.json'
import HumanFriendlyToken from '@gnosis.pm/util-contracts/build/contracts/HumanFriendlyToken.json'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type GlobalState } from '~/store/index'
import { makeToken, type TokenProps } from '~/logic/tokens/store/model/token'
import { fetchTokenList } from '~/logic/tokens/api'
import { ensureOnce } from '~/utils/singleton'
import saveTokens from './saveTokens'
import { getRelayUrl } from '~/config/index'
const createStandardTokenContract = async () => {
const web3 = getWeb3()
@ -31,13 +30,6 @@ export const getHumanFriendlyToken = ensureOnce(createHumanFriendlyTokenContract
export const getStandardTokenContract = ensureOnce(createStandardTokenContract)
const fetchTokenList = async () => {
const apiUrl = getRelayUrl()
const url = `${apiUrl}/tokens`
const errMsg = 'Error querying safe balances'
return axios.get(url, errMsg)
}
export const fetchTokens = () => async (dispatch: ReduxDispatch<GlobalState>) => {
try {
const {

View File

@ -11,7 +11,7 @@ const loadActiveTokens = () => async (dispatch: ReduxDispatch<GlobalState>) => {
const tokens: Map<string, TokenProps> = await getActiveTokens()
const tokenRecordsList: List<Token> = List(
Object.values(tokens).map(token => makeToken(token)),
Object.values(tokens).map((token: TokenProps): Token => makeToken(token)),
)
dispatch(saveTokens(tokenRecordsList))

View File

@ -1,7 +1,7 @@
// @flow
import { Map } from 'immutable'
import { handleActions, type ActionType } from 'redux-actions'
import { type Token } from '~/logic/tokens/store/model/token'
import { type Token, makeToken } from '~/logic/tokens/store/model/token'
import { ADD_TOKEN } from '~/logic/tokens/store/actions/addToken'
import { REMOVE_TOKEN } from '~/logic/tokens/store/actions/removeToken'
import { ADD_TOKENS } from '~/logic/tokens/store/actions/saveTokens'
@ -27,7 +27,7 @@ export default handleActions<State, *>(
const { token } = action.payload
const { address: tokenAddress } = token
return state.set(tokenAddress, token)
return state.set(tokenAddress, makeToken(token))
},
[REMOVE_TOKEN]: (state: State, action: ActionType<Function>): State => {
const { token } = action.payload

View File

@ -10,7 +10,9 @@ import OpenPaper from '~/components/Stepper/OpenPaper'
import Col from '~/components/layout/Col'
import Row from '~/components/layout/Row'
import Paragraph from '~/components/layout/Paragraph'
import { sm, md, lg, border, secondary, background } from '~/theme/variables'
import {
sm, md, lg, border, secondary, background,
} from '~/theme/variables'
import Hairline from '~/components/layout/Hairline'
import { openAddressInEtherScan } from '~/logic/wallets/getWeb3'
import { FIELD_NAME, FIELD_CONFIRMATIONS, getNumOwnersFrom } from '../fields'
@ -111,17 +113,21 @@ const ReviewComponent = ({ values, classes, network }: Props) => {
</Paragraph>
</Block>
<Hairline />
{ names.map((name, index) => (
<React.Fragment key={`name${(index)}`}>
{names.map((name, index) => (
<React.Fragment key={`name${index}`}>
<Row className={classes.owner}>
<Col xs={1} align="center">
<Identicon address={addresses[index]} diameter={32} />
</Col>
<Col xs={11}>
<Block className={classNames(classes.name, classes.userName)}>
<Paragraph size="lg" noMargin >{name}</Paragraph>
<Paragraph size="lg" noMargin>
{name}
</Paragraph>
<Block align="center" className={classes.user}>
<Paragraph size="md" color="disabled" noMargin>{addresses[index]}</Paragraph>
<Paragraph size="md" color="disabled" noMargin>
{addresses[index]}
</Paragraph>
<OpenInNew
className={classes.open}
style={openIconStyle}
@ -138,7 +144,7 @@ const ReviewComponent = ({ values, classes, network }: Props) => {
</Row>
<Row className={classes.info} align="center">
<Paragraph noMargin color="primary" size="md">
{'You\'re about to create a new Safe.'}
{"You're about to create a new Safe."}
</Paragraph>
<Paragraph noMargin color="primary" size="md">
Make sure you have enough ETH in your wallet client to fund this transaction.
@ -158,5 +164,4 @@ const Review = ({ network }: LayoutProps) => (controls: React$Node, { values }:
</React.Fragment>
)
export default Review

View File

@ -37,8 +37,19 @@ const SafeName = ({ classes }: Props) => (
<React.Fragment>
<Block margin="lg">
<Paragraph noMargin size="md" color="primary" className={classes.links}>
This setup will create a Safe with one or more owners. Optionally give the Safe a local name.
By continuing you consent with the <a rel="noopener noreferrer" href="https://safe.gnosis.io/terms" target="_blank">terms of use</a> and <a rel="noopener noreferrer" href="https://safe.gnosis.io/privacy" target="_blank">privacy policy</a>.
This setup will create a Safe with one or more owners. Optionally give the Safe a local name. By continuing you
consent with the
{' '}
<a rel="noopener noreferrer" href="https://safe.gnosis.io/terms" target="_blank">
terms of use
</a>
{' '}
and
{' '}
<a rel="noopener noreferrer" href="https://safe.gnosis.io/privacy" target="_blank">
privacy policy
</a>
.
</Paragraph>
</Block>
<Row margin="md" className={classes.text}>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

View File

@ -4,7 +4,9 @@ import Field from '~/components/forms/Field'
import OpenPaper from '~/components/Stepper/OpenPaper'
import TextField from '~/components/forms/TextField'
import Checkbox from '~/components/forms/Checkbox'
import { composeValidators, required, mustBeEthereumAddress, uniqueAddress } from '~/components/forms/validator'
import {
composeValidators, required, mustBeEthereumAddress, uniqueAddress,
} from '~/components/forms/validator'
import Block from '~/components/layout/Block'
import Heading from '~/components/layout/Heading'
@ -27,7 +29,7 @@ export const safeFieldsValidation = (values: Object) => {
type Props = {
numOwners: number,
threshold: number,
addresses: string[]
addresses: string[],
}
const AddOwnerForm = ({ addresses, numOwners, threshold }: Props) => (controls: React$Node) => (
@ -59,11 +61,7 @@ const AddOwnerForm = ({ addresses, numOwners, threshold }: Props) => (controls:
/>
</Block>
<Block margin="md">
<Field
name={INCREASE_PARAM}
component={Checkbox}
type="checkbox"
/>
<Field name={INCREASE_PARAM} component={Checkbox} type="checkbox" />
<Block>Increase threshold?</Block>
</Block>
</OpenPaper>

View File

@ -6,7 +6,7 @@ import Block from '~/components/layout/Block'
import Bold from '~/components/layout/Bold'
import Heading from '~/components/layout/Heading'
import Paragraph from '~/components/layout/Paragraph'
import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/component/AddOwner/AddOwnerForm'
import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/components/AddOwner/AddOwnerForm'
type FormProps = {
values: Object,

View File

@ -5,7 +5,7 @@ import Stepper from '~/components/Stepper'
import { connect } from 'react-redux'
import { type Safe } from '~/routes/safe/store/models/safe'
import { type Owner, makeOwner } from '~/routes/safe/store/models/owner'
import { setOwners } from '~/utils/storage'
import { setOwners } from '~/logic/safe/utils'
import { getSafeEthereumInstance, createTransaction } from '~/logic/safe/safeFrontendOperations'
import AddOwnerForm, { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from './AddOwnerForm'
import Review from './Review'

View File

@ -0,0 +1,26 @@
// @flow
import * as React from 'react'
import Block from '~/components/layout/Block'
import Img from '~/components/layout/Img'
import Paragraph from '~/components/layout/Paragraph'
import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils'
type Props = {
asset: {
logoUri: string,
name: string,
},
}
const AssetTableCell = (props: Props) => {
const { asset } = props
return (
<Block align="left">
<Img src={asset.logoUri} height={26} alt={asset.name} onError={setImageToPlaceholder} />
<Paragraph style={{ marginLeft: 10 }}>{asset.name}</Paragraph>
</Block>
)
}
export default AssetTableCell

View File

@ -0,0 +1,5 @@
// @flow
import AssetTableCell from './AssetTableCell'
export default AssetTableCell

View File

@ -1,13 +1,19 @@
// @flow
import fetchTokens from '~/logic/tokens/store/actions/fetchTokens'
import { addToken } from '~/logic/tokens/store/actions/addToken'
import updateActiveTokens from '~/routes/safe/store/actions/updateActiveTokens'
import activateTokenForAllSafes from '~/routes/safe/store/actions/activateTokenForAllSafes'
export type Actions = {
fetchTokens: Function,
updateActiveTokens: Function,
addToken: Function,
activateTokenForAllSafes: Function,
}
export default {
fetchTokens,
addToken,
updateActiveTokens,
activateTokenForAllSafes,
}

View File

@ -0,0 +1,81 @@
// @flow
import React, { useState } from 'react'
import { connect } from 'react-redux'
import { List } from 'immutable'
import { withStyles } from '@material-ui/core/styles'
import Close from '@material-ui/icons/Close'
import IconButton from '@material-ui/core/IconButton'
import Paragraph from '~/components/layout/Paragraph'
import Hairline from '~/components/layout/Hairline'
import Row from '~/components/layout/Row'
import TokenList from '~/routes/safe/components/Balances/Tokens/screens/TokenList'
import AddCustomToken from '~/routes/safe/components/Balances/Tokens/screens/AddCustomToken'
import { type Token } from '~/logic/tokens/store/model/token'
import actions, { type Actions } from './actions'
import { styles } from './style'
type Props = Actions & {
onClose: () => void,
classes: Object,
tokens: List<Token>,
safeAddress: string,
activeTokens: List<Token>,
}
const Tokens = (props: Props) => {
const [activeScreen, setActiveScreen] = useState<string>('tokenList')
const {
onClose,
classes,
tokens,
activeTokens,
fetchTokens,
updateActiveTokens,
safeAddress,
addToken,
activateTokenForAllSafes,
} = props
return (
<React.Fragment>
<Row align="center" grow className={classes.heading}>
<Paragraph className={classes.manage} noMargin>
Manage Tokens
</Paragraph>
<IconButton onClick={onClose} disableRipple>
<Close className={classes.close} />
</IconButton>
</Row>
<Hairline />
{activeScreen === 'tokenList' && (
<TokenList
tokens={tokens}
activeTokens={activeTokens}
fetchTokens={fetchTokens}
updateActiveTokens={updateActiveTokens}
safeAddress={safeAddress}
setActiveScreen={setActiveScreen}
/>
)}
{activeScreen === 'addCustomToken' && (
<AddCustomToken
setActiveScreen={setActiveScreen}
onClose={onClose}
addToken={addToken}
safeAddress={safeAddress}
activeTokens={activeTokens}
updateActiveTokens={updateActiveTokens}
activateTokenForAllSafes={activateTokenForAllSafes}
tokens={tokens}
/>
)}
</React.Fragment>
)
}
const TokenComponent = withStyles(styles)(Tokens)
export default connect(
undefined,
actions,
)(TokenComponent)

View File

@ -0,0 +1,192 @@
// @flow
import React, { useState } from 'react'
import { List } from 'immutable'
import { FormSpy } from 'react-final-form'
import { withStyles } from '@material-ui/core/styles'
import Block from '~/components/layout/Block'
import Paragraph from '~/components/layout/Paragraph'
import Row from '~/components/layout/Row'
import Col from '~/components/layout/Col'
import Img from '~/components/layout/Img'
import Button from '~/components/layout/Button'
import Field from '~/components/forms/Field'
import Checkbox from '~/components/forms/Checkbox'
import GnoForm from '~/components/forms/GnoForm'
import TextField from '~/components/forms/TextField'
import Hairline from '~/components/layout/Hairline'
import {
composeValidators, required, mustBeEthereumAddress, minMaxLength,
} from '~/components/forms/validator'
import { type TokenProps, type Token } from '~/logic/tokens/store/model/token'
import TokenPlaceholder from '~/routes/safe/components/Balances/assets/token_placeholder.svg'
import { addressIsTokenContract, doesntExistInTokenList } from './validators'
import { styles } from './style'
import { getSymbolAndDecimalsFromContract } from './utils'
type Props = {
classes: Object,
addToken: Function,
updateActiveTokens: Function,
safeAddress: string,
activeTokens: List<TokenProps>,
tokens: List<Token>,
setActiveScreen: Function,
onClose: Function,
activateTokenForAllSafes: Function,
}
const INITIAL_FORM_STATE = {
address: '',
decimals: '',
symbol: '',
logoUri: '',
}
const AddCustomToken = (props: Props) => {
const {
classes, setActiveScreen, onClose, addToken, updateActiveTokens, safeAddress, activeTokens, tokens, activateTokenForAllSafes,
} = props
const [formValues, setFormValues] = useState(INITIAL_FORM_STATE)
const handleSubmit = (values) => {
const token = {
address: values.address,
decimals: values.decimals,
symbol: values.symbol,
name: values.symbol,
}
addToken(token)
if (values.showForAllSafes) {
activateTokenForAllSafes(token.address)
} else {
const activeTokensAddresses = activeTokens.map(({ address }) => address)
updateActiveTokens(safeAddress, activeTokensAddresses.push(token.address))
}
onClose()
}
const populateFormValuesFromAddress = async (tokenAddress: string) => {
const tokenData = await getSymbolAndDecimalsFromContract(tokenAddress)
if (tokenData.length) {
const [symbol, decimals] = tokenData
setFormValues({
address: tokenAddress,
symbol,
decimals,
name: symbol,
})
}
}
const formSpyOnChangeHandler = async (state) => {
const {
errors, validating, values, dirty, submitSucceeded,
} = state
// for some reason this is called after submitting, we don't need to update the values
// after submit
if (submitSucceeded) {
return
}
if (dirty && !validating && errors.address) {
setFormValues(INITIAL_FORM_STATE)
}
if (!errors.address && !validating && dirty) {
await populateFormValuesFromAddress(values.address)
}
}
const goBackToTokenList = () => {
setActiveScreen('tokenList')
}
return (
<React.Fragment>
<GnoForm onSubmit={handleSubmit} initialValues={formValues}>
{() => (
<React.Fragment>
<Block className={classes.formContainer}>
<Paragraph noMargin className={classes.title} weight="bolder" size="lg">
Add custom token
</Paragraph>
<Field
name="address"
component={TextField}
type="text"
validate={composeValidators(
required,
mustBeEthereumAddress,
doesntExistInTokenList(tokens),
addressIsTokenContract,
)}
placeholder="Token contract address*"
text="Token contract address*"
className={classes.addressInput}
/>
<FormSpy
subscription={{
values: true,
errors: true,
validating: true,
dirty: true,
submitSucceeded: true,
}}
onChange={formSpyOnChangeHandler}
/>
<Row>
<Col xs={6} layout="column">
<Field
name="symbol"
component={TextField}
type="text"
validate={composeValidators(required, minMaxLength(3, 12))}
placeholder="Token symbol*"
text="Token symbol"
className={classes.addressInput}
/>
<Field
name="decimals"
component={TextField}
disabled
type="text"
placeholder="Token decimals*"
text="Token decimals*"
className={classes.addressInput}
/>
<Block align="left">
<Field name="showForAllSafes" component={Checkbox} type="checkbox" className={classes.checkbox} />
<Paragraph weight="bolder" size="md" className={classes.checkboxLabel}>
Activate token for all Safes
</Paragraph>
</Block>
</Col>
<Col xs={6} layout="column" align="center">
<Paragraph className={classes.tokenImageHeading}>Token Image</Paragraph>
<Img src={TokenPlaceholder} alt="Token image" height={100} />
</Col>
</Row>
</Block>
<Hairline />
<Row align="center" className={classes.buttonRow}>
<Button className={classes.button} minWidth={140} onClick={goBackToTokenList}>
Cancel
</Button>
<Button type="submit" className={classes.button} variant="contained" minWidth={140} color="primary">
Save
</Button>
</Row>
</React.Fragment>
)}
</GnoForm>
</React.Fragment>
)
}
const AddCustomTokenComponent = withStyles(styles)(AddCustomToken)
export default AddCustomTokenComponent

View File

@ -0,0 +1,34 @@
// @flow
import { lg } from '~/theme/variables'
export const styles = () => ({
title: {
padding: `${lg} 0 20px`,
fontSize: '16px',
},
formContainer: {
padding: '0 20px',
minHeight: '369px',
},
addressInput: {
marginBottom: '15px',
},
tokenImageHeading: {
margin: '0 0 15px',
},
checkbox: {
padding: '0 7px 0 0',
width: '18px',
height: '18px',
},
checkboxLabel: {
letterSpacing: '-0.5px',
},
buttonRow: {
height: '84px',
justifyContent: 'center',
},
button: {
height: '42px',
},
})

View File

@ -0,0 +1,17 @@
// @flow
import { getHumanFriendlyToken } from '~/logic/tokens/store/actions/fetchTokens'
export const getSymbolAndDecimalsFromContract = async (tokenAddress: string) => {
const tokenContract = await getHumanFriendlyToken()
const token = await tokenContract.at(tokenAddress)
let values
try {
const [symbol, decimals] = await Promise.all([token.symbol(), token.decimals()])
values = [symbol, decimals.toString()]
} catch {
values = []
}
return values
}

View File

@ -0,0 +1,46 @@
// @flow
import { List } from 'immutable'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type Token } from '~/logic/tokens/store/model/token'
import { sameAddress } from '~/logic/wallets/ethAddresses'
// import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens'
export const simpleMemoize = (fn: Function) => {
let lastArg
let lastResult
return (arg: any) => {
if (arg !== lastArg) {
lastArg = arg
lastResult = fn(arg)
}
return lastResult
}
}
// eslint-disable-next-line
export const addressIsTokenContract = simpleMemoize(async (tokenAddress: string) => {
// SECOND APPROACH:
// They both seem to work the same
// const tokenContract = await getStandardTokenContract()
// try {
// await tokenContract.at(tokenAddress)
// } catch {
// return 'Not a token address'
// }
const web3 = getWeb3()
const call = await web3.eth.call({ to: tokenAddress, data: web3.utils.sha3('totalSupply()') })
if (call === '0x') {
return 'Not a token address'
}
})
// eslint-disable-next-line
export const doesntExistInTokenList = (tokenList: List<Token>) => simpleMemoize((tokenAddress: string) => {
const tokenIndex = tokenList.findIndex(({ address }) => sameAddress(address, tokenAddress))
if (tokenIndex !== -1) {
return 'Token already exists in your token list'
}
})

View File

@ -1,8 +1,7 @@
// @flow
import * as React from 'react'
import { connect } from 'react-redux'
import { List, Set } from 'immutable'
import classNames from 'classnames/bind'
import cn from 'classnames'
import SearchBar from 'material-ui-search-bar'
import { withStyles } from '@material-ui/core/styles'
import MuiList from '@material-ui/core/List'
@ -12,28 +11,27 @@ import ListItem from '@material-ui/core/ListItem'
import ListItemIcon from '@material-ui/core/ListItemIcon'
import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction'
import ListItemText from '@material-ui/core/ListItemText'
import Close from '@material-ui/icons/Close'
import Search from '@material-ui/icons/Search'
import IconButton from '@material-ui/core/IconButton'
import Paragraph from '~/components/layout/Paragraph'
import Button from '~/components/layout/Button'
import Switch from '@material-ui/core/Switch'
import Divider from '~/components/layout/Divider'
import Hairline from '~/components/layout/Hairline'
import Spacer from '~/components/Spacer'
import CircularProgress from '@material-ui/core/CircularProgress'
import Row from '~/components/layout/Row'
import { ETH_ADDRESS } from '~/logic/tokens/utils/tokenHelpers'
import { type Token } from '~/logic/tokens/store/model/token'
import actions, { type Actions } from './actions'
import TokenPlaceholder from './assets/token_placeholder.png'
import { setImageToPlaceholder } from '~/routes/safe/components/Balances/utils'
import { styles } from './style'
type Props = Actions & {
onClose: () => void,
type Props = {
classes: Object,
tokens: List<Token>,
safeAddress: string,
activeTokens: List<Token>,
fetchTokens: Function,
updateActiveTokens: Function,
setActiveScreen: Function,
}
type State = {
@ -60,9 +58,9 @@ class Tokens extends React.Component<Props, State> {
}
componentDidMount() {
const { fetchTokens, safeAddress } = this.props
const { fetchTokens } = this.props
fetchTokens(safeAddress)
fetchTokens()
}
static getDerivedStateFromProps(nextProps, prevState) {
@ -109,13 +107,8 @@ class Tokens extends React.Component<Props, State> {
}
}
setImageToPlaceholder = (e) => {
e.target.onerror = null
e.target.src = TokenPlaceholder
}
render() {
const { onClose, classes, tokens } = this.props
const { classes, tokens, setActiveScreen } = this.props
const { filter, activeTokensAddresses } = this.state
const searchClasses = {
input: classes.searchInput,
@ -123,22 +116,14 @@ class Tokens extends React.Component<Props, State> {
iconButton: classes.searchIcon,
searchContainer: classes.searchContainer,
}
const switchToAddCustomTokenScreen = () => setActiveScreen('addCustomToken')
const filteredTokens = filterBy(filter, tokens)
return (
<React.Fragment>
<Block className={classes.root}>
<Row align="center" grow className={classes.heading}>
<Paragraph className={classes.manage} noMargin>
Manage Tokens
</Paragraph>
<IconButton onClick={onClose} disableRipple>
<Close className={classes.close} />
</IconButton>
</Row>
<Hairline />
<Row align="center" className={classNames(classes.padding, classes.actions)}>
<Row align="center" className={cn(classes.padding, classes.actions)}>
<Search className={classes.search} />
<SearchBar
placeholder="Search by name or symbol"
@ -150,20 +135,31 @@ class Tokens extends React.Component<Props, State> {
<Spacer />
<Divider />
<Spacer />
<Button variant="contained" size="small" color="secondary" className={classes.add}>
<Button
variant="contained"
size="small"
color="secondary"
className={classes.add}
onClick={switchToAddCustomTokenScreen}
>
+ ADD CUSTOM TOKEN
</Button>
</Row>
<Hairline />
</Block>
<MuiList className={classes.list}>
{!tokens.size && (
<Block align="center" className={classes.progressContainer}>
<CircularProgress />
</Block>
)}
{filteredTokens.map((token: Token) => {
const isActive = activeTokensAddresses.has(token.address)
return (
<ListItem key={token.address} className={classes.token}>
<ListItemIcon>
<Img src={token.logoUri} height={28} alt={token.name} onError={this.setImageToPlaceholder} />
<Img src={token.logoUri} height={28} alt={token.name} onError={setImageToPlaceholder} />
</ListItemIcon>
<ListItemText primary={token.symbol} secondary={token.name} />
{token.address !== ETH_ADDRESS && (
@ -182,7 +178,4 @@ class Tokens extends React.Component<Props, State> {
const TokenComponent = withStyles(styles)(Tokens)
export default connect(
undefined,
actions,
)(TokenComponent)
export default TokenComponent

View File

@ -1,25 +1,11 @@
// @flow
import {
lg, md, sm, xs, mediumFontSize, border,
md, sm, xs, mediumFontSize, border,
} from '~/theme/variables'
export const styles = () => ({
root: {
minHeight: '127px',
},
heading: {
padding: `${sm} ${lg}`,
justifyContent: 'space-between',
},
manage: {
fontSize: '24px',
},
actions: {
height: '50px',
},
close: {
height: '35px',
width: '35px',
minHeight: '48px',
},
search: {
color: '#a2a8ba',
@ -29,14 +15,19 @@ export const styles = () => ({
padding: `0 ${md}`,
},
add: {
fontSize: '11px',
fontWeight: 'normal',
paddingRight: md,
paddingLeft: md,
},
actions: {
height: '50px',
},
list: {
overflow: 'hidden',
overflowY: 'scroll',
padding: 0,
height: '100%',
},
token: {
minHeight: '50px',
@ -45,7 +36,7 @@ export const styles = () => ({
searchInput: {
backgroundColor: 'transparent',
lineHeight: 'initial',
fontSize: mediumFontSize,
fontSize: '13px',
padding: 0,
'& > input::placeholder': {
letterSpacing: '-0.5px',
@ -56,6 +47,11 @@ export const styles = () => ({
letterSpacing: '-0.5px',
},
},
progressContainer: {
width: '100%',
height: '100%',
alignItems: 'center',
},
searchContainer: {
width: '180px',
marginLeft: xs,
@ -64,9 +60,12 @@ export const styles = () => ({
searchRoot: {
letterSpacing: '-0.5px',
fontFamily: 'Roboto Mono, monospace',
fontSize: mediumFontSize,
fontSize: '13px',
border: 'none',
boxShadow: 'none',
'& > button': {
display: 'none',
},
},
searchIcon: {
'&:hover': {

View File

@ -0,0 +1,18 @@
// @flow
import { lg, sm } from '~/theme/variables'
export const styles = () => ({
heading: {
padding: `${sm} ${lg}`,
justifyContent: 'space-between',
maxHeight: '75px',
boxSizing: 'border-box',
},
manage: {
fontSize: '24px',
},
close: {
height: '35px',
width: '35px',
},
})

View File

@ -0,0 +1 @@
<svg height="26" viewBox="0 0 26 26" width="26" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="nonzero"><circle cx="13" cy="13" fill="#eae9ef" r="13"/><path d="m12.9800266 4.09134443c-.0615216.00319594-.1222455.01997459-.1765755.04953761-.05433.02956221-.1014704.07190818-.1374265.12224554l-6.1059363 8.59150972c-.04873785.0687133-.07590285.1526054-.07590285.2373076 0 .0838943.027165.1685862.07590285.2373076l6.1059363 8.5898734c.0375515.0527326.0878889.096678.1462136.1262403.0575269.0295622.1222455.0455429.1877618.0455429.0647186 0 .1302349-.0159797.1877618-.0455429.057527-.0295623.1078623-.0735077.1462136-.1262403l6.1059363-8.5898734c.0487379-.0687132.0759028-.1526054.0759028-.2373076 0-.0838942-.0271649-.1685862-.0759028-.2373076l-6.1073681-8.59150972c-.039151-.05592949-.093481-.10067268-.1542049-.13103259-.0615217-.02956221-.1302349-.04394343-.1981484-.04074851zm.0191757 1.7729551 2.2890102 6.81773647h-4.5774068zm-1.2160533 1.05305516-1.93513509 5.76476311h-2.16199071zm2.4330066 0 4.0971462 5.76476311h-2.1619907zm-6.53015285 6.58292421h2.16117254l1.93513511 5.7631268zm3.02494615 0h4.5774068l-2.2890102 6.8161001zm5.4403622 0h2.1611726l-4.0963281 5.7631268z" fill="#a2a8ba"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -9,21 +9,21 @@ export const BALANCE_TABLE_BALANCE_ID = 'balance'
export const BALANCE_TABLE_VALUE_ID = 'value'
type BalanceData = {
asset: string,
asset: Object,
balance: string,
}
export type BalanceRow = SortRow<BalanceData>
export const getBalanceData = (activeTokens: List<Token>): Array<BalanceRow> => {
export const getBalanceData = (activeTokens: List<Token>): List<BalanceRow> => {
const rows = activeTokens.map((token: Token) => ({
[BALANCE_TABLE_ASSET_ID]: token.name,
[BALANCE_TABLE_ASSET_ID]: { name: token.name, logoUri: token.logoUri },
[BALANCE_TABLE_BALANCE_ID]: `${token.balance} ${token.symbol}`,
[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)]: Number(token.balance),
[FIXED]: token.get('symbol') === 'ETH',
}))
return Array.from(rows)
return rows
}
export const generateColumns = () => {
@ -56,4 +56,4 @@ export const generateColumns = () => {
return List([assetRow, balanceRow, actions])
}
export const filterByZero = (data: Array<BalanceRow>, hideZero: boolean): Array<BalanceRow> => data.filter((row: BalanceRow) => (hideZero ? row[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)] !== 0 : true))
export const filterByZero = (data: List<BalanceRow>, hideZero: boolean): List<BalanceRow> => data.filter((row: BalanceRow) => (hideZero ? row[buildOrderFieldFrom(BALANCE_TABLE_BALANCE_ID)] !== 0 : true))

View File

@ -19,6 +19,7 @@ import Table from '~/components/Table'
import {
getBalanceData, generateColumns, BALANCE_TABLE_ASSET_ID, type BalanceRow, filterByZero,
} from './dataFetcher'
import AssetTableCell from './AssetTableCell'
import Tokens from './Tokens'
import Send from './Send'
import Receive from './Receive'
@ -116,14 +117,14 @@ class Balances extends React.Component<Props, State> {
defaultOrderBy={BALANCE_TABLE_ASSET_ID}
columns={columns}
data={filteredData}
size={filteredData.length}
size={filteredData.size}
defaultFixed
>
{(sortedData: Array<BalanceRow>) => sortedData.map((row: any, index: number) => (
<TableRow tabIndex={-1} key={index} className={classes.hide}>
{autoColumns.map((column: Column) => (
<TableCell key={column.id} style={cellWidth(column.width)} align={column.align} component="td">
{row[column.id]}
{column.id === BALANCE_TABLE_ASSET_ID ? <AssetTableCell asset={row[column.id]} /> : row[column.id]}
</TableCell>
))}
<TableCell component="td">

View File

@ -0,0 +1,3 @@
// @flow
export * from './setTokenImgToPlaceholder'

View File

@ -0,0 +1,7 @@
// @flow
import TokenPlaceholder from '~/routes/safe/components/Balances/assets/token_placeholder.svg'
export const setImageToPlaceholder = (e) => {
e.target.onerror = null
e.target.src = TokenPlaceholder
}

View File

@ -19,28 +19,30 @@ type Props = {
const RemoveOwnerForm = ({
numOwners, threshold, name, disabled, pendingTransactions,
}: Props) => (controls: React$Node) => (
}: Props) => (
controls: React$Node,
) => (
<OpenPaper controls={controls}>
<Heading tag="h2" margin="lg">
Remove Owner { !!name && name }
Remove Owner
{' '}
{!!name && name}
</Heading>
<Heading tag="h4" margin="lg">
{`Actual number of owners: ${numOwners}, threhsold of safe: ${threshold}`}
</Heading>
{ pendingTransactions &&
{pendingTransactions && (
<SnackbarContent
variant="warning"
message="Be careful removing an owner might incur in some of the pending transactions could never be executed"
/>
}
)}
<Block margin="md">
<Field
name={DECREASE_PARAM}
component={Checkbox}
type="checkbox"
disabled={disabled}
/>
<Block>{disabled && '(disabled) '}Decrease threshold?</Block>
<Field name={DECREASE_PARAM} component={Checkbox} type="checkbox" disabled={disabled} />
<Block>
{disabled && '(disabled) '}
Decrease threshold?
</Block>
</Block>
</OpenPaper>
)

View File

@ -6,7 +6,7 @@ import OpenPaper from '~/components/Stepper/OpenPaper'
import Bold from '~/components/layout/Bold'
import Heading from '~/components/layout/Heading'
import Paragraph from '~/components/layout/Paragraph'
import { DECREASE_PARAM } from '~/routes/safe/component/RemoveOwner/RemoveOwnerForm'
import { DECREASE_PARAM } from '~/routes/safe/components/RemoveOwner/RemoveOwnerForm'
type Props = {
name: string,

View File

@ -11,8 +11,8 @@ const pendingTransactionsSelector = createSelector(
)
export type SelectorProps = {
executor: userAccountSelector,
pendingTransactions: pendingTransactionsSelector,
executor: typeof userAccountSelector,
pendingTransactions: typeof pendingTransactionsSelector,
}
export default createStructuredSelector({

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -11,11 +11,11 @@ import Row from '~/components/layout/Row'
import { type Safe } from '~/routes/safe/store/models/safe'
import { type Token } from '~/logic/tokens/store/model/token'
import Transactions from '~/routes/safe/component/Transactions'
import Threshold from '~/routes/safe/component/Threshold'
import AddOwner from '~/routes/safe/component/AddOwner'
import RemoveOwner from '~/routes/safe/component/RemoveOwner'
import SendToken from '~/routes/safe/component/SendToken'
import Transactions from '~/routes/safe/components/Transactions'
import Threshold from '~/routes/safe/components/Threshold'
import AddOwner from '~/routes/safe/components/AddOwner'
import RemoveOwner from '~/routes/safe/components/RemoveOwner'
import SendToken from '~/routes/safe/components/SendToken'
import Address from './Address'
import BalanceInfo from './BalanceInfo'

View File

@ -6,7 +6,7 @@ import Bold from '~/components/layout/Bold'
import OpenPaper from '~/components/Stepper/OpenPaper'
import Heading from '~/components/layout/Heading'
import Paragraph from '~/components/layout/Paragraph'
import { TKN_DESTINATION_PARAM, TKN_VALUE_PARAM } from '~/routes/safe/component/SendToken/SendTokenForm/index'
import { TKN_DESTINATION_PARAM, TKN_VALUE_PARAM } from '~/routes/safe/components/SendToken/SendTokenForm/index'
type FormProps = {
values: Object,

View File

@ -7,7 +7,7 @@ import { sleep } from '~/utils/timer'
import { type Safe } from '~/routes/safe/store/models/safe'
import { getStandardTokenContract } from '~/logic/tokens/store/actions/fetchTokens'
import { type Token } from '~/logic/tokens/store/model/token'
import { isEther } from '~/logic/tokens/utils/tokens'
import { isEther } from '~/logic/tokens/utils/tokenHelpers'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { toNative } from '~/logic/wallets/tokens'
import { createTransaction, getSafeEthereumInstance } from '~/logic/safe/safeFrontendOperations'

View File

@ -3,9 +3,9 @@ import { createStructuredSelector } from 'reselect'
import { userAccountSelector } from '~/logic/wallets/store/selectors'
export type SelectorProps = {
userAddress: userAccountSelector,
userAddress: typeof userAccountSelector,
}
export default createStructuredSelector({
export default createStructuredSelector<Object, *>({
userAddress: userAccountSelector,
})

View File

@ -6,7 +6,7 @@ import Bold from '~/components/layout/Bold'
import OpenPaper from '~/components/Stepper/OpenPaper'
import Heading from '~/components/layout/Heading'
import Paragraph from '~/components/layout/Paragraph'
import { THRESHOLD_PARAM } from '~/routes/safe/component/Threshold/ThresholdForm'
import { THRESHOLD_PARAM } from '~/routes/safe/components/Threshold/ThresholdForm'
type FormProps = {
values: Object,

View File

@ -1,10 +1,8 @@
// @flow
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
type FetchTransactions = typeof fetchTransactions
export type Actions = {
fetchTransactions: FetchTransactions,
fetchTransactions: typeof fetchTransactions,
}
export default {

View File

@ -3,9 +3,9 @@ import { createStructuredSelector } from 'reselect'
import { userAccountSelector } from '~/logic/wallets/store/selectors'
export type SelectorProps = {
userAddress: userAccountSelector,
userAddress: typeof userAccountSelector,
}
export default createStructuredSelector({
export default createStructuredSelector<Object, *>({
userAddress: userAccountSelector,
})

View File

@ -15,7 +15,7 @@ import AttachMoney from '@material-ui/icons/AttachMoney'
import Atm from '@material-ui/icons/LocalAtm'
import DoneAll from '@material-ui/icons/DoneAll'
import CompareArrows from '@material-ui/icons/CompareArrows'
import Collapsed from '~/routes/safe/component/Transactions/Collapsed'
import Collapsed from '~/routes/safe/components/Transactions/Collapsed'
import { type Transaction } from '~/routes/safe/store/models/transaction'
import Hairline from '~/components/layout/Hairline/index'
import Button from '~/components/layout/Button'

View File

@ -7,8 +7,8 @@ import { type GlobalState } from '~/store'
import { type Confirmation } from '~/routes/safe/store/models/confirmation'
export type SelectorProps = {
confirmed: confirmationsTransactionSelector,
userAddress: userAccountSelector,
confirmed: typeof confirmationsTransactionSelector,
userAddress: typeof userAccountSelector,
executionHash: string,
}
@ -27,7 +27,7 @@ const transactionHashSector = (state: GlobalState, props: TxProps) => {
return executedConf ? executedConf.get('hash') : undefined
}
export default createStructuredSelector({
export default createStructuredSelector<Object, *>({
executionHash: transactionHashSector,
confirmed: confirmationsTransactionSelector,
userAddress: userAccountSelector,

View File

@ -3,8 +3,8 @@ import * as React from 'react'
import { List } from 'immutable'
import { connect } from 'react-redux'
import { type Transaction } from '~/routes/safe/store/models/transaction'
import NoTransactions from '~/routes/safe/component/Transactions/NoTransactions'
import GnoTransaction from '~/routes/safe/component/Transactions/Transaction'
import NoTransactions from '~/routes/safe/components/Transactions/NoTransactions'
import GnoTransaction from '~/routes/safe/components/Transactions/Transaction'
import { sameAddress } from '~/logic/wallets/ethAddresses'
import { type Confirmation } from '~/routes/safe/store/models/confirmation'
import { processTransaction } from '~/logic/safe/safeFrontendOperations'
@ -19,7 +19,9 @@ type Props = SelectorProps & Actions & {
}
class Transactions extends React.Component<Props, {}> {
componentDidMount() {
this.props.fetchTransactions(this.props.safeAddress)
const { fetchTransactions, safeAddress } = this.props
fetchTransactions(safeAddress)
}
onProcessTx = async (tx: Transaction, alreadyConfirmed: number) => {

View File

@ -7,10 +7,10 @@ import { userAccountSelector } from '~/logic/wallets/store/selectors'
export type SelectorProps = {
transactions: List<Transaction>,
userAddress: userAccountSelector,
userAddress: typeof userAccountSelector,
}
export default createStructuredSelector({
export default createStructuredSelector<Object, *>({
transactions: safeTransactionsSelector,
userAddress: userAccountSelector,
})

View File

@ -1,16 +1,13 @@
// @flow
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
import loadActiveTokens from '~/logic/tokens/store/actions/loadActiveTokens'
import fetchTokenBalances from '~/routes/safe/store/actions/fetchTokenBalances'
export type Actions = {
fetchSafe: typeof fetchSafe,
loadActiveTokens: typeof loadActiveTokens,
fetchTokenBalances: typeof fetchTokenBalances,
}
export default {
fetchSafe,
loadActiveTokens,
fetchTokenBalances,
}

View File

@ -2,7 +2,7 @@
import * as React from 'react'
import { connect } from 'react-redux'
import Page from '~/components/layout/Page'
import Layout from '~/routes/safe/component/Layout'
import Layout from '~/routes/safe/components/Layout'
import selector, { type SelectorProps } from './selector'
import actions, { type Actions } from './actions'
@ -16,15 +16,13 @@ const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 15000
class SafeView extends React.Component<Props> {
componentDidMount() {
const {
fetchSafe, loadActiveTokens, activeTokens, safeUrl, fetchTokenBalances,
fetchSafe, activeTokens, safeUrl, fetchTokenBalances,
} = this.props
fetchSafe(safeUrl)
// loadActiveTokens(safeUrl)
fetchTokenBalances(safeUrl, activeTokens)
this.intervalId = setInterval(() => {
// update in another function so it uses up-to-date props values
this.checkForUpdates()
}, TIMEOUT)
}

View File

@ -0,0 +1,8 @@
// @flow
import { createAction } from 'redux-actions'
export const ACTIVATE_TOKEN_FOR_ALL_SAFES = 'ACTIVATE_TOKEN_FOR_ALL_SAFES'
const activateTokenForAllSafes = createAction<string, *>(ACTIVATE_TOKEN_FOR_ALL_SAFES)
export default activateTokenForAllSafes

View File

@ -9,8 +9,9 @@ import { getActiveTokensAddressesForAllSafes } from '~/routes/safe/store/selecto
import { tokensSelector } from '~/logic/tokens/store/selectors'
import type { Token } from '~/logic/tokens/store/model/token'
import { saveActiveTokens } from '~/logic/tokens/utils/tokensStorage'
import { ACTIVATE_TOKEN_FOR_ALL_SAFES } from '~/routes/safe/store/actions/activateTokenForAllSafes'
const watchedActions = [ADD_SAFE, UPDATE_SAFE]
const watchedActions = [ADD_SAFE, UPDATE_SAFE, ACTIVATE_TOKEN_FOR_ALL_SAFES]
const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => async (action: AnyAction) => {
const handledAction = next(action)
@ -21,7 +22,7 @@ const safeStorageMware = (store: Store<GlobalState>) => (next: Function) => asyn
saveSafes(safes.toJSON())
// recalculate active tokens
if (action.payload.activeTokens) {
if (action.payload.activeTokens || action.type === ACTIVATE_TOKEN_FOR_ALL_SAFES) {
const tokens = tokensSelector(state)
const activeTokenAddresses = getActiveTokensAddressesForAllSafes(state)

View File

@ -8,6 +8,7 @@ import { type OwnerProps } from '~/routes/safe/store/models/owner'
import { loadFromStorage } from '~/utils/storage'
import { SAFES_KEY } from '~/logic/safe/utils'
import { UPDATE_SAFE } from '~/routes/safe/store/actions/updateSafe'
import { ACTIVATE_TOKEN_FOR_ALL_SAFES } from '~/routes/safe/store/actions/activateTokenForAllSafes'
export const SAFE_REDUCER_ID = 'safes'
@ -63,6 +64,20 @@ export default handleActions<State, *>(
return state.update(safeAddress, prevSafe => prevSafe.merge(safe))
},
[ACTIVATE_TOKEN_FOR_ALL_SAFES]: (state: State, action: ActionType<Function>): State => {
const tokenAddress = action.payload
const newState = state.withMutations((map) => {
map.keySeq().forEach((safeAddress) => {
const safeActiveTokens = map.getIn([safeAddress, 'activeTokens'])
const activeTokens = safeActiveTokens.push(tokenAddress)
map.update(safeAddress, prevSafe => prevSafe.merge({ activeTokens }))
})
})
return newState
},
[ADD_SAFE]: (state: State, action: ActionType<Function>): State => {
const { safe }: { safe: SafeProps } = action.payload

View File

@ -1,14 +1,14 @@
// @flow
import { type Store } from 'redux'
import TestUtils from 'react-dom/test-utils'
import SafeView from '~/routes/safe/component/Safe'
import SafeView from '~/routes/safe/components/Safe'
import { aNewStore, type GlobalState } from '~/store'
import { sleep } from '~/utils/timer'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { addEtherTo } from '~/test/utils/tokenMovements'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { travelToSafe } from '~/test/builder/safe.dom.utils'
import { MOVE_FUNDS_BUTTON_TEXT } from '~/routes/safe/component/Safe/BalanceInfo'
import { MOVE_FUNDS_BUTTON_TEXT } from '~/routes/safe/components/Safe/BalanceInfo'
export type DomSafe = {
address: string,

View File

@ -2,7 +2,7 @@
import * as React from 'react'
import TestUtils from 'react-dom/test-utils'
import ListItemText from '~/components/List/ListItemText/index'
import { SEE_MULTISIG_BUTTON_TEXT } from '~/routes/safe/component/Safe/MultisigTx'
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 { Provider } from 'react-redux'

View File

@ -1,7 +1,7 @@
// @flow
import TestUtils from 'react-dom/test-utils'
import { List } from 'immutable'
import Transaction from '~/routes/safe/component/Transactions/Transaction'
import Transaction from '~/routes/safe/components/Transactions/Transaction'
import {
listTxsClickingOn,
LIST_TXS_INDEX,

View File

@ -7,11 +7,11 @@ import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
import { type Safe } from '~/routes/safe/store/models/safe'
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/component/AddOwner/AddOwnerForm'
import { addOwner } from '~/routes/safe/component/AddOwner/index'
import { NAME_PARAM, OWNER_ADDRESS_PARAM, INCREASE_PARAM } from '~/routes/safe/components/AddOwner/AddOwnerForm'
import { addOwner } from '~/routes/safe/components/AddOwner/index'
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
import { removeOwner, shouldDecrease, initialValuesFrom } from '~/routes/safe/component/RemoveOwner'
import { DECREASE_PARAM } from '~/routes/safe/component/RemoveOwner/RemoveOwnerForm'
import { removeOwner, shouldDecrease, initialValuesFrom } from '~/routes/safe/components/RemoveOwner'
import { DECREASE_PARAM } from '~/routes/safe/components/RemoveOwner/RemoveOwnerForm'
import { getSafeFrom } from '~/test/utils/safeHelper'
import { getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields'
import { processTransaction } from '~/logic/safe/safeFrontendOperations'

View File

@ -3,7 +3,7 @@ import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer'
import { checkMinedTx, checkPendingTx } from '~/test/builder/safe.dom.utils'
import { whenExecuted } from '~/test/utils/logTransactions'
import AddOwner from '~/routes/safe/component/AddOwner'
import AddOwner from '~/routes/safe/components/AddOwner'
export const sendAddOwnerForm = async (
SafeDom: React$Component<any, any>,

View File

@ -2,7 +2,7 @@
import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer'
import { checkMinedTx, checkPendingTx } from '~/test/builder/safe.dom.utils'
import SendToken from '~/routes/safe/component/SendToken'
import SendToken from '~/routes/safe/components/SendToken'
import { whenExecuted } from '~/test/utils/logTransactions'
export const sendMoveFundsForm = async (

View File

@ -5,7 +5,7 @@ import { sleep } from '~/utils/timer'
import * as fetchTokensAction from '~/logic/tokens/store/actions/fetchTokens'
import { checkMinedTx, checkPendingTx, EXPAND_BALANCE_INDEX } from '~/test/builder/safe.dom.utils'
import { whenExecuted } from '~/test/utils/logTransactions'
import SendToken from '~/routes/safe/component/SendToken'
import SendToken from '~/routes/safe/components/SendToken'
import { makeToken, type Token } from '~/logic/tokens/store/model/token'
import addTokens from '~/logic/tokens/store/actions/saveTokens'

View File

@ -4,7 +4,7 @@ import { sleep } from '~/utils/timer'
import { checkMinedTx, EXPAND_OWNERS_INDEX, checkPendingTx } from '~/test/builder/safe.dom.utils'
import { filterMoveButtonsFrom } from '~/test/builder/safe.dom.builder'
import { whenExecuted } from '~/test/utils/logTransactions'
import RemoveOwner from '~/routes/safe/component/RemoveOwner'
import RemoveOwner from '~/routes/safe/components/RemoveOwner'
export const sendRemoveOwnerForm = async (
SafeDom: React$Component<any, any>,

View File

@ -3,7 +3,7 @@ import TestUtils from 'react-dom/test-utils'
import { sleep } from '~/utils/timer'
import { checkMinedTx } from '~/test/builder/safe.dom.utils'
import { getGnosisSafeInstanceAt } from '~/logic/contracts/safeContracts'
import Threshold from '~/routes/safe/component/Threshold'
import Threshold from '~/routes/safe/components/Threshold'
import { whenExecuted } from '~/test/utils/logTransactions'
export const sendChangeThresholdForm = async (

View File

@ -106,8 +106,8 @@ export default createMuiTheme({
fontFamily: 'Roboto Mono, monospace',
fontSize: '12px',
padding: `0 0 0 ${md}`,
position: 'relative',
top: '20px',
position: 'absolute',
top: '5px',
color: secondary,
order: 0,
marginTop: '0px',

470
yarn.lock
View File

@ -1086,7 +1086,7 @@
dependencies:
regenerator-runtime "^0.12.0"
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3":
"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.1.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.3":
version "7.4.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.3.tgz#79888e452034223ad9609187a0ad1fe0d2ad4bdc"
integrity sha512-9lsJwJLxDh/T3Q3SZszfWOTkk3pHbkmH+3KY+zwIDmsNlxsumuhS2TH3NIpktU4kNvfzy+k3eLT7aTJSPTo0OA==
@ -1571,15 +1571,15 @@
dependencies:
uuid "^3.1.0"
"@storybook/addon-actions@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.0.9.tgz#c604ea9086ff517a488a2605ff040539ae68b103"
integrity sha512-npkesPnVB8Vi18pM0wT3fn67DqZ3lZmxqahdHn+SI7ROR+Jm6mcOAOCPqKZtpWIyvLBqgK8BuodXNL04cNhIeg==
"@storybook/addon-actions@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-5.0.10.tgz#7791ee26c41c63f6d2f36ec0b41108ba9b138171"
integrity sha512-zPwGMsS11uoKu/gBkBdcdXMtAle2u04O7B1rWFoHFtbQRX+ZDgtkjtSRldpn9t6MYEqJmZ4s3TUxbwv6hKeBOQ==
dependencies:
"@storybook/addons" "5.0.9"
"@storybook/components" "5.0.9"
"@storybook/core-events" "5.0.9"
"@storybook/theming" "5.0.9"
"@storybook/addons" "5.0.10"
"@storybook/components" "5.0.10"
"@storybook/core-events" "5.0.10"
"@storybook/theming" "5.0.10"
core-js "^2.6.5"
fast-deep-equal "^2.0.1"
global "^4.3.2"
@ -1607,15 +1607,15 @@
react-inspector "^2.2.2"
uuid "^3.2.1"
"@storybook/addon-knobs@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-5.0.9.tgz#1310822a0cccc3606fe28e9c42e30982f28cf90a"
integrity sha512-ZMSbd507Brvsn6Flm1V0DQVM50ZtbBlu5+wZRXCMwBA7D2pYVJbjwYVdRl7Ms4RA4g6u3GzRfzCPIXefs91qbQ==
"@storybook/addon-knobs@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-5.0.10.tgz#6c8828ee188572ce7ba2430846e875318b049cbf"
integrity sha512-5HIncloKy/cj/q2RoW2b9Xe5Ew41v9wDSN3XLiOgsr1TA1uZslStoIfvhuHT4I0rBFTYEgjWebBGgnuY7vvZoA==
dependencies:
"@storybook/addons" "5.0.9"
"@storybook/components" "5.0.9"
"@storybook/core-events" "5.0.9"
"@storybook/theming" "5.0.9"
"@storybook/addons" "5.0.10"
"@storybook/components" "5.0.10"
"@storybook/core-events" "5.0.10"
"@storybook/theming" "5.0.10"
copy-to-clipboard "^3.0.8"
core-js "^2.6.5"
escape-html "^1.0.3"
@ -1629,57 +1629,57 @@
react-select "^2.3.0"
util-deprecate "^1.0.2"
"@storybook/addon-links@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-5.0.9.tgz#e450b5038a31cc6e83167c7fa497500c2c5388f8"
integrity sha512-EmK5MnjmELg3XIlEVboOfNlJPLm/flqgtPuRCqZZFQQTN3I+dP7vcdel2y2Q6QlRP4cuODHTuYL+2sXauWtDDQ==
"@storybook/addon-links@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-5.0.10.tgz#abf97d9d336a76ea773e71781a0bc1808ff1dd42"
integrity sha512-dDiwtHtJydN0fAGKWlWIFQUA8wAiMEepWfKf3Fi7a7gW5syZf9HczlqKqJW9R0oUshPJ+GBTr5Ua49Yan6+9RQ==
dependencies:
"@storybook/addons" "5.0.9"
"@storybook/core-events" "5.0.9"
"@storybook/addons" "5.0.10"
"@storybook/core-events" "5.0.10"
common-tags "^1.8.0"
core-js "^2.6.5"
global "^4.3.2"
prop-types "^15.6.2"
qs "^6.5.2"
"@storybook/addons@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.0.9.tgz#27791868c84acf36e16ec7b0c61c878b82dbae32"
integrity sha512-PzAiLWziVpLlyZ6yzu8f86J9HIbUiSbbRe4t9nMrR9W54rbIqciM9DFq0HdX2KkuTFhQWnAdzD/WhpLcZpB5PA==
"@storybook/addons@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-5.0.10.tgz#8911e6e7797185327f0117035a4bc451a57e62d7"
integrity sha512-plpLh17dt8KWhs8dRQlleClc7sibE1Plq7QQWyAsZjblRHfpNnv82Ax9ArmMeGFx2TRTTbCOcw9PiaKkt5/E7Q==
dependencies:
"@storybook/channels" "5.0.9"
"@storybook/client-logger" "5.0.9"
"@storybook/channels" "5.0.10"
"@storybook/client-logger" "5.0.10"
core-js "^2.6.5"
global "^4.3.2"
util-deprecate "^1.0.2"
"@storybook/channel-postmessage@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.0.9.tgz#e357f3645cf1ac708a00e345841ce94cf9ab7e81"
integrity sha512-GEmYXOFZf1M3CqvB71F5e5MZmEHsOjwdggyxXymzpnjbe9NtUyUKkvU7NCE5/Xmv6SA6Am9lyyrAjQ8EnQBdeA==
"@storybook/channel-postmessage@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-5.0.10.tgz#ade24994e57d7c684d334c2dac3dd049e36c08ff"
integrity sha512-5qM6JhgO0eXUcos+CNckq1gOVYJNi9LUBBT0yniO3PdEf7CzwQicv0pTyoFXfUwVNdRobXNPihErqceScXxcFQ==
dependencies:
"@storybook/channels" "5.0.9"
"@storybook/client-logger" "5.0.9"
"@storybook/channels" "5.0.10"
"@storybook/client-logger" "5.0.10"
core-js "^2.6.5"
global "^4.3.2"
telejson "^2.1.0"
"@storybook/channels@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.0.9.tgz#a750b349a8278ab58bdcc41ae00f5cb60644ad83"
integrity sha512-JX9repbRH6WVRT1A6KQA7mDkowFhWHJbMG8WtZ1hCXgwFBKmN01IKspZrZj9vokyVIngWGxt52BnOJ6NdaF5SA==
"@storybook/channels@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-5.0.10.tgz#b1ae31784359a3d12403a53a5be8eb2327c4a467"
integrity sha512-5WWSHEI6uFkzv3E5UaqMH2H0BFCI1CyPrJRUZyhsrBcnJctUQ+4J74IMCP9FQhaBCc6yLQlKWLpllaIHB5kPbA==
dependencies:
core-js "^2.6.5"
"@storybook/client-api@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.0.9.tgz#d0942a17aa114129a2bcb7eae32eeccb0b54e126"
integrity sha512-HkquVtwfX0lX0J2t+sQJ54FKOiVwg3QbpWyi9Ujf8QPS3xDR1BpJqZ+P7DjLZDYFcPmeb5QWokA59fEANwutNw==
"@storybook/client-api@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/client-api/-/client-api-5.0.10.tgz#c9cae5e35369658415a3f41d9a65418605664ad1"
integrity sha512-AfzSvXKfnQQQQUs3U+AecIJx0aNW0NT+pb8OcQLsO47gKdSTE2ursRiii7+YbjSG96/cL4mpdD/AmFoWJ+ubow==
dependencies:
"@storybook/addons" "5.0.9"
"@storybook/client-logger" "5.0.9"
"@storybook/core-events" "5.0.9"
"@storybook/router" "5.0.9"
"@storybook/addons" "5.0.10"
"@storybook/client-logger" "5.0.10"
"@storybook/core-events" "5.0.10"
"@storybook/router" "5.0.10"
common-tags "^1.8.0"
core-js "^2.6.5"
eventemitter3 "^3.1.0"
@ -1691,10 +1691,10 @@
memoizerific "^1.11.3"
qs "^6.5.2"
"@storybook/client-logger@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.0.9.tgz#39dcabcfaee3ea04cab5a95ac9027459581d1731"
integrity sha512-EIWrXzScR5Ex1rdPgngECFrY8c/ngR4V6lgMdEJypW2GUbcRDRZPdJ13KSaDvkbSwkfHKZmKsjYLlOM2Ss0oOg==
"@storybook/client-logger@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-5.0.10.tgz#710b249c30aa320a0aef7da464d7e621a390bf92"
integrity sha512-Nh4dJ8rTPtOT1/Bef39+4HZVYX6EJthMpjjV04AWxT5ngxBa2MzhmcbnoYc3NOBSRh9fhJ6jm14/skQmLAO/jQ==
dependencies:
core-js "^2.6.5"
@ -1707,16 +1707,16 @@
glamorous "^4.12.1"
prop-types "^15.6.1"
"@storybook/components@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.0.9.tgz#981610abea5fba57f7399e62728cac9fd9339db9"
integrity sha512-4CCfVva0S4HkeotyvBSSjatAiPeUFZUpMm7YB586vsAGKmobZnLUZ2jKoYKZTJS/Z7WVOnHHLLv+wQ/PvYZpew==
"@storybook/components@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-5.0.10.tgz#e0e7eed0e42160a8143fb7e57e7b45bb1ed71841"
integrity sha512-G2+2+8y3vFBvOqbaqOLDAjWFM9iO3TNnWadqkS5t6jAsl/pCVozKecPihR8S7Qr4Joy3PpdVSXGjFNFDWVJT4g==
dependencies:
"@storybook/addons" "5.0.9"
"@storybook/client-logger" "5.0.9"
"@storybook/core-events" "5.0.9"
"@storybook/router" "5.0.9"
"@storybook/theming" "5.0.9"
"@storybook/addons" "5.0.10"
"@storybook/client-logger" "5.0.10"
"@storybook/core-events" "5.0.10"
"@storybook/router" "5.0.10"
"@storybook/theming" "5.0.10"
core-js "^2.6.5"
global "^4.3.2"
immer "^1.12.0"
@ -1738,32 +1738,32 @@
recompose "^0.30.0"
render-fragment "^0.1.1"
"@storybook/core-events@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.0.9.tgz#4b7a33f271a5ed7994a702c74d6a3ad117ba168f"
integrity sha512-gZtqZRflqhtH7uJMkdTWn4bRlfQU0PrAb/VeSCv20N/3HGCyKOwKhzCeV74u8A0FyVMVJfM0vWrjKMBC9LNyUQ==
"@storybook/core-events@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/core-events/-/core-events-5.0.10.tgz#6437f8b6a6c3c902fa2fbad8de992c5104115332"
integrity sha512-Hp8PleSXAbVNr/yi58JIQb/tjZVpRcjEe8ztIp4JT5qhpz+xHTiVnS7mo8gCdyMw5cr38ANgdlZGnLshJY29lQ==
dependencies:
core-js "^2.6.5"
"@storybook/core@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.0.9.tgz#2bad4eebc4cdc5aaf12635a53f3cd7612ee77278"
integrity sha512-OT7TFzCUOhmYiWhj1txbWFBW9HeyAYePcJyp6UARWK20TPR45OS5DZSJq2LF/DaIUrtVGJmwxMWNp08mkazhQA==
"@storybook/core@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-5.0.10.tgz#fa9632a97fa97fd86c75c9fbeb02a54c34c7e903"
integrity sha512-b87JULxcvZxyM3w8JwdW5iJAt9aVqohfFA3v6dTGSq+H6q8do2rGD3nBCG/iaLsy1NnSskLw6Cd2BNuLDvvWOA==
dependencies:
"@babel/plugin-proposal-class-properties" "^7.3.0"
"@babel/plugin-proposal-object-rest-spread" "^7.3.2"
"@babel/plugin-syntax-dynamic-import" "^7.2.0"
"@babel/plugin-transform-react-constant-elements" "^7.2.0"
"@babel/preset-env" "^7.4.1"
"@storybook/addons" "5.0.9"
"@storybook/channel-postmessage" "5.0.9"
"@storybook/client-api" "5.0.9"
"@storybook/client-logger" "5.0.9"
"@storybook/core-events" "5.0.9"
"@storybook/node-logger" "5.0.9"
"@storybook/router" "5.0.9"
"@storybook/theming" "5.0.9"
"@storybook/ui" "5.0.9"
"@storybook/addons" "5.0.10"
"@storybook/channel-postmessage" "5.0.10"
"@storybook/client-api" "5.0.10"
"@storybook/client-logger" "5.0.10"
"@storybook/core-events" "5.0.10"
"@storybook/node-logger" "5.0.10"
"@storybook/router" "5.0.10"
"@storybook/theming" "5.0.10"
"@storybook/ui" "5.0.10"
airbnb-js-shims "^1 || ^2"
autoprefixer "^9.4.7"
babel-plugin-add-react-displayname "^0.0.5"
@ -1819,10 +1819,10 @@
webpack-dev-middleware "^3.5.1"
webpack-hot-middleware "^2.24.3"
"@storybook/node-logger@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.0.9.tgz#d971301c27c9c8e957649cf868456052f0846f15"
integrity sha512-QJPUAoFEBtZiHZOohO0+/fbS+sNm36aEOy2H6+QP5fRjnHVNoayurFYro2AlBU+ONvQ31cG0Ou9X+2UAzusDEg==
"@storybook/node-logger@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-5.0.10.tgz#ee1908c30d5fd0262e3b01c13cfd92b07dbbb083"
integrity sha512-+ais31IeGdbJ1AyZ0MRoNdWnIjZmqrp7SBgwyj37EKn1isgTsN/iP6xqEgmAdWlxMTPRFExYMD3pkxip1WtwaQ==
dependencies:
chalk "^2.4.2"
core-js "^2.6.5"
@ -1830,17 +1830,17 @@
pretty-hrtime "^1.0.3"
regenerator-runtime "^0.12.1"
"@storybook/react@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.0.9.tgz#a4da49f9fd922ea017acd4da242c66816192a358"
integrity sha512-V8TMnAAPLdKewdorLQrUKmUZKzugCdd4/LAGPhVhAYnMTs2PPykU1rYng7+Lgq4aTpoDUOUn+59O8h8V2+uiYQ==
"@storybook/react@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.0.10.tgz#95f886a7beff1c7e8a1f8478a652c42661a5c16c"
integrity sha512-oYtD+JccEx5y1HCmuK5xBkm4gQ+PIoYqGhi0sV+MCNEhP0CulUQCHkain+QhvNaysgT68AqDyk3/H08gy3Sh1w==
dependencies:
"@babel/plugin-transform-react-constant-elements" "^7.2.0"
"@babel/preset-flow" "^7.0.0"
"@babel/preset-react" "^7.0.0"
"@storybook/core" "5.0.9"
"@storybook/node-logger" "5.0.9"
"@storybook/theming" "5.0.9"
"@storybook/core" "5.0.10"
"@storybook/node-logger" "5.0.10"
"@storybook/theming" "5.0.10"
"@svgr/webpack" "^4.0.3"
babel-plugin-named-asset-import "^0.3.0"
babel-plugin-react-docgen "^2.0.2"
@ -1856,26 +1856,26 @@
semver "^5.6.0"
webpack "^4.29.0"
"@storybook/router@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.0.9.tgz#89e5ef2600d9c9015435b909b9929edad7af3cd1"
integrity sha512-ruHXh4crwfkE9Z4KNwcQdGJi1yK4RKaYP1NDW8M/rLdw0m5ybGZcrLzvnJPCT5R5JEmV5DzAjVzXp6IA5fk7yg==
"@storybook/router@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.0.10.tgz#a756dc521fc4df19a090fcc23eed0a5de5fedc87"
integrity sha512-mHxMynnsbUNcr1GoXXunRVI+JvDTBE/lAAdqzMUduI4E6eUv8MHXw2KfeNQcZaNAf0PLynvbqJd2qpfMpKo/zA==
dependencies:
"@reach/router" "^1.2.1"
"@storybook/theming" "5.0.9"
"@storybook/theming" "5.0.10"
core-js "^2.6.5"
global "^4.3.2"
memoizerific "^1.11.3"
qs "^6.5.2"
"@storybook/theming@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.0.9.tgz#3daef3d2eb5d9e4f68399f44920df3d6e62fd623"
integrity sha512-KuzRKaQIyYwFPc6MSWdpMCy4lQlvcmCNDMTRzH73+qNewka+c+gdOBzgQt3dn3uG0e8hBbsa1gx/URTZAgf7Pg==
"@storybook/theming@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/theming/-/theming-5.0.10.tgz#6e2b00f879678419e2297ed8a31c357ae7976801"
integrity sha512-4IUtWglyAQCPHKMqPZkTWc/8FbfGHwtRSbaNxbv5S6PEcfWPIiMVWWRYMBNyETvYoYbCOHORH1w7iwJs75sRmA==
dependencies:
"@emotion/core" "^10.0.7"
"@emotion/styled" "^10.0.7"
"@storybook/client-logger" "5.0.9"
"@storybook/client-logger" "5.0.10"
common-tags "^1.8.0"
core-js "^2.6.5"
deep-object-diff "^1.1.0"
@ -1888,17 +1888,17 @@
prop-types "^15.6.2"
react-inspector "^2.3.1"
"@storybook/ui@5.0.9":
version "5.0.9"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.0.9.tgz#87f317703690cbb9ef7084933e60a8bbe1c1a701"
integrity sha512-4GEtSDT3TL5NICgPeXnm16MDu9e0Yt/7Ummx8jaUdA9okOLDklqTshfHX1LZpkk8NvEoX0l8R56yVGAMgc0GIg==
"@storybook/ui@5.0.10":
version "5.0.10"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-5.0.10.tgz#58b7d8c706776eb9c048d3dc69bedc8a198b0609"
integrity sha512-iKMmfY5MCJ3hVrWxqlN0t1sldJhnx9t0cXp91yI8Y+cV190Yw3KI5nE8kHF2ETInhHLfSRSl4Ssz/Xi2s4AsKg==
dependencies:
"@storybook/addons" "5.0.9"
"@storybook/client-logger" "5.0.9"
"@storybook/components" "5.0.9"
"@storybook/core-events" "5.0.9"
"@storybook/router" "5.0.9"
"@storybook/theming" "5.0.9"
"@storybook/addons" "5.0.10"
"@storybook/client-logger" "5.0.10"
"@storybook/components" "5.0.10"
"@storybook/core-events" "5.0.10"
"@storybook/router" "5.0.10"
"@storybook/theming" "5.0.10"
core-js "^2.6.5"
fast-deep-equal "^2.0.1"
fuzzy-search "^3.0.1"
@ -10469,11 +10469,6 @@ lodash.pick@^4.4.0:
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
lodash.range@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/lodash.range/-/lodash.range-3.2.0.tgz#f461e588f66683f7eadeade513e38a69a565a15d"
integrity sha1-9GHliPZmg/fq3q3lE+OKaaVloV0=
lodash.some@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
@ -13097,6 +13092,13 @@ react-fast-compare@^2.0.2:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-final-form-listeners@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-final-form-listeners/-/react-final-form-listeners-1.0.2.tgz#b52da984300281cf1f69a6412e86df6249e2bf1c"
integrity sha512-AaUUHcXRhD3esC80yUfYPI8FJ3TUiMu0f4hk18QL8NMCWjokg6NWS32WkRJsH3bLWDoiy7+uNVOAAyO/XoupyA==
dependencies:
"@babel/runtime" "^7.1.5"
react-final-form@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/react-final-form/-/react-final-form-4.1.0.tgz#4e1b513de164771b2b824f3fb9c0548014255971"
@ -15603,16 +15605,16 @@ truffle-artifactor@^2.1.2:
truffle-contract "^2.0.3"
truffle-contract-schema "^0.0.5"
truffle-artifactor@^4.0.10:
version "4.0.10"
resolved "https://registry.yarnpkg.com/truffle-artifactor/-/truffle-artifactor-4.0.10.tgz#a604329dfd0d004a4c6299062dbb226ce411ce8e"
integrity sha512-+3UB6XJvBOATNK1tZb0I+r6JsNWl6785XseFGtPTByvWqhciQTU+/IBj68vEjzbZmRmHtf/aj9snH7cmvuV2yw==
truffle-artifactor@^4.0.11:
version "4.0.11"
resolved "https://registry.yarnpkg.com/truffle-artifactor/-/truffle-artifactor-4.0.11.tgz#84b2e059123f0c531eb552995569033693abaea9"
integrity sha512-J8Xgez/flyP6/ZTI4qT3T3H5/EuM5tQFXJviIFb1+3zXWFM2UcdrcI29RJUdqHdushxCMmXE5kH3KpxCY1jGWQ==
dependencies:
async "2.6.1"
debug "^4.1.0"
fs-extra "6.0.1"
lodash "4.17.11"
truffle-contract "^4.0.11"
truffle-contract "^4.0.12"
truffle-contract-schema "^3.0.6"
truffle-expect "^0.0.7"
@ -15633,10 +15635,10 @@ truffle-blockchain-utils@^0.0.8:
resolved "https://registry.yarnpkg.com/truffle-blockchain-utils/-/truffle-blockchain-utils-0.0.8.tgz#09995c36016a54092b337f237c3dc1a3dca12341"
integrity sha512-4dbgqd4GrloKNLiaXACiymE3R2PsNFOlbgOh/CGkQVLArtcbgBAl7Fg2l5yVfDV8dtOFWHddj/2UkY25KY1+Dw==
truffle-box@^1.0.20:
version "1.0.20"
resolved "https://registry.yarnpkg.com/truffle-box/-/truffle-box-1.0.20.tgz#2069ebca20026b5ce783c42fde5f7e72d57d67d1"
integrity sha512-pfTJbvi9eQG6B2cIw0BibOOCvnEsHpadVTsmXECJhxcf34QH6fYCwPdExe8fgu2p5r6g4+77RJ/21n2h7IMvUw==
truffle-box@^1.0.21:
version "1.0.21"
resolved "https://registry.yarnpkg.com/truffle-box/-/truffle-box-1.0.21.tgz#ee1fe77cc0e376b31c5f83b96e6c19c3089ca25c"
integrity sha512-tO6mDqKjTmOKaFGUv5JmeZj/aZzoT0RT87QyI8rgKM4x3Yx6s/Q1c7p3ltCbXoMHjx0Wx+zakyZ1ZUJB9ITEuQ==
dependencies:
fs-extra "6.0.1"
github-download "^0.5.0"
@ -15650,21 +15652,21 @@ truffle-code-utils@^1.2.1:
resolved "https://registry.yarnpkg.com/truffle-code-utils/-/truffle-code-utils-1.2.1.tgz#5abe1ce8237ee90ca511c7a612b98d545030a47f"
integrity sha512-baCmNq6dcRnRkoGdSS4e0/yNtsmCyWApCxjjB18fNaavs6QGNQVguFJ3n4Dd7dglQxc4dqwjcngt2I+GFIAt5w==
truffle-compile-vyper@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/truffle-compile-vyper/-/truffle-compile-vyper-1.0.10.tgz#bccb742156a75f65dab1e60f6a8656030cd9bed7"
integrity sha512-sLCpfC5mRCj8Ny6u6ctve/Hmd9gQvztLtx/CUYfxC53otSh0iNzXpgJ0vkj/MRjpdeyTYd/YRu6iCV1qDewTNQ==
truffle-compile-vyper@^1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/truffle-compile-vyper/-/truffle-compile-vyper-1.0.11.tgz#1e561ab2a5da1ddf0cb4791e6d89fec9b5905824"
integrity sha512-qSOsiCOxNGqEtqQf/TA0/MxThkrEtJVbZy7HLGie9lIYoUtct7W1q1nkJS6XecKlZtW/aQm/1dlYfDNultwbug==
dependencies:
async "2.6.1"
colors "^1.1.2"
eslint "^5.5.0"
minimatch "^3.0.4"
truffle-compile "^4.0.10"
truffle-compile "^4.0.11"
truffle-compile@^4.0.10:
version "4.0.10"
resolved "https://registry.yarnpkg.com/truffle-compile/-/truffle-compile-4.0.10.tgz#ecc5ec91760392f3ec5bc0bb86c1b95b68357dab"
integrity sha512-FDW9lDKif69pCbZQAUgEUp9K3wp9V4RuyDVhAJQ19bm8gq1Ietw+59yZJa3EukiVvmEZvz9M8P7ux/jyevQwQg==
truffle-compile@^4.0.11:
version "4.0.11"
resolved "https://registry.yarnpkg.com/truffle-compile/-/truffle-compile-4.0.11.tgz#261e31c9efc4e807e8084fdd1322405f04c20378"
integrity sha512-rgwvQwVlCyryhOzkbALNePEtsR2wTrwaUgnEm5mefCFWHmSFgB/sw2u6CT4wb1aOAofeYgkQXlUzS9qmM+7jTg==
dependencies:
async "2.6.1"
colors "^1.1.2"
@ -15676,12 +15678,12 @@ truffle-compile@^4.0.10:
require-from-string "^2.0.2"
semver "^5.6.0"
solc "0.5.0"
truffle-config "^1.1.7"
truffle-config "^1.1.8"
truffle-contract-sources "^0.1.3"
truffle-error "^0.0.4"
truffle-expect "^0.0.7"
truffle-config@^1.0.1, truffle-config@^1.1.7:
truffle-config@^1.0.1:
version "1.1.7"
resolved "https://registry.yarnpkg.com/truffle-config/-/truffle-config-1.1.7.tgz#dba089e6479cbe7bdb2a5d661624c61b4ffe67b1"
integrity sha512-0AAhsl6cbNhGwOBlceVCDKRLlaePMwUpba4268Phy8lt/n/Py1/nmO6TgG9x2AafiaLTLLSNwtMDNBaktgw0pw==
@ -15693,6 +15695,18 @@ truffle-config@^1.0.1, truffle-config@^1.1.7:
truffle-error "^0.0.4"
truffle-provider "^0.1.6"
truffle-config@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/truffle-config/-/truffle-config-1.1.8.tgz#3df667d08dddf8ab57f607925a1008924fdd60f7"
integrity sha512-0auelJDz2aZztxO12T+y32wjYh/Dj/ENOfqD/d7+wEa0TMdBHGTnmSJ62eS/JryMwQEbAt9gRE7l4afH18uAJw==
dependencies:
configstore "^4.0.0"
find-up "^2.1.0"
lodash "4.17.11"
original-require "1.0.1"
truffle-error "^0.0.4"
truffle-provider "^0.1.6"
truffle-contract-schema@^0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/truffle-contract-schema/-/truffle-contract-schema-0.0.5.tgz#5e9d20bd0bf2a27fe94310748249d484eee49961"
@ -15742,20 +15756,10 @@ truffle-contract@4.0.0-next.0:
web3-eth-abi "1.0.0-beta.35"
web3-utils "1.0.0-beta.35"
truffle-contract@^2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/truffle-contract/-/truffle-contract-2.0.5.tgz#3394df90ffa927d106ae3b36b33c6debf9117491"
integrity sha512-ItnN85wh4qVYPg6T4CpubI40c8dWEArtUcWcDoZ7xzj9DL7cwxqstJ0yRxyQIh4u8SRSlrOtm1dh0B7R8jtG+w==
dependencies:
ethjs-abi "0.1.8"
truffle-blockchain-utils "^0.0.3"
truffle-contract-schema "^0.0.5"
web3 "^0.20.1"
truffle-contract@^4.0.11:
version "4.0.11"
resolved "https://registry.yarnpkg.com/truffle-contract/-/truffle-contract-4.0.11.tgz#587d0e032c33ad320b7e12f1093eb789c62a8275"
integrity sha512-lzKFdLngTSt7MQMOvsUhOEPUjagSbGVkhQm7rSant4Y/VSWIppL3GXqpTOzdcOJMHgL9iYlMEm42+pHXq6DZxg==
truffle-contract@4.0.12, truffle-contract@^4.0.12:
version "4.0.12"
resolved "https://registry.yarnpkg.com/truffle-contract/-/truffle-contract-4.0.12.tgz#b7ecf7f8398936a0d0f1b57c18a4be60ea8b22a1"
integrity sha512-/ZfGvBgMB+NcKtJ0gpq803JyhNW0BNiEb29HgEr0FS7rLh4fGXD7gfYzwWwl3neKLeqGtAyhxEPMPBOTqNe+xw==
dependencies:
bignumber.js "^7.2.1"
ethers "^4.0.0-beta.1"
@ -15768,10 +15772,20 @@ truffle-contract@^4.0.11:
web3-eth-abi "1.0.0-beta.37"
web3-utils "1.0.0-beta.37"
truffle-core@^5.0.12:
version "5.0.12"
resolved "https://registry.yarnpkg.com/truffle-core/-/truffle-core-5.0.12.tgz#bc89b6429fd3de21e3ed816438840945f71673e5"
integrity sha512-G6JVqOK7vr2MSbDD59yEYHGhn7nFgMm35YbyahsxI5QyphfTFTntTmI/L+RAX37dZhfuR4OuAlYWjivA6kzXuQ==
truffle-contract@^2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/truffle-contract/-/truffle-contract-2.0.5.tgz#3394df90ffa927d106ae3b36b33c6debf9117491"
integrity sha512-ItnN85wh4qVYPg6T4CpubI40c8dWEArtUcWcDoZ7xzj9DL7cwxqstJ0yRxyQIh4u8SRSlrOtm1dh0B7R8jtG+w==
dependencies:
ethjs-abi "0.1.8"
truffle-blockchain-utils "^0.0.3"
truffle-contract-schema "^0.0.5"
web3 "^0.20.1"
truffle-core@^5.0.13:
version "5.0.13"
resolved "https://registry.yarnpkg.com/truffle-core/-/truffle-core-5.0.13.tgz#57e54de775e1177aa0b2ed21381fa60eaf130c28"
integrity sha512-0dnH56+NcMNyL4OKtlA++j7wsgh+tKM5jaITAvG5md0Sn7D+Wl5M8Yu/MSzR7Xw2o6ERRfMrmTtOM6cO3BXEqw==
dependencies:
app-module-path "^2.2.0"
async "2.6.1"
@ -15802,26 +15816,26 @@ truffle-core@^5.0.12:
source-map-support "^0.5.3"
spawn-args "^0.1.0"
temp "^0.8.3"
truffle-artifactor "^4.0.10"
truffle-box "^1.0.20"
truffle-compile "^4.0.10"
truffle-config "^1.1.7"
truffle-contract "^4.0.11"
truffle-artifactor "^4.0.11"
truffle-box "^1.0.21"
truffle-compile "^4.0.11"
truffle-config "^1.1.8"
truffle-contract "^4.0.12"
truffle-contract-sources "^0.1.3"
truffle-debug-utils "^1.0.15"
truffle-debugger "^5.0.6"
truffle-deployer "^3.0.12"
truffle-debugger "^5.0.7"
truffle-deployer "^3.0.13"
truffle-error "^0.0.4"
truffle-expect "^0.0.7"
truffle-init "^1.0.7"
truffle-interface-adapter "^0.1.2"
truffle-migrate "^3.0.12"
truffle-migrate "^3.0.13"
truffle-provider "^0.1.6"
truffle-provisioner "^0.1.4"
truffle-require "^2.0.7"
truffle-resolver "^5.0.10"
truffle-require "^2.0.8"
truffle-resolver "^5.0.11"
truffle-solidity-utils "^1.2.2"
truffle-workflow-compile "^2.0.10"
truffle-workflow-compile "^2.0.11"
universal-analytics "^0.4.17"
web3 "1.0.0-beta.37"
xregexp "^4.2.4"
@ -15836,15 +15850,14 @@ truffle-debug-utils@^1.0.15:
debug "^4.1.0"
node-dir "0.1.17"
truffle-debugger@^5.0.6:
version "5.0.6"
resolved "https://registry.yarnpkg.com/truffle-debugger/-/truffle-debugger-5.0.6.tgz#dfc61e61f97d6c2b52e3b273d269a332388aaeb0"
integrity sha512-0qRIHcZmLymj23aTl3pk6z05MsTdOj3gn2qV4AfEOEoCpJaLAc0PH3iE/vBYxLBZ2LbBf+Zlvz/wvBUcJkwKTA==
truffle-debugger@^5.0.7:
version "5.0.7"
resolved "https://registry.yarnpkg.com/truffle-debugger/-/truffle-debugger-5.0.7.tgz#45e91a482a62801a9f13181150dea59f77a61493"
integrity sha512-inSvAYz2xZVJXbCRKUJvVtvvNvzGxqbmCWq9dIPJmN323ha+Oh76Kc8+Pig89QHKAOzudJdlV8u7dtGtoexauA==
dependencies:
bn.js "^4.11.8"
debug "^4.1.0"
json-pointer "^0.6.0"
lodash.escaperegexp "^4.1.2"
lodash.sum "^4.0.2"
redux "^3.7.2"
redux-cli-logger "^2.0.1"
@ -15852,26 +15865,28 @@ truffle-debugger@^5.0.6:
remote-redux-devtools "^0.5.12"
reselect-tree "^1.3.0"
truffle-code-utils "^1.2.1"
truffle-decode-utils "^1.0.8"
truffle-decoder "^2.0.5"
truffle-decode-utils "^1.0.9"
truffle-decoder "^3.0.0"
truffle-expect "^0.0.7"
truffle-solidity-utils "^1.2.2"
web3 "1.0.0-beta.37"
web3-eth-abi "1.0.0-beta.37"
truffle-decode-utils@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/truffle-decode-utils/-/truffle-decode-utils-1.0.8.tgz#2cefc99a9671463cb46f8a3ded7782ec56dc9a5f"
integrity sha512-qMz0S0eFPoAnfh3mrYGsGm6a2jKPEtUHYhHIBV92tketSE2uA83HTYZ87mQa0W3/9SmwTRAdQnR8tFLQ2RlHBA==
truffle-decode-utils@^1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/truffle-decode-utils/-/truffle-decode-utils-1.0.9.tgz#ee07165bb0ad475b57cde20179d0551efc1fdffe"
integrity sha512-9kNNZvsuUE16WHytj/bG/vp2GFcqANTl8sr8/+dvQ6dZG2RnmrdWmEmSNR0/roKi4dxsdhExON1gTj1emN3yeQ==
dependencies:
bn.js "^4.11.8"
lodash.clonedeep "^4.5.0"
lodash.escaperegexp "^4.1.2"
web3 "1.0.0-beta.37"
web3-eth-abi "1.0.0-beta.52"
truffle-decoder@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/truffle-decoder/-/truffle-decoder-2.0.5.tgz#096b9b371343a3a2dda37d1585e70c1a2beddf72"
integrity sha512-WUr1Mkb895IUpG+Z5wLKLCnt+5/pKQWEsC7dIvFcVepxGExP+5wjPOD4fKOwSb8V01whIJfkcGU3MRJuEUxSIw==
truffle-decoder@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/truffle-decoder/-/truffle-decoder-3.0.0.tgz#03d264ad325cbb8ad3956002e1f963c2aa193cf6"
integrity sha512-ax27U6hk3Mh5fmrtw3PByi+z/c1mQc0igxrejGx6xTQCrU1tIuW/TMiLGXaGsZg9B2L5DfR1MP9QvDlIbn+WdQ==
dependencies:
abi-decoder "^1.2.0"
async-eventemitter "^0.2.4"
@ -15880,17 +15895,16 @@ truffle-decoder@^2.0.5:
lodash.clonedeep "^4.5.0"
lodash.isequal "^4.5.0"
lodash.merge "^4.6.1"
lodash.range "^3.2.0"
truffle-decode-utils "^1.0.8"
truffle-decode-utils "^1.0.9"
web3 "1.0.0-beta.37"
truffle-deployer@^3.0.12:
version "3.0.12"
resolved "https://registry.yarnpkg.com/truffle-deployer/-/truffle-deployer-3.0.12.tgz#fb0342d4ef5a706e30012f8763f62de95b29330f"
integrity sha512-bttgzZ0oQvBAZ9Y9SsE9r89nbWPBo3Co7jDTbGxjkAkNwKZcs/dImTBBFAhIbhg2mORkz06tuVN76Kfw4598Ng==
truffle-deployer@^3.0.13:
version "3.0.13"
resolved "https://registry.yarnpkg.com/truffle-deployer/-/truffle-deployer-3.0.13.tgz#9954be3336b3796beded3a04559b4246ba98eb55"
integrity sha512-7ZrQaSdJO8DLsgAnWyGSC4XWYcpvPhDL82stxKts2gfOHuYwKhDwSxlxqVgbidjNB0Ed+Fko9cmRvxXFvnJ7Rw==
dependencies:
emittery "^0.4.0"
truffle-contract "^4.0.11"
truffle-contract "^4.0.12"
truffle-expect "^0.0.7"
truffle-error@^0.0.3:
@ -15939,19 +15953,19 @@ truffle-interface-adapter@^0.1.2:
bn.js "^4.11.8"
web3 "1.0.0-beta.37"
truffle-migrate@^3.0.12:
version "3.0.12"
resolved "https://registry.yarnpkg.com/truffle-migrate/-/truffle-migrate-3.0.12.tgz#8eadcdcab1e428422ed39028f2471b1efe1f44c6"
integrity sha512-ylC5A7xiA/EFWp+bbAjPPw5pi7qN24sBiy4Yd6qOzXRtP0ZgdBAtNRKrrm2c1YZhyuLU693hMS+h8jP3aij5mQ==
truffle-migrate@^3.0.13:
version "3.0.13"
resolved "https://registry.yarnpkg.com/truffle-migrate/-/truffle-migrate-3.0.13.tgz#d2898be4a16fd0e219b0fb4d8a2929016e592b7a"
integrity sha512-C0eQSPbNmmpGDh54CI17gFYPY3CHphXI6exfDBcQl7ZFcWSpOlWMztJ4aexlIl7jlR1yPIbxVwJroSb6wNmr9Q==
dependencies:
async "2.6.1"
emittery "^0.4.0"
node-dir "0.1.17"
truffle-deployer "^3.0.12"
truffle-deployer "^3.0.13"
truffle-expect "^0.0.7"
truffle-interface-adapter "^0.1.2"
truffle-reporters "^1.0.8"
truffle-require "^2.0.7"
truffle-reporters "^1.0.9"
truffle-require "^2.0.8"
web3 "1.0.0-beta.37"
truffle-provider@^0.1.6:
@ -15968,74 +15982,74 @@ truffle-provisioner@^0.1.4:
resolved "https://registry.yarnpkg.com/truffle-provisioner/-/truffle-provisioner-0.1.4.tgz#a470f7e603d069b481481dba92f5c9d2f1a8526a"
integrity sha512-d4GhAsS4bEtYIfuedaFl9k22o7UJOsmgMZM8M3fQYI0uAGt9ApEGEL0Yvdy7/uWw/0T1796ZVe+EuzlbcjaiUQ==
truffle-reporters@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/truffle-reporters/-/truffle-reporters-1.0.8.tgz#60ae1c14df8c6143f5b80e8e7d770dad24f2a140"
integrity sha512-NhHjUhSKRctZKFsS4ndrAhY3CKWa7oGCvqXr5P/bu4WKT3jbayTIv9SmfS2vwVwZ6OlczmWwgoYGQuw9LX7Zfw==
truffle-reporters@^1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/truffle-reporters/-/truffle-reporters-1.0.9.tgz#efbdff21084fb9abf5a80cb615a37b5d0fbe9a07"
integrity sha512-M4F59OaNSOrLQt0bXDMyw93jwszCnL7+sjlTKkmmOf0dW8TJJQ4yps/L8i4X4GJOdtSGu4FveQdSY2ElEZVZtA==
dependencies:
node-emoji "^1.8.1"
ora "^3.0.0"
web3-utils "1.0.0-beta.37"
truffle-require@^2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/truffle-require/-/truffle-require-2.0.7.tgz#2c1c876b81d639f21cafeac1616bcae5852814ee"
integrity sha512-QJWSzan15H1qTwpodxWIR5lD7wZTIdwv5tioyhOjNJZOZfRWx/+C9mcB/afNn+Gb2ZT9UPHnZ8/vmuGQPnGFVg==
truffle-require@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/truffle-require/-/truffle-require-2.0.8.tgz#7be74fb7e36c0002f9e088aea34dec40d5ded732"
integrity sha512-qVg0i3Qq+IBsUmHO32457cJ4Alkj8pEPSXPsJeM45wd0mbhUaKF+3k7xpCg8FSg7Td2HDmIRPQljQpVW09Z7nA==
dependencies:
original-require "1.0.1"
truffle-config "^1.1.7"
truffle-config "^1.1.8"
truffle-expect "^0.0.7"
truffle-interface-adapter "^0.1.2"
web3 "1.0.0-beta.37"
truffle-resolver@^5.0.10:
version "5.0.10"
resolved "https://registry.yarnpkg.com/truffle-resolver/-/truffle-resolver-5.0.10.tgz#4009263b16d9c954b671d464987b7db911b32a78"
integrity sha512-jjXvEJcYusOfRKXSec2Gyg0ptM75BzKE0Czi162iaod9UgyhIyp32wRrajqPYP3mXhu0OGIUNf95po/fIqsrtQ==
truffle-resolver@^5.0.11:
version "5.0.11"
resolved "https://registry.yarnpkg.com/truffle-resolver/-/truffle-resolver-5.0.11.tgz#78efdb618177909a45c76594d9f94238167f2ad0"
integrity sha512-yB89eDOyYwR6SQ1d2nVm0Dt+NWW5tTAso91+D4O7PoUdbZHD9sxTbLC6nv6bsTqN5xGGvpxWOx0h0b04RpAc2Q==
dependencies:
async "2.6.1"
truffle-contract "^4.0.11"
truffle-contract "^4.0.12"
truffle-expect "^0.0.7"
truffle-provisioner "^0.1.4"
truffle-solidity-loader@0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/truffle-solidity-loader/-/truffle-solidity-loader-0.1.12.tgz#50aee0f20eaca18788a5de69207a523b1cba372d"
integrity sha512-NQhyVOS5xfHUrsITECTcgmGBquqAsX6TxuHk+oePtVK5eTcS4v9j+f6pd5Hno4Hd9RmdWr/NbvE8X6rxwhKo1w==
truffle-solidity-loader@0.1.13:
version "0.1.13"
resolved "https://registry.yarnpkg.com/truffle-solidity-loader/-/truffle-solidity-loader-0.1.13.tgz#a3839f4fe815b9335a8b139895e254c9a6c363b2"
integrity sha512-oJ0GYGf9BWkgSGonaCAvwomlAno7sxvJ53Y934I50hxsisq60qSjgOTwD/245TQL8RlD2fWE2PUZ5d0a6pbXcg==
dependencies:
chalk "^1.1.3"
find-up "^1.1.2"
loader-utils "^1.1.0"
schema-utils "^1.0.0"
truffle-config "^1.1.7"
truffle-core "^5.0.12"
truffle-config "^1.1.8"
truffle-core "^5.0.13"
truffle-solidity-utils@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/truffle-solidity-utils/-/truffle-solidity-utils-1.2.2.tgz#72100f12317a94cb8e784bc84d8f8832292e5fc0"
integrity sha512-27Eos1o33x+tdRogeR8WwWuhRXatHwbp9AHANGSCm46ZhRzSWcObW8Ctm2kKdAP0jZehDLT2e7l5oZ4NJofLMg==
truffle-workflow-compile@^2.0.10:
version "2.0.10"
resolved "https://registry.yarnpkg.com/truffle-workflow-compile/-/truffle-workflow-compile-2.0.10.tgz#15d8aff5b2ea12ffde68cc9a8cc3aa843a8e0bb3"
integrity sha512-c/xpQ55mI5YPaepu6APYEW8fnnkHNb1S2KuLVcVGI757LBvjVfXCzLYOPaw8itXhoTWg0PWCdBoMvvvDG4N/Qw==
truffle-workflow-compile@^2.0.11:
version "2.0.11"
resolved "https://registry.yarnpkg.com/truffle-workflow-compile/-/truffle-workflow-compile-2.0.11.tgz#b07c928d19b86f1d6858c64f5238fda9288079db"
integrity sha512-rRuGtzQP29qknVU0JNyTWv9U2BoTA+Zd7AKyM2IS00dJweLnlfPY/Ja2G43GBSMR0PF/4iNI7U88iQL/j4tkNA==
dependencies:
async "2.6.1"
debug "^4.1.0"
lodash "4.17.11"
mkdirp "^0.5.1"
truffle-artifactor "^4.0.10"
truffle-compile "^4.0.10"
truffle-compile-vyper "^1.0.10"
truffle-config "^1.1.7"
truffle-artifactor "^4.0.11"
truffle-compile "^4.0.11"
truffle-compile-vyper "^1.0.11"
truffle-config "^1.1.8"
truffle-expect "^0.0.7"
truffle-external-compile "^1.0.7"
truffle-resolver "^5.0.10"
truffle-resolver "^5.0.11"
truffle@5.0.12:
version "5.0.12"
resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.0.12.tgz#05ab7d2561a3ee4fd5e026dcc4b91b8f3c6e3795"
integrity sha512-dqnDmtTGNcnL29PHQwPE/CVmFFeGLuTFeb4TS3VY/vbASefu118IKXcadOWzkCPPwktv/njwylHSPhwoS00F2A==
truffle@5.0.13:
version "5.0.13"
resolved "https://registry.yarnpkg.com/truffle/-/truffle-5.0.13.tgz#bd0c6c142889140ab9db57d9a8738d5f5afaed68"
integrity sha512-TF8X95780TqfxkWtITG8n3dyBI23ifLmOpsrQp6TugmB150nLZrZ1ncW63wgF9jwj/B0UXGE04bE72SYhbgcvg==
dependencies:
app-module-path "^2.2.0"
mocha "^4.1.0"
@ -17426,10 +17440,10 @@ webpack-bundle-analyzer@3.3.2:
opener "^1.5.1"
ws "^6.0.0"
webpack-cli@^3.2.3:
version "3.3.0"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.0.tgz#55c8a74cae1e88117f9dda3a801c7272e93ca318"
integrity sha512-t1M7G4z5FhHKJ92WRKwZ1rtvi7rHc0NZoZRbSkol0YKl4HvcC8+DsmGDmK7MmZxHSAetHagiOsjOB6MmzC2TUw==
webpack-cli@3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.1.tgz#98b0499c7138ba9ece8898bd99c4f007db59909d"
integrity sha512-c2inFU7SM0IttEgF7fK6AaUsbBnORRzminvbyRKS+NlbQHVZdCtzKBlavRL5359bFsywXGRAItA5di/IruC8mg==
dependencies:
chalk "^2.4.1"
cross-spawn "^6.0.5"