WA-232 tokens route
This commit is contained in:
parent
d7193dcc9a
commit
0b5d14c8f2
|
@ -7,11 +7,11 @@ import GnoSafe from './Safe'
|
|||
type Props = SelectorProps
|
||||
|
||||
const Layout = ({
|
||||
safe, balances, provider, userAddress,
|
||||
safe, tokens, provider, userAddress,
|
||||
}: Props) => (
|
||||
<React.Fragment>
|
||||
{ safe
|
||||
? <GnoSafe safe={safe} balances={balances} userAddress={userAddress} />
|
||||
? <GnoSafe safe={safe} tokens={tokens} userAddress={userAddress} />
|
||||
: <NoSafe provider={provider} text="Not found safe" />
|
||||
}
|
||||
</React.Fragment>
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as React from 'react'
|
|||
import { Map } from 'immutable'
|
||||
import styles from '~/components/layout/PageFrame/index.scss'
|
||||
import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
|
||||
import { makeBalance } from '~/routes/safe/store/model/balance'
|
||||
import { makeToken } from '~/routes/tokens/store/model/token'
|
||||
import Component from './Layout'
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@ const FrameDecorator = story => (
|
|||
</div>
|
||||
)
|
||||
|
||||
const ethBalance = makeBalance({
|
||||
const ethBalance = makeToken({
|
||||
address: '0',
|
||||
name: 'Ether',
|
||||
symbol: 'ETH',
|
||||
|
@ -30,7 +30,7 @@ storiesOf('Routes /safe:address', module)
|
|||
userAddress="foo"
|
||||
safe={undefined}
|
||||
provider="METAMASK"
|
||||
balances={Map()}
|
||||
tokens={Map()}
|
||||
fetchBalance={() => {}}
|
||||
/>
|
||||
))
|
||||
|
@ -39,7 +39,7 @@ storiesOf('Routes /safe:address', module)
|
|||
userAddress="foo"
|
||||
safe={undefined}
|
||||
provider=""
|
||||
balances={Map()}
|
||||
tokens={Map()}
|
||||
fetchBalance={() => {}}
|
||||
/>
|
||||
))
|
||||
|
@ -51,7 +51,7 @@ storiesOf('Routes /safe:address', module)
|
|||
userAddress="foo"
|
||||
safe={safe}
|
||||
provider="METAMASK"
|
||||
balances={Map().set('ETH', ethBalance)}
|
||||
tokens={Map().set('ETH', ethBalance)}
|
||||
fetchBalance={() => {}}
|
||||
/>
|
||||
)
|
||||
|
@ -64,7 +64,7 @@ storiesOf('Routes /safe:address', module)
|
|||
userAddress="foo"
|
||||
safe={safe}
|
||||
provider="METAMASK"
|
||||
balances={Map().set('ETH', ethBalance)}
|
||||
tokens={Map().set('ETH', ethBalance)}
|
||||
fetchBalance={() => {}}
|
||||
/>
|
||||
)
|
||||
|
|
|
@ -17,11 +17,11 @@ import { Map } from 'immutable'
|
|||
import Button from '~/components/layout/Button'
|
||||
import openHoc, { type Open } from '~/components/hoc/OpenHoc'
|
||||
import { type WithStyles } from '~/theme/mui'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
type Props = Open & WithStyles & {
|
||||
balances: Map<string, Balance>,
|
||||
onMoveFunds: (balance: Balance) => void,
|
||||
tokens: Map<string, Token>,
|
||||
onMoveFunds: (token: Token) => void,
|
||||
}
|
||||
|
||||
const styles = {
|
||||
|
@ -33,9 +33,9 @@ const styles = {
|
|||
export const MOVE_FUNDS_BUTTON_TEXT = 'Move'
|
||||
|
||||
const BalanceComponent = openHoc(({
|
||||
open, toggle, balances, classes, onMoveFunds,
|
||||
open, toggle, tokens, classes, onMoveFunds,
|
||||
}: Props) => {
|
||||
const hasBalances = balances.count() > 0
|
||||
const hasBalances = tokens.count() > 0
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
@ -53,18 +53,18 @@ const BalanceComponent = openHoc(({
|
|||
</ListItem>
|
||||
<Collapse in={open} timeout="auto">
|
||||
<List component="div" disablePadding>
|
||||
{balances.valueSeq().map((balance: Balance) => {
|
||||
const symbol = balance.get('symbol')
|
||||
const name = balance.get('name')
|
||||
const disabled = Number(balance.get('funds')) === 0
|
||||
const onMoveFundsClick = () => onMoveFunds(balance)
|
||||
{tokens.valueSeq().map((token: Token) => {
|
||||
const symbol = token.get('symbol')
|
||||
const name = token.get('name')
|
||||
const disabled = Number(token.get('funds')) === 0
|
||||
const onMoveFundsClick = () => onMoveFunds(token)
|
||||
|
||||
return (
|
||||
<ListItem key={symbol} className={classNames(classes.nested, symbol)}>
|
||||
<ListItemIcon>
|
||||
<Img src={balance.get('logoUrl')} height={30} alt={name} />
|
||||
<Img src={token.get('logoUrl')} height={30} alt={name} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={name} secondary={`${balance.get('funds')} ${symbol}`} />
|
||||
<ListItemText primary={name} secondary={`${token.get('funds')} ${symbol}`} />
|
||||
<Button variant="raised" color="primary" onClick={onMoveFundsClick} disabled={disabled}>
|
||||
{MOVE_FUNDS_BUTTON_TEXT}
|
||||
</Button>
|
||||
|
|
|
@ -9,7 +9,7 @@ import Img from '~/components/layout/Img'
|
|||
import Paragraph from '~/components/layout/Paragraph'
|
||||
import Row from '~/components/layout/Row'
|
||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
import Withdraw from '~/routes/safe/component/Withdraw'
|
||||
import Transactions from '~/routes/safe/component/Transactions'
|
||||
|
@ -30,7 +30,7 @@ const safeIcon = require('./assets/gnosis_safe.svg')
|
|||
|
||||
type SafeProps = {
|
||||
safe: Safe,
|
||||
balances: Map<string, Balance>,
|
||||
tokens: Map<string, Token>,
|
||||
userAddress: string,
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ const listStyle = {
|
|||
width: '100%',
|
||||
}
|
||||
|
||||
const getEthBalanceFrom = (balances: Map<string, Balance>) => {
|
||||
const getEthBalanceFrom = (balances: Map<string, Token>) => {
|
||||
const ethBalance = balances.get('ETH')
|
||||
if (!ethBalance) {
|
||||
return 0
|
||||
|
@ -93,13 +93,13 @@ class GnoSafe extends React.PureComponent<SafeProps, State> {
|
|||
this.setState({ component: <RemoveOwner safeAddress={safe.get('address')} threshold={safe.get('threshold')} safe={safe} name={name} userToRemove={address} /> })
|
||||
}
|
||||
|
||||
onMoveTokens = (ercToken: Balance) => {
|
||||
onMoveTokens = (ercToken: Token) => {
|
||||
const { safe } = this.props
|
||||
|
||||
this.setState({
|
||||
component: <SendToken
|
||||
safe={safe}
|
||||
balance={ercToken}
|
||||
token={ercToken}
|
||||
key={ercToken.get('symbol')}
|
||||
onReset={this.onListTransactions}
|
||||
/>,
|
||||
|
@ -107,15 +107,15 @@ class GnoSafe extends React.PureComponent<SafeProps, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { safe, balances, userAddress } = this.props
|
||||
const { safe, tokens, userAddress } = this.props
|
||||
const { component } = this.state
|
||||
const ethBalance = getEthBalanceFrom(balances)
|
||||
const ethBalance = getEthBalanceFrom(tokens)
|
||||
|
||||
return (
|
||||
<Row grow>
|
||||
<Col sm={12} top="xs" md={5} margin="xl" overflow>
|
||||
<List style={listStyle}>
|
||||
<BalanceInfo balances={balances} onMoveFunds={this.onMoveTokens} />
|
||||
<BalanceInfo tokens={tokens} onMoveFunds={this.onMoveTokens} />
|
||||
<Owners
|
||||
owners={safe.owners}
|
||||
onAddOwner={this.onAddOwner}
|
||||
|
|
|
@ -5,9 +5,9 @@ import { connect } from 'react-redux'
|
|||
import Stepper from '~/components/Stepper'
|
||||
import { sleep } from '~/utils/timer'
|
||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
import { getStandardTokenContract } from '~/routes/tokens/store/actions/fetchTokens'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
import { createTransaction } from '~/wallets/createTransactions'
|
||||
import { getStandardTokenContract } from '~/routes/safe/store/actions/fetchBalances'
|
||||
import { EMPTY_DATA } from '~/wallets/ethTransactions'
|
||||
import { toNative } from '~/wallets/tokens'
|
||||
import actions, { type Actions } from './actions'
|
||||
|
@ -21,7 +21,7 @@ const getSteps = () => [
|
|||
|
||||
type Props = SelectorProps & Actions & {
|
||||
safe: Safe,
|
||||
balance: Balance,
|
||||
token: Token,
|
||||
onReset: () => void,
|
||||
}
|
||||
|
||||
|
@ -40,16 +40,16 @@ const getTransferData = async (tokenAddress: string, to: string, amount: BigNumb
|
|||
return myToken.contract.transfer.getData(to, amount)
|
||||
}
|
||||
|
||||
const processTokenTransfer = async (safe: Safe, balance: Balance, to: string, amount: number, userAddress: string) => {
|
||||
const symbol = balance.get('symbol')
|
||||
const processTokenTransfer = async (safe: Safe, token: Token, to: string, amount: number, userAddress: string) => {
|
||||
const symbol = token.get('symbol')
|
||||
const nonce = Date.now()
|
||||
const name = `Send ${amount} ${balance.get('symbol')} to ${to}`
|
||||
const name = `Send ${amount} ${token.get('symbol')} to ${to}`
|
||||
const value = isEther(symbol) ? amount : 0
|
||||
const tokenAddress = balance.get('address')
|
||||
const tokenAddress = token.get('address')
|
||||
const destination = isEther(symbol) ? to : tokenAddress
|
||||
const data = isEther(symbol)
|
||||
? EMPTY_DATA
|
||||
: await getTransferData(tokenAddress, to, await toNative(amount, balance.get('decimals')))
|
||||
: await getTransferData(tokenAddress, to, await toNative(amount, token.get('decimals')))
|
||||
|
||||
return createTransaction(safe, name, destination, value, nonce, userAddress, data)
|
||||
}
|
||||
|
@ -61,12 +61,12 @@ class SendToken extends React.Component<Props, State> {
|
|||
|
||||
onTransaction = async (values: Object) => {
|
||||
try {
|
||||
const { safe, balance, userAddress } = this.props
|
||||
const { safe, token, userAddress } = this.props
|
||||
|
||||
const amount = values[TKN_VALUE_PARAM]
|
||||
const destination = values[TKN_DESTINATION_PARAM]
|
||||
|
||||
await processTokenTransfer(safe, balance, destination, amount, userAddress)
|
||||
await processTokenTransfer(safe, token, destination, amount, userAddress)
|
||||
await sleep(1500)
|
||||
this.props.fetchTransactions()
|
||||
this.setState({ done: true })
|
||||
|
@ -84,10 +84,10 @@ class SendToken extends React.Component<Props, State> {
|
|||
|
||||
render() {
|
||||
const { done } = this.state
|
||||
const { balance } = this.props
|
||||
const { token } = this.props
|
||||
const steps = getSteps()
|
||||
const finishedButton = <Stepper.FinishButton title={SEE_TXS_BUTTON_TEXT} />
|
||||
const symbol = balance.get('symbol')
|
||||
const symbol = token.get('symbol')
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
@ -98,7 +98,7 @@ class SendToken extends React.Component<Props, State> {
|
|||
steps={steps}
|
||||
onReset={this.onReset}
|
||||
>
|
||||
<Stepper.Page funds={balance.get('funds')} symbol={symbol}>
|
||||
<Stepper.Page funds={token.get('funds')} symbol={symbol}>
|
||||
{ SendTokenForm }
|
||||
</Stepper.Page>
|
||||
<Stepper.Page symbol={symbol}>
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
// @flow
|
||||
import fetchSafe from '~/routes/safe/store/actions/fetchSafe'
|
||||
import { fetchBalances } from '~/routes/safe/store/actions/fetchBalances'
|
||||
import { fetchTokens } from '~/routes/tokens/store/actions/fetchTokens'
|
||||
|
||||
export type Actions = {
|
||||
fetchSafe: typeof fetchSafe,
|
||||
fetchBalances: typeof fetchBalances,
|
||||
fetchTokens: typeof fetchTokens,
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchSafe,
|
||||
fetchBalances,
|
||||
fetchTokens,
|
||||
}
|
||||
|
|
|
@ -16,12 +16,12 @@ const TIMEOUT = process.env.NODE_ENV === 'test' ? 1500 : 15000
|
|||
class SafeView extends React.PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
this.intervalId = setInterval(() => {
|
||||
const { safe, fetchBalances, fetchSafe } = this.props
|
||||
const { safe, fetchTokens, fetchSafe } = this.props
|
||||
if (!safe) {
|
||||
return
|
||||
}
|
||||
const safeAddress = safe.get('address')
|
||||
fetchBalances(safeAddress)
|
||||
fetchTokens(safeAddress)
|
||||
fetchSafe(safe)
|
||||
}, TIMEOUT)
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class SafeView extends React.PureComponent<Props> {
|
|||
|
||||
if (this.props.safe) {
|
||||
const safeAddress = this.props.safe.get('address')
|
||||
this.props.fetchBalances(safeAddress)
|
||||
this.props.fetchTokens(safeAddress)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,13 +45,13 @@ class SafeView extends React.PureComponent<Props> {
|
|||
|
||||
render() {
|
||||
const {
|
||||
safe, provider, balances, granted, userAddress,
|
||||
safe, provider, tokens, granted, userAddress,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Page>
|
||||
{ granted
|
||||
? <Layout balances={balances} provider={provider} safe={safe} userAddress={userAddress} />
|
||||
? <Layout tokens={tokens} provider={provider} safe={safe} userAddress={userAddress} />
|
||||
: <NoRights />
|
||||
}
|
||||
</Page>
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
// @flow
|
||||
import { List, Map } from 'immutable'
|
||||
import { createSelector, createStructuredSelector, type Selector } from 'reselect'
|
||||
import { balanceSelector, safeSelector, type RouterProps, type SafeSelectorProps } from '~/routes/safe/store/selectors'
|
||||
import { safeSelector, type RouterProps, type SafeSelectorProps } from '~/routes/safe/store/selectors'
|
||||
import { providerNameSelector, userAccountSelector } from '~/wallets/store/selectors/index'
|
||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||
import { type Owner } from '~/routes/safe/store/model/owner'
|
||||
import { type GlobalState } from '~/store/index'
|
||||
import { sameAddress } from '~/wallets/ethAddresses'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
import { tokensSelector } from '~/routes/tokens/store/selectors'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
export type SelectorProps = {
|
||||
safe: SafeSelectorProps,
|
||||
provider: string,
|
||||
balances: Map<string, Balance>,
|
||||
tokens: Map<string, Token>,
|
||||
userAddress: string,
|
||||
}
|
||||
|
||||
|
@ -40,7 +41,7 @@ export const grantedSelector: Selector<GlobalState, RouterProps, boolean> = crea
|
|||
export default createStructuredSelector({
|
||||
safe: safeSelector,
|
||||
provider: providerNameSelector,
|
||||
balances: balanceSelector,
|
||||
tokens: tokensSelector,
|
||||
granted: grantedSelector,
|
||||
userAddress: userAccountSelector,
|
||||
})
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
// @flow
|
||||
import { Map } from 'immutable'
|
||||
import { createAction } from 'redux-actions'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
|
||||
export const ADD_BALANCES = 'ADD_BALANCES'
|
||||
|
||||
type BalanceProps = {
|
||||
safeAddress: string,
|
||||
balances: Map<string, Balance>,
|
||||
}
|
||||
|
||||
const addBalances = createAction(
|
||||
ADD_BALANCES,
|
||||
(safeAddress: string, balances: Map<string, Balance>): BalanceProps => ({
|
||||
safeAddress,
|
||||
balances,
|
||||
}),
|
||||
)
|
||||
|
||||
export default addBalances
|
|
@ -11,15 +11,23 @@ const buildSafesFrom = async (loadedSafes: Object): Promise<Map<string, Safe>> =
|
|||
const safes = Map()
|
||||
|
||||
const keys = Object.keys(loadedSafes)
|
||||
const safeRecords = await Promise.all(keys.map((address: string) => buildSafe(loadedSafes[address])))
|
||||
try {
|
||||
const safeRecords = await Promise.all(keys.map((address: string) => buildSafe(loadedSafes[address])))
|
||||
|
||||
return safes.withMutations(async (map) => {
|
||||
safeRecords.forEach((safe: Safe) => map.set(safe.get('address'), safe))
|
||||
})
|
||||
return safes.withMutations(async (map) => {
|
||||
safeRecords.forEach((safe: Safe) => map.set(safe.get('address'), safe))
|
||||
})
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.log("Error while fetching safes information")
|
||||
|
||||
return Map()
|
||||
}
|
||||
}
|
||||
|
||||
export default () => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||
const storedSafes = load(SAFES_KEY)
|
||||
|
||||
const safes = storedSafes ? await buildSafesFrom(storedSafes) : Map()
|
||||
|
||||
return dispatch(updateSafes(safes))
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
// @flow
|
||||
import { Map } from 'immutable'
|
||||
import { handleActions, type ActionType } from 'redux-actions'
|
||||
import addBalances, { ADD_BALANCES } from '~/routes/safe/store/actions/addBalances'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
|
||||
export const BALANCE_REDUCER_ID = 'balances'
|
||||
|
||||
export type State = Map<string, Map<string, Balance>>
|
||||
|
||||
export default handleActions({
|
||||
[ADD_BALANCES]: (state: State, action: ActionType<typeof addBalances>): State =>
|
||||
state.update(action.payload.safeAddress, (prevSafe: Map<string, Balance>) => {
|
||||
if (!prevSafe) {
|
||||
return action.payload.balances
|
||||
}
|
||||
|
||||
return prevSafe.equals(action.payload.balances) ? prevSafe : action.payload.balances
|
||||
}),
|
||||
}, Map())
|
|
@ -6,11 +6,9 @@ import { type GlobalState } from '~/store/index'
|
|||
import { SAFE_PARAM_ADDRESS } from '~/routes/routes'
|
||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||
import { safesMapSelector } from '~/routes/safeList/store/selectors'
|
||||
import { BALANCE_REDUCER_ID } from '~/routes/safe/store/reducer/balances'
|
||||
import { type State as TransactionsState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
||||
import { type Transaction } from '~/routes/safe/store/model/transaction'
|
||||
import { type Confirmation } from '~/routes/safe/store/model/confirmation'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
|
||||
export type RouterProps = {
|
||||
match: Match,
|
||||
|
@ -26,14 +24,12 @@ type TransactionProps = {
|
|||
|
||||
const safePropAddressSelector = (state: GlobalState, props: SafeProps) => props.safeAddress
|
||||
|
||||
const safeParamAddressSelector = (state: GlobalState, props: RouterProps) => props.match.params[SAFE_PARAM_ADDRESS] || ''
|
||||
|
||||
const balancesSelector = (state: GlobalState) => state[BALANCE_REDUCER_ID]
|
||||
|
||||
const transactionsSelector = (state: GlobalState): TransactionsState => state[TRANSACTIONS_REDUCER_ID]
|
||||
|
||||
const oneTransactionSelector = (state: GlobalState, props: TransactionProps) => props.transaction
|
||||
|
||||
export const safeParamAddressSelector = (state: GlobalState, props: RouterProps) => props.match.params[SAFE_PARAM_ADDRESS] || ''
|
||||
|
||||
export const safeTransactionsSelector: Selector<GlobalState, SafeProps, List<Transaction>> = createSelector(
|
||||
transactionsSelector,
|
||||
safePropAddressSelector,
|
||||
|
@ -82,18 +78,6 @@ export const safeSelector: Selector<GlobalState, RouterProps, SafeSelectorProps>
|
|||
},
|
||||
)
|
||||
|
||||
export const balanceSelector: Selector<GlobalState, RouterProps, Map<string, Balance>> = createSelector(
|
||||
balancesSelector,
|
||||
safeParamAddressSelector,
|
||||
(balances: Map<string, Map<string, Balance>>, address: string) => {
|
||||
if (!address) {
|
||||
return Map()
|
||||
}
|
||||
|
||||
return balances.get(address) || Map()
|
||||
},
|
||||
)
|
||||
|
||||
export default createStructuredSelector({
|
||||
safe: safeSelector,
|
||||
})
|
||||
|
|
|
@ -29,7 +29,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
safes: Map(),
|
||||
providers: makeProvider(),
|
||||
balances: Map(),
|
||||
tokens: Map(),
|
||||
transactions: Map(),
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
safes: Map(),
|
||||
providers: makeProvider(),
|
||||
balances: Map(),
|
||||
tokens: Map(),
|
||||
transactions: Map(),
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
safes: Map(),
|
||||
providers: makeProvider(),
|
||||
balances: Map(),
|
||||
tokens: Map(),
|
||||
transactions: Map(),
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
providers: makeProvider(provider),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
providers: makeProvider(provider),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
providers: makeProvider(provider),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ const safeSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: Map(),
|
||||
providers: undefined,
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
const match: Match = buildMathPropsFrom('fooAddress')
|
||||
|
@ -38,7 +38,7 @@ const safeSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
providers: undefined,
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: Map(),
|
||||
providers: makeProvider(),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: Map(),
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: Map(),
|
||||
providers: makeProvider(),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: Map({ fooAddress: List([transaction]) }),
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: Map(),
|
||||
providers: makeProvider(),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: Map({ fooAddress: List([transaction]) }),
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ const grantedSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: Map(),
|
||||
providers: makeProvider(),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: Map({ fooAddress: List([transaction]) }),
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ const safesListSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||
[SAFE_REDUCER_ID]: Map(),
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
const emptyList = List([])
|
||||
|
@ -42,7 +42,7 @@ const safesListSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ const safesListSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ const safesListSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ const safesListSelectorTests = () => {
|
|||
const reduxStore = {
|
||||
[SAFE_REDUCER_ID]: map,
|
||||
[PROVIDER_REDUCER_ID]: walletRecord,
|
||||
balances: undefined,
|
||||
tokens: undefined,
|
||||
transactions: undefined,
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// @flow
|
||||
import * as MuiList from '@material-ui/core/List'
|
||||
import * as React from 'react'
|
||||
import Block from '~/components/layout/Block'
|
||||
import Col from '~/components/layout/Col'
|
||||
import Bold from '~/components/layout/Bold'
|
||||
import Img from '~/components/layout/Img'
|
||||
import Paragraph from '~/components/layout/Paragraph'
|
||||
import Row from '~/components/layout/Row'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
import { type SelectorProps } from '~/routes/tokens/container/selector'
|
||||
import { type Actions } from '~/routes/tokens/container/actions'
|
||||
import TokenComponent from './Token'
|
||||
// import AddToken from '~/routes/tokens/component/AddToken'
|
||||
// import RemoveToken from '~/routes/tokens/component/RemoveToken'
|
||||
|
||||
const safeIcon = require('~/routes/safe/component/Safe/assets/gnosis_safe.svg')
|
||||
|
||||
type TokenProps = SelectorProps & Actions
|
||||
|
||||
type State = {
|
||||
component: React$Node,
|
||||
}
|
||||
|
||||
const listStyle = {
|
||||
width: '100%',
|
||||
}
|
||||
|
||||
class TokenLayout extends React.PureComponent<TokenProps, State> {
|
||||
state = {
|
||||
component: undefined,
|
||||
}
|
||||
/*
|
||||
onAddToken = () => {
|
||||
const { addresses } = this.props
|
||||
this.setState({ component: <AddToken/> })
|
||||
}
|
||||
|
||||
onRemoveToken = () => {
|
||||
this.setState({ component: <RemoveToken /> })
|
||||
}
|
||||
*/
|
||||
onEnableToken = (token: Token) => {
|
||||
const { enableToken, safe } = this.props
|
||||
const safeAddress = safe.get('address')
|
||||
|
||||
enableToken(safeAddress, token)
|
||||
}
|
||||
|
||||
onDisableToken = (token: Token) => {
|
||||
const { disableToken, safe } = this.props
|
||||
const safeAddress = safe.get('address')
|
||||
|
||||
disableToken(safeAddress, token)
|
||||
}
|
||||
|
||||
render() {
|
||||
const { safe, tokens } = this.props
|
||||
const { component } = this.state
|
||||
const name = safe ? safe.get('name') : ''
|
||||
|
||||
return (
|
||||
<Row grow>
|
||||
<Col sm={12} top="xs" md={5} margin="xl" overflow>
|
||||
<MuiList style={listStyle}>
|
||||
{tokens.map((token: Token) => (<TokenComponent
|
||||
token={token}
|
||||
onDisableToken={this.onDisableToken}
|
||||
onEnableToken={this.onEnableToken}
|
||||
/>))}
|
||||
</MuiList>
|
||||
</Col>
|
||||
<Col sm={12} center="xs" md={7} margin="xl" layout="column">
|
||||
<Block margin="xl">
|
||||
<Paragraph size="lg" noMargin align="right">
|
||||
<Bold>{name}</Bold>
|
||||
</Paragraph>
|
||||
</Block>
|
||||
<Row grow>
|
||||
<Col sm={12} center={component ? undefined : 'sm'} middle={component ? undefined : 'sm'} layout="column">
|
||||
{ component || <Img alt="Safe Icon" src={safeIcon} height={330} /> }
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default TokenLayout
|
|
@ -0,0 +1,107 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
import { withStyles } from '@material-ui/core/styles'
|
||||
import Block from '~/components/layout/Block'
|
||||
import Bold from '~/components/layout/Bold'
|
||||
import Checkbox from '@material-ui/core/Checkbox'
|
||||
import Card from '@material-ui/core/Card'
|
||||
import CardContent from '@material-ui/core/CardContent'
|
||||
import CardMedia from '@material-ui/core/CardMedia'
|
||||
import Typography from '@material-ui/core/Typography'
|
||||
// import Delete from '@material-ui/icons/Delete'
|
||||
// import IconButton from '@material-ui/core/IconButton'
|
||||
import { type WithStyles } from '~/theme/mui'
|
||||
|
||||
type Props = WithStyles & {
|
||||
token: Token,
|
||||
onRemoveToken: (balance: Token)=> void,
|
||||
onEnableToken: (token: Token) => void,
|
||||
onDisableToken: (token: Token) => void,
|
||||
}
|
||||
|
||||
type State = {
|
||||
checked: boolean,
|
||||
}
|
||||
|
||||
const styles = theme => ({
|
||||
card: {
|
||||
display: 'flex',
|
||||
},
|
||||
details: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
content: {
|
||||
flex: '1 0 auto',
|
||||
},
|
||||
cover: {
|
||||
width: 45,
|
||||
height: 45,
|
||||
},
|
||||
controls: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
paddingLeft: theme.spacing.unit,
|
||||
paddingBottom: theme.spacing.unit,
|
||||
},
|
||||
playIcon: {
|
||||
height: 38,
|
||||
width: 38,
|
||||
},
|
||||
})
|
||||
|
||||
class TokenComponent extends React.Component<Props, State> {
|
||||
state = {
|
||||
checked: true,
|
||||
}
|
||||
|
||||
// onRemoveClick = () => this.props.onRemoveToken(this.props.token)
|
||||
|
||||
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
||||
const { checked } = e.target
|
||||
const callback = checked ? this.props.onDisableToken : this.props.onDisableToken
|
||||
this.setState(() => ({ checked: e.target.checked }), () => callback(this.props.token))
|
||||
}
|
||||
|
||||
render() {
|
||||
const { classes, token } = this.props
|
||||
const name = token.get('name')
|
||||
const symbol = token.get('symbol')
|
||||
|
||||
return (
|
||||
<Card className={classes.card}>
|
||||
<Block className={classes.details}>
|
||||
<CardContent className={classes.content}>
|
||||
<Typography variant="headline">{name}</Typography>
|
||||
<Typography variant="subheading" color="textSecondary">
|
||||
{symbol}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
<Block className={classes.controls}>
|
||||
<Bold>
|
||||
{symbol}
|
||||
</Bold>
|
||||
<Checkbox
|
||||
checked={this.state.checked}
|
||||
onChange={this.handleChange}
|
||||
color="primary"
|
||||
/>
|
||||
{/*
|
||||
<IconButton aria-label="Delete" onClick={this.onRemoveClick}>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
*/}
|
||||
</Block>
|
||||
</Block>
|
||||
<CardMedia
|
||||
className={classes.cover}
|
||||
image={token.get('logoUrl')}
|
||||
title={name}
|
||||
/>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(styles, { withTheme: true })(TokenComponent)
|
|
@ -0,0 +1,13 @@
|
|||
// @flow
|
||||
import enableToken from '~/routes/tokens/store/actions/enableToken'
|
||||
import disableToken from '~/routes/tokens/store/actions/disableToken'
|
||||
|
||||
export type Actions = {
|
||||
enableToken: typeof enableToken,
|
||||
disableToken: typeof disableToken,
|
||||
}
|
||||
|
||||
export default {
|
||||
enableToken,
|
||||
disableToken,
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// @flow
|
||||
import * as React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import Page from '~/components/layout/Page'
|
||||
import Layout from '~/routes/tokens/component/Layout'
|
||||
import selector, { type SelectorProps } from './selector'
|
||||
import actions, { type Actions } from './actions'
|
||||
|
||||
type Props = Actions & SelectorProps
|
||||
|
||||
class TokensView extends React.PureComponent<Props> {
|
||||
render() {
|
||||
const {
|
||||
tokens, addresses, safe, disableToken, enableToken,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<Layout
|
||||
tokens={tokens}
|
||||
addresses={addresses}
|
||||
safe={safe}
|
||||
disableToken={disableToken}
|
||||
enableToken={enableToken}
|
||||
/>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(selector, actions)(TokensView)
|
|
@ -0,0 +1,19 @@
|
|||
// @flow
|
||||
import { List } from 'immutable'
|
||||
import { createStructuredSelector } from 'reselect'
|
||||
import { tokenListSelector, tokenAddressesSelector } from '~/routes/tokens/store/selectors'
|
||||
import { type Safe } from '~/routes/safe/store/model/safe'
|
||||
import { safeSelector } from '~/routes/safe/store/selectors'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
export type SelectorProps = {
|
||||
tokens: List<Token>,
|
||||
addresses: List<String>,
|
||||
safe: Safe,
|
||||
}
|
||||
|
||||
export default createStructuredSelector({
|
||||
safe: safeSelector,
|
||||
tokens: tokenListSelector,
|
||||
addresses: tokenAddressesSelector,
|
||||
})
|
|
@ -0,0 +1,21 @@
|
|||
// @flow
|
||||
import { Map } from 'immutable'
|
||||
import { createAction } from 'redux-actions'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
export const ADD_TOKENS = 'ADD_TOKENS'
|
||||
|
||||
type TokenProps = {
|
||||
safeAddress: string,
|
||||
tokens: Map<string, Token>,
|
||||
}
|
||||
|
||||
const addTokens = createAction(
|
||||
ADD_TOKENS,
|
||||
(safeAddress: string, tokens: Map<string, Token>): TokenProps => ({
|
||||
safeAddress,
|
||||
tokens,
|
||||
}),
|
||||
)
|
||||
|
||||
export default addTokens
|
|
@ -0,0 +1,15 @@
|
|||
// @flow
|
||||
import { createAction } from 'redux-actions'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
export const DISABLE_TOKEN = 'DISABLE_TOKEN'
|
||||
|
||||
const disableToken = createAction(
|
||||
DISABLE_TOKEN,
|
||||
(safeAddress: string, token: Token) => ({
|
||||
safeAddress,
|
||||
symbol: token.get('symbol'),
|
||||
}),
|
||||
)
|
||||
|
||||
export default disableToken
|
|
@ -0,0 +1,15 @@
|
|||
// @flow
|
||||
import { createAction } from 'redux-actions'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
export const ENABLE_TOKEN = 'ENABLE_TOKEN'
|
||||
|
||||
const enableToken = createAction(
|
||||
ENABLE_TOKEN,
|
||||
(safeAddress: string, token: Token) => ({
|
||||
safeAddress,
|
||||
symbol: token.get('symbol'),
|
||||
}),
|
||||
)
|
||||
|
||||
export default enableToken
|
|
@ -5,10 +5,10 @@ import type { Dispatch as ReduxDispatch } from 'redux'
|
|||
import StandardToken from '@gnosis.pm/util-contracts/build/contracts/StandardToken.json'
|
||||
import { getBalanceInEtherOf, getWeb3 } from '~/wallets/getWeb3'
|
||||
import { type GlobalState } from '~/store/index'
|
||||
import { makeBalance, type Balance, type BalanceProps } from '~/routes/safe/store/model/balance'
|
||||
import { makeToken, type Token, type TokenProps } from '~/routes/tokens/store/model/token'
|
||||
import logo from '~/assets/icons/icon_etherTokens.svg'
|
||||
import { ensureOnce } from '~/utils/singleton'
|
||||
import addBalances from './addBalances'
|
||||
import addTokens from './addTokens'
|
||||
|
||||
|
||||
const createStandardTokenContract = async () => {
|
||||
|
@ -29,9 +29,9 @@ export const calculateBalanceOf = async (tokenAddress: string, address: string,
|
|||
.catch(() => '0')
|
||||
}
|
||||
|
||||
export const fetchBalances = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||
export const fetchTokens = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
|
||||
const balance = await getBalanceInEtherOf(safeAddress)
|
||||
const ethBalance = makeBalance({
|
||||
const ethBalance = makeToken({
|
||||
address: '0',
|
||||
name: 'Ether',
|
||||
symbol: 'ETH',
|
||||
|
@ -57,17 +57,17 @@ export const fetchBalances = (safeAddress: string) => async (dispatch: ReduxDisp
|
|||
const json = await response.json()
|
||||
|
||||
try {
|
||||
const balancesRecords = await Promise.all(json.map(async (item: BalanceProps) => {
|
||||
const balancesRecords = await Promise.all(json.map(async (item: TokenProps) => {
|
||||
const funds = await calculateBalanceOf(item.address, safeAddress, item.decimals)
|
||||
return makeBalance({ ...item, funds })
|
||||
return makeToken({ ...item, funds })
|
||||
}))
|
||||
|
||||
const balances: Map<string, Balance> = Map().withMutations((map) => {
|
||||
const balances: Map<string, Token> = Map().withMutations((map) => {
|
||||
balancesRecords.forEach(record => map.set(record.get('symbol'), record))
|
||||
map.set('ETH', ethBalance)
|
||||
})
|
||||
|
||||
return dispatch(addBalances(safeAddress, balances))
|
||||
return dispatch(addTokens(safeAddress, balances))
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line
|
||||
console.log("Error fetching token balances...")
|
|
@ -2,22 +2,26 @@
|
|||
import { Record } from 'immutable'
|
||||
import type { RecordFactory, RecordOf } from 'immutable'
|
||||
|
||||
export type BalanceProps = {
|
||||
export type TokenProps = {
|
||||
address: string,
|
||||
name: string,
|
||||
symbol: string,
|
||||
decimals: number,
|
||||
logoUrl: string,
|
||||
funds: string,
|
||||
status: boolean,
|
||||
removable: boolean,
|
||||
}
|
||||
|
||||
export const makeBalance: RecordFactory<BalanceProps> = Record({
|
||||
export const makeToken: RecordFactory<TokenProps> = Record({
|
||||
address: '',
|
||||
name: '',
|
||||
symbol: '',
|
||||
decimals: 0,
|
||||
logoUrl: '',
|
||||
funds: '0',
|
||||
status: true,
|
||||
removable: false,
|
||||
})
|
||||
|
||||
export type Balance = RecordOf<BalanceProps>
|
||||
export type Token = RecordOf<TokenProps>
|
|
@ -0,0 +1,26 @@
|
|||
// @flow
|
||||
import { Map } from 'immutable'
|
||||
import { handleActions, type ActionType } from 'redux-actions'
|
||||
import addTokens, { ADD_TOKENS } from '~/routes/tokens/store/actions/addTokens'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
import disableToken, { DISABLE_TOKEN } from '~/routes/tokens/store/actions/disableToken'
|
||||
import enableToken, { ENABLE_TOKEN } from '~/routes/tokens/store/actions/enableToken'
|
||||
|
||||
export const TOKEN_REDUCER_ID = 'tokens'
|
||||
|
||||
export type State = Map<string, Map<string, Token>>
|
||||
|
||||
export default handleActions({
|
||||
[ADD_TOKENS]: (state: State, action: ActionType<typeof addTokens>): State =>
|
||||
state.update(action.payload.safeAddress, (prevSafe: Map<string, Token>) => {
|
||||
if (!prevSafe) {
|
||||
return action.payload.tokens
|
||||
}
|
||||
|
||||
return prevSafe.equals(action.payload.tokens) ? prevSafe : action.payload.tokens
|
||||
}),
|
||||
[DISABLE_TOKEN]: (state: State, action: ActionType<typeof disableToken>): State =>
|
||||
state.setIn([action.payload.safeAddress, action.payload.symbol, 'status'], false),
|
||||
[ENABLE_TOKEN]: (state: State, action: ActionType<typeof enableToken>): State =>
|
||||
state.setIn([action.payload.safeAddress, action.payload.symbol, 'status'], true),
|
||||
}, Map())
|
|
@ -0,0 +1,36 @@
|
|||
// @flow
|
||||
import { List, Map } from 'immutable'
|
||||
import { createSelector, type Selector } from 'reselect'
|
||||
import { safeParamAddressSelector, type RouterProps } from '~/routes/safe/store/selectors'
|
||||
import { type GlobalState } from '~/store'
|
||||
import { TOKEN_REDUCER_ID } from '~/routes/tokens/store/reducer/tokens'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
|
||||
const balancesSelector = (state: GlobalState) => state[TOKEN_REDUCER_ID]
|
||||
|
||||
export const tokensSelector: Selector<GlobalState, RouterProps, Map<string, Token>> = createSelector(
|
||||
balancesSelector,
|
||||
safeParamAddressSelector,
|
||||
(balances: Map<string, Map<string, Token>>, address: string) => {
|
||||
if (!address) {
|
||||
return Map()
|
||||
}
|
||||
|
||||
return balances.get(address) || Map()
|
||||
},
|
||||
)
|
||||
|
||||
export const tokenListSelector = createSelector(
|
||||
tokensSelector,
|
||||
(balances: Map<string, Token>) => balances.toList(),
|
||||
)
|
||||
|
||||
export const tokenAddressesSelector = createSelector(
|
||||
tokenListSelector,
|
||||
(balances: List<Token>) => {
|
||||
const addresses = List().withMutations(list =>
|
||||
balances.map(token => list.push(token.address)))
|
||||
|
||||
return addresses
|
||||
},
|
||||
)
|
|
@ -5,7 +5,7 @@ import { combineReducers, createStore, applyMiddleware, compose, type Reducer, t
|
|||
import thunk from 'redux-thunk'
|
||||
import provider, { PROVIDER_REDUCER_ID, type State as ProviderState } from '~/wallets/store/reducer/provider'
|
||||
import safe, { SAFE_REDUCER_ID, type State as SafeState } from '~/routes/safe/store/reducer/safe'
|
||||
import balances, { BALANCE_REDUCER_ID, type State as BalancesState } from '~/routes/safe/store/reducer/balances'
|
||||
import tokens, { TOKEN_REDUCER_ID, type State as TokensState } from '~/routes/tokens/store/reducer/tokens'
|
||||
import transactions, { type State as TransactionsState, transactionsInitialState, TRANSACTIONS_REDUCER_ID } from '~/routes/safe/store/reducer/transactions'
|
||||
|
||||
export const history = createBrowserHistory()
|
||||
|
@ -20,7 +20,7 @@ const finalCreateStore = composeEnhancers(applyMiddleware(
|
|||
export type GlobalState = {
|
||||
providers: ProviderState,
|
||||
safes: SafeState,
|
||||
balances: BalancesState,
|
||||
tokens: TokensState,
|
||||
transactions: TransactionsState,
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ const reducers: Reducer<GlobalState> = combineReducers({
|
|||
routing: routerReducer,
|
||||
[PROVIDER_REDUCER_ID]: provider,
|
||||
[SAFE_REDUCER_ID]: safe,
|
||||
[BALANCE_REDUCER_ID]: balances,
|
||||
[TOKEN_REDUCER_ID]: tokens,
|
||||
[TRANSACTIONS_REDUCER_ID]: transactions,
|
||||
})
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// @flow
|
||||
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import * as fetchBalancesAction from '~/routes/safe/store/actions/fetchBalances'
|
||||
import * as fetchBalancesAction from '~/routes/tokens/store/actions/fetchTokens'
|
||||
import { aNewStore } from '~/store'
|
||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||
import { addTknTo, getTokenContract } from '~/test/utils/tokenMovements'
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
// @flow
|
||||
import { Map } from 'immutable'
|
||||
import { BALANCE_REDUCER_ID } from '~/routes/safe/store/reducer/balances'
|
||||
import * as fetchBalancesAction from '~/routes/safe/store/actions/fetchBalances'
|
||||
import * as fetchTokensAction from '~/routes/tokens/store/actions/fetchTokens'
|
||||
import { aNewStore } from '~/store'
|
||||
import { aMinedSafe } from '~/test/builder/safe.redux.builder'
|
||||
import { type Balance } from '~/routes/safe/store/model/balance'
|
||||
import { type Token } from '~/routes/tokens/store/model/token'
|
||||
import { TOKEN_REDUCER_ID } from '~/routes/tokens/store/reducer/tokens'
|
||||
import { addEtherTo, addTknTo } from '~/test/utils/tokenMovements'
|
||||
import { dispatchTknBalance } from '~/test/utils/transactions/moveTokens.helper'
|
||||
|
||||
|
@ -21,13 +21,13 @@ describe('Safe - redux balance property', () => {
|
|||
const tokenList = ['WE', '<3', 'GNO', 'OMG', 'RDN']
|
||||
|
||||
// WHEN
|
||||
await store.dispatch(fetchBalancesAction.fetchBalances(address))
|
||||
await store.dispatch(fetchTokensAction.fetchTokens(address))
|
||||
|
||||
// THEN
|
||||
const balances: Map<string, Map<string, Balance>> | typeof undefined = store.getState()[BALANCE_REDUCER_ID]
|
||||
if (!balances) throw new Error()
|
||||
const tokens: Map<string, Map<string, Token>> | typeof undefined = store.getState()[TOKEN_REDUCER_ID]
|
||||
if (!tokens) throw new Error()
|
||||
|
||||
const safeBalances: Map<string, Balance> | typeof undefined = balances.get(address)
|
||||
const safeBalances: Map<string, Token> | typeof undefined = tokens.get(address)
|
||||
if (!safeBalances) throw new Error()
|
||||
expect(safeBalances.size).toBe(6)
|
||||
|
||||
|
@ -41,13 +41,13 @@ describe('Safe - redux balance property', () => {
|
|||
it('reducer should return 0.03456 ETH as funds to safe with 0.03456 ETH', async () => {
|
||||
// WHEN
|
||||
await addEtherTo(address, '0.03456')
|
||||
await store.dispatch(fetchBalancesAction.fetchBalances(address))
|
||||
await store.dispatch(fetchTokensAction.fetchTokens(address))
|
||||
|
||||
// THEN
|
||||
const balances: Map<string, Map<string, Balance>> | typeof undefined = store.getState()[BALANCE_REDUCER_ID]
|
||||
if (!balances) throw new Error()
|
||||
const tokens: Map<string, Map<string, Token>> | typeof undefined = store.getState()[TOKEN_REDUCER_ID]
|
||||
if (!tokens) throw new Error()
|
||||
|
||||
const safeBalances: Map<string, Balance> | typeof undefined = balances.get(address)
|
||||
const safeBalances: Map<string, Token> | typeof undefined = tokens.get(address)
|
||||
if (!safeBalances) throw new Error()
|
||||
expect(safeBalances.size).toBe(6)
|
||||
|
||||
|
@ -65,7 +65,7 @@ describe('Safe - redux balance property', () => {
|
|||
await dispatchTknBalance(store, tokenAddress, address)
|
||||
|
||||
// THEN
|
||||
const safeBalances = store.getState()[BALANCE_REDUCER_ID].get(address)
|
||||
const safeBalances = store.getState()[TOKEN_REDUCER_ID].get(address)
|
||||
expect(safeBalances.size).toBe(1)
|
||||
|
||||
const tknBalance = safeBalances.get('TKN')
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
import { Map } from 'immutable'
|
||||
import TestUtils from 'react-dom/test-utils'
|
||||
import { sleep } from '~/utils/timer'
|
||||
import * as fetchBalancesAction from '~/routes/safe/store/actions/fetchBalances'
|
||||
import * as fetchTokensAction from '~/routes/tokens/store/actions/fetchTokens'
|
||||
import { checkMinedTx, checkPendingTx, EXPAND_BALANCE_INDEX } from '~/test/builder/safe.dom.utils'
|
||||
import { makeBalance, type Balance } from '~/routes/safe/store/model/balance'
|
||||
import addBalances from '~/routes/safe/store/actions/addBalances'
|
||||
import { whenExecuted } from '~/test/utils/logTransactions'
|
||||
import SendToken from '~/routes/safe/component/SendToken'
|
||||
import { makeToken, type Token } from '~/routes/tokens/store/model/token'
|
||||
import addTokens from '~/routes/tokens/store/actions/addTokens'
|
||||
|
||||
export const sendMoveTokensForm = async (
|
||||
SafeDom: React$Component<any, any>,
|
||||
|
@ -44,9 +44,9 @@ export const sendMoveTokensForm = async (
|
|||
}
|
||||
|
||||
export const dispatchTknBalance = async (store: Store, tokenAddress: string, address: string) => {
|
||||
const fetchBalancesMock = jest.spyOn(fetchBalancesAction, 'fetchBalances')
|
||||
const funds = await fetchBalancesAction.calculateBalanceOf(tokenAddress, address, 18)
|
||||
const balances: Map<string, Balance> = Map().set('TKN', makeBalance({
|
||||
const fetchBalancesMock = jest.spyOn(fetchTokensAction, 'fetchTokens')
|
||||
const funds = await fetchTokensAction.calculateBalanceOf(tokenAddress, address, 18)
|
||||
const balances: Map<string, Token> = Map().set('TKN', makeToken({
|
||||
address: tokenAddress,
|
||||
name: 'Token',
|
||||
symbol: 'TKN',
|
||||
|
@ -54,8 +54,8 @@ export const dispatchTknBalance = async (store: Store, tokenAddress: string, add
|
|||
logoUrl: 'https://github.com/TrustWallet/tokens/blob/master/images/0x6810e776880c02933d47db1b9fc05908e5386b96.png?raw=true',
|
||||
funds,
|
||||
}))
|
||||
fetchBalancesMock.mockImplementation(() => store.dispatch(addBalances(address, balances)))
|
||||
await store.dispatch(fetchBalancesAction.fetchBalances(address))
|
||||
fetchBalancesMock.mockImplementation(() => store.dispatch(addTokens(address, balances)))
|
||||
await store.dispatch(fetchTokensAction.fetchTokens(address))
|
||||
fetchBalancesMock.mockRestore()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue