* Replace 'Manage Tokens' with 'Manage List' * prevent 301 redirects * Add `BLACKLISTED_TOKENS` key to persist through immortal * Add store/action to extract _activate tokens by its balance_ - keeps already activated tokens - discards blacklisted tokens - adds tokens whose vales are bigger than zero and are not blacklisted * Add `blacklistedTokens` list to safe's store * Display activeTokensByBalance in 'Balances' screen * Enable token's blacklisting functionality in Tokens List * Retrieve balance from API * Rename action to `activateTokensByBalance` * Fix linting errors - line too long - required return * Do not persist a separate list into `BLACKLISTED_TOKENS`
This commit is contained in:
parent
85ff11796e
commit
21b7a59f20
|
@ -0,0 +1,16 @@
|
||||||
|
// @flow
|
||||||
|
import axios from 'axios'
|
||||||
|
import { getTxServiceHost } from '~/config/index'
|
||||||
|
|
||||||
|
const fetchTokenBalanceList = (safeAddress: string) => {
|
||||||
|
const apiUrl = getTxServiceHost()
|
||||||
|
const url = `${apiUrl}safes/${safeAddress}/balances/`
|
||||||
|
|
||||||
|
return axios.get(url, {
|
||||||
|
params: {
|
||||||
|
limit: 300,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default fetchTokenBalanceList
|
|
@ -4,7 +4,7 @@ import { getRelayUrl } from '~/config/index'
|
||||||
|
|
||||||
const fetchTokenList = () => {
|
const fetchTokenList = () => {
|
||||||
const apiUrl = getRelayUrl()
|
const apiUrl = getRelayUrl()
|
||||||
const url = `${apiUrl}/tokens`
|
const url = `${apiUrl}tokens/`
|
||||||
|
|
||||||
return axios.get(url, {
|
return axios.get(url, {
|
||||||
params: {
|
params: {
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
// @flow
|
||||||
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
|
import { Set } from 'immutable'
|
||||||
|
import { type GetState, type GlobalState } from '~/store'
|
||||||
|
import updateActiveTokens from '~/routes/safe/store/actions/updateActiveTokens'
|
||||||
|
import {
|
||||||
|
safeActiveTokensSelectorBySafe,
|
||||||
|
safeBlacklistedTokensSelectorBySafe,
|
||||||
|
safesMapSelector,
|
||||||
|
} from '~/routes/safe/store/selectors'
|
||||||
|
import fetchTokenBalanceList from '~/logic/tokens/api/fetchTokenBalanceList'
|
||||||
|
import updateSafe from '~/routes/safe/store/actions/updateSafe'
|
||||||
|
|
||||||
|
const activateTokensByBalance = (safeAddress: string) => async (
|
||||||
|
dispatch: ReduxDispatch<GlobalState>,
|
||||||
|
getState: GetState,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const result = await fetchTokenBalanceList(safeAddress)
|
||||||
|
const safes = safesMapSelector(getState())
|
||||||
|
const alreadyActiveTokens = safeActiveTokensSelectorBySafe(safeAddress, safes)
|
||||||
|
const blacklistedTokens = safeBlacklistedTokensSelectorBySafe(safeAddress, safes)
|
||||||
|
|
||||||
|
// addresses: potentially active tokens by balance
|
||||||
|
// balances: tokens' balance returned by the backend
|
||||||
|
const { addresses, balances } = result.data.reduce((acc, { tokenAddress, balance }) => ({
|
||||||
|
addresses: [...acc.addresses, tokenAddress],
|
||||||
|
balances: [...acc.balances, balance],
|
||||||
|
}), { addresses: [], balances: [] })
|
||||||
|
|
||||||
|
// update balance list for the safe
|
||||||
|
dispatch(updateSafe({ address: safeAddress, balances: Set(balances) }))
|
||||||
|
|
||||||
|
// active tokens by balance, excluding those already blacklisted and the `null` address
|
||||||
|
const activeByBalance = addresses.filter((address) => address !== null && !blacklistedTokens.includes(address))
|
||||||
|
|
||||||
|
// need to persist those already active tokens, despite its balances
|
||||||
|
const activeTokens = alreadyActiveTokens.toSet().union(activeByBalance)
|
||||||
|
|
||||||
|
// update list of active tokens
|
||||||
|
dispatch(updateActiveTokens(safeAddress, activeTokens))
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching token list', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default activateTokensByBalance
|
|
@ -2,7 +2,7 @@
|
||||||
import { createAction } from 'redux-actions'
|
import { createAction } from 'redux-actions'
|
||||||
import type { Dispatch as ReduxDispatch } from 'redux'
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
import { type Token } from '~/logic/tokens/store/model/token'
|
import { type Token } from '~/logic/tokens/store/model/token'
|
||||||
import { removeTokenFromStorage, removeFromActiveTokens } from '~/logic/tokens/utils/tokensStorage'
|
import { removeFromActiveTokens, removeTokenFromStorage } from '~/logic/tokens/utils/tokensStorage'
|
||||||
import { type GlobalState } from '~/store/index'
|
import { type GlobalState } from '~/store/index'
|
||||||
|
|
||||||
export const REMOVE_TOKEN = 'REMOVE_TOKEN'
|
export const REMOVE_TOKEN = 'REMOVE_TOKEN'
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
import fetchTokens from '~/logic/tokens/store/actions/fetchTokens'
|
import fetchTokens from '~/logic/tokens/store/actions/fetchTokens'
|
||||||
import { addToken } from '~/logic/tokens/store/actions/addToken'
|
import { addToken } from '~/logic/tokens/store/actions/addToken'
|
||||||
import updateActiveTokens from '~/routes/safe/store/actions/updateActiveTokens'
|
import updateActiveTokens from '~/routes/safe/store/actions/updateActiveTokens'
|
||||||
|
import updateBlacklistedTokens from '~/routes/safe/store/actions/updateBlacklistedTokens'
|
||||||
import activateTokenForAllSafes from '~/routes/safe/store/actions/activateTokenForAllSafes'
|
import activateTokenForAllSafes from '~/routes/safe/store/actions/activateTokenForAllSafes'
|
||||||
|
|
||||||
export type Actions = {
|
export type Actions = {
|
||||||
fetchTokens: Function,
|
fetchTokens: Function,
|
||||||
updateActiveTokens: Function,
|
updateActiveTokens: Function,
|
||||||
|
updateBlacklistedTokens: typeof updateBlacklistedTokens,
|
||||||
addToken: Function,
|
addToken: Function,
|
||||||
activateTokenForAllSafes: Function,
|
activateTokenForAllSafes: Function,
|
||||||
}
|
}
|
||||||
|
@ -15,5 +17,6 @@ export default {
|
||||||
fetchTokens,
|
fetchTokens,
|
||||||
addToken,
|
addToken,
|
||||||
updateActiveTokens,
|
updateActiveTokens,
|
||||||
|
updateBlacklistedTokens,
|
||||||
activateTokenForAllSafes,
|
activateTokenForAllSafes,
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ type Props = Actions & {
|
||||||
tokens: List<Token>,
|
tokens: List<Token>,
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
activeTokens: List<Token>,
|
activeTokens: List<Token>,
|
||||||
|
blacklistedTokens: List<Token>,
|
||||||
}
|
}
|
||||||
type ActiveScreen = 'tokenList' | 'addCustomToken'
|
type ActiveScreen = 'tokenList' | 'addCustomToken'
|
||||||
|
|
||||||
|
@ -32,8 +33,10 @@ const Tokens = (props: Props) => {
|
||||||
classes,
|
classes,
|
||||||
tokens,
|
tokens,
|
||||||
activeTokens,
|
activeTokens,
|
||||||
|
blacklistedTokens,
|
||||||
fetchTokens,
|
fetchTokens,
|
||||||
updateActiveTokens,
|
updateActiveTokens,
|
||||||
|
updateBlacklistedTokens,
|
||||||
safeAddress,
|
safeAddress,
|
||||||
addToken,
|
addToken,
|
||||||
activateTokenForAllSafes,
|
activateTokenForAllSafes,
|
||||||
|
@ -43,7 +46,7 @@ const Tokens = (props: Props) => {
|
||||||
<>
|
<>
|
||||||
<Row align="center" grow className={classes.heading}>
|
<Row align="center" grow className={classes.heading}>
|
||||||
<Paragraph size="xl" noMargin weight="bolder">
|
<Paragraph size="xl" noMargin weight="bolder">
|
||||||
Manage Tokens
|
Manage List
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
<IconButton onClick={onClose} disableRipple data-testid={MANAGE_TOKENS_MODAL_CLOSE_BUTTON_TEST_ID}>
|
<IconButton onClick={onClose} disableRipple data-testid={MANAGE_TOKENS_MODAL_CLOSE_BUTTON_TEST_ID}>
|
||||||
<Close className={classes.close} />
|
<Close className={classes.close} />
|
||||||
|
@ -54,8 +57,10 @@ const Tokens = (props: Props) => {
|
||||||
<TokenList
|
<TokenList
|
||||||
tokens={tokens}
|
tokens={tokens}
|
||||||
activeTokens={activeTokens}
|
activeTokens={activeTokens}
|
||||||
|
blacklistedTokens={blacklistedTokens}
|
||||||
fetchTokens={fetchTokens}
|
fetchTokens={fetchTokens}
|
||||||
updateActiveTokens={updateActiveTokens}
|
updateActiveTokens={updateActiveTokens}
|
||||||
|
updateBlacklistedTokens={updateBlacklistedTokens}
|
||||||
safeAddress={safeAddress}
|
safeAddress={safeAddress}
|
||||||
setActiveScreen={setActiveScreen}
|
setActiveScreen={setActiveScreen}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -25,14 +25,17 @@ type Props = {
|
||||||
tokens: List<Token>,
|
tokens: List<Token>,
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
activeTokens: List<Token>,
|
activeTokens: List<Token>,
|
||||||
fetchTokens: Function,
|
blacklistedTokens: List<Token>,
|
||||||
updateActiveTokens: Function,
|
updateActiveTokens: Function,
|
||||||
|
updateBlacklistedTokens: Function,
|
||||||
setActiveScreen: Function,
|
setActiveScreen: Function,
|
||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
filter: string,
|
filter: string,
|
||||||
activeTokensAddresses: Set<string>,
|
activeTokensAddresses: Set<string>,
|
||||||
|
initialActiveTokensAddresses: Set<string>,
|
||||||
|
blacklistedTokensAddresses: Set<string>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterBy = (filter: string, tokens: List<Token>): List<Token> => tokens.filter(
|
const filterBy = (filter: string, tokens: List<Token>): List<Token> => tokens.filter(
|
||||||
|
@ -52,13 +55,10 @@ class Tokens extends React.Component<Props, State> {
|
||||||
state = {
|
state = {
|
||||||
filter: '',
|
filter: '',
|
||||||
activeTokensAddresses: Set([]),
|
activeTokensAddresses: Set([]),
|
||||||
|
initialActiveTokensAddresses: Set([]),
|
||||||
|
blacklistedTokensAddresses: Set([]),
|
||||||
activeTokensCalculated: false,
|
activeTokensCalculated: false,
|
||||||
}
|
blacklistedTokensCalculated: false,
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
const { fetchTokens } = this.props
|
|
||||||
|
|
||||||
fetchTokens()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static getDerivedStateFromProps(nextProps, prevState) {
|
static getDerivedStateFromProps(nextProps, prevState) {
|
||||||
|
@ -70,17 +70,29 @@ class Tokens extends React.Component<Props, State> {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeTokensAddresses: Set(activeTokens.map(({ address }) => address)),
|
activeTokensAddresses: Set(activeTokens.map(({ address }) => address)),
|
||||||
|
initialActiveTokensAddresses: Set(activeTokens.map(({ address }) => address)),
|
||||||
activeTokensCalculated: true,
|
activeTokensCalculated: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!prevState.blacklistedTokensCalculated) {
|
||||||
|
const { blacklistedTokens } = nextProps
|
||||||
|
|
||||||
|
return {
|
||||||
|
blacklistedTokensAddresses: blacklistedTokens,
|
||||||
|
blacklistedTokensCalculated: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const { activeTokensAddresses } = this.state
|
const { activeTokensAddresses, blacklistedTokensAddresses } = this.state
|
||||||
const { updateActiveTokens, safeAddress } = this.props
|
const { updateActiveTokens, updateBlacklistedTokens, safeAddress } = this.props
|
||||||
|
|
||||||
updateActiveTokens(safeAddress, activeTokensAddresses)
|
updateActiveTokens(safeAddress, activeTokensAddresses)
|
||||||
|
updateBlacklistedTokens(safeAddress, blacklistedTokensAddresses)
|
||||||
}
|
}
|
||||||
|
|
||||||
onCancelSearch = () => {
|
onCancelSearch = () => {
|
||||||
|
@ -92,17 +104,20 @@ class Tokens extends React.Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSwitch = (token: Token) => () => {
|
onSwitch = (token: Token) => () => {
|
||||||
const { activeTokensAddresses } = this.state
|
this.setState((prevState) => {
|
||||||
|
const activeTokensAddresses = prevState.activeTokensAddresses.has(token.address)
|
||||||
|
? prevState.activeTokensAddresses.remove(token.address)
|
||||||
|
: prevState.activeTokensAddresses.add(token.address)
|
||||||
|
|
||||||
|
let { blacklistedTokensAddresses } = prevState
|
||||||
if (activeTokensAddresses.has(token.address)) {
|
if (activeTokensAddresses.has(token.address)) {
|
||||||
this.setState({
|
blacklistedTokensAddresses = prevState.blacklistedTokensAddresses.remove(token.address)
|
||||||
activeTokensAddresses: activeTokensAddresses.remove(token.address),
|
} else if (prevState.initialActiveTokensAddresses.has(token.address)) {
|
||||||
})
|
blacklistedTokensAddresses = prevState.blacklistedTokensAddresses.add(token.address)
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
activeTokensAddresses: activeTokensAddresses.add(token.address),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ({ ...prevState, activeTokensAddresses, blacklistedTokensAddresses })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
createItemData = (tokens, activeTokensAddresses) => ({
|
createItemData = (tokens, activeTokensAddresses) => ({
|
||||||
|
|
|
@ -38,6 +38,9 @@ type Props = {
|
||||||
granted: boolean,
|
granted: boolean,
|
||||||
tokens: List<Token>,
|
tokens: List<Token>,
|
||||||
activeTokens: List<Token>,
|
activeTokens: List<Token>,
|
||||||
|
blacklistedTokens: List<Token>,
|
||||||
|
activateTokensByBalance: Function,
|
||||||
|
fetchTokens: Function,
|
||||||
safeAddress: string,
|
safeAddress: string,
|
||||||
safeName: string,
|
safeName: string,
|
||||||
ethBalance: string,
|
ethBalance: string,
|
||||||
|
@ -57,6 +60,7 @@ class Balances extends React.Component<Props, State> {
|
||||||
},
|
},
|
||||||
showReceive: false,
|
showReceive: false,
|
||||||
}
|
}
|
||||||
|
props.fetchTokens()
|
||||||
}
|
}
|
||||||
|
|
||||||
onShow = (action: Action) => () => {
|
onShow = (action: Action) => () => {
|
||||||
|
@ -85,6 +89,17 @@ class Balances extends React.Component<Props, State> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
||||||
|
const { checked } = e.target
|
||||||
|
|
||||||
|
this.setState(() => ({ hideZero: checked }))
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
const { activateTokensByBalance, safeAddress } = this.props
|
||||||
|
activateTokensByBalance(safeAddress)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
showToken, showReceive, sendFunds,
|
showToken, showReceive, sendFunds,
|
||||||
|
@ -95,6 +110,7 @@ class Balances extends React.Component<Props, State> {
|
||||||
tokens,
|
tokens,
|
||||||
safeAddress,
|
safeAddress,
|
||||||
activeTokens,
|
activeTokens,
|
||||||
|
blacklistedTokens,
|
||||||
safeName,
|
safeName,
|
||||||
ethBalance,
|
ethBalance,
|
||||||
createTransaction,
|
createTransaction,
|
||||||
|
@ -110,10 +126,10 @@ class Balances extends React.Component<Props, State> {
|
||||||
<Row align="center" className={classes.message}>
|
<Row align="center" className={classes.message}>
|
||||||
<Col xs={12} end="sm">
|
<Col xs={12} end="sm">
|
||||||
<ButtonLink size="lg" onClick={this.onShow('Token')} testId="manage-tokens-btn">
|
<ButtonLink size="lg" onClick={this.onShow('Token')} testId="manage-tokens-btn">
|
||||||
Manage Tokens
|
Manage List
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
<Modal
|
<Modal
|
||||||
title="Manage Tokens"
|
title="Manage List"
|
||||||
description="Enable and disable tokens to be listed"
|
description="Enable and disable tokens to be listed"
|
||||||
handleClose={this.onHide('Token')}
|
handleClose={this.onHide('Token')}
|
||||||
open={showToken}
|
open={showToken}
|
||||||
|
@ -123,6 +139,7 @@ class Balances extends React.Component<Props, State> {
|
||||||
onClose={this.onHide('Token')}
|
onClose={this.onHide('Token')}
|
||||||
safeAddress={safeAddress}
|
safeAddress={safeAddress}
|
||||||
activeTokens={activeTokens}
|
activeTokens={activeTokens}
|
||||||
|
blacklistedTokens={blacklistedTokens}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
|
@ -60,9 +60,12 @@ const Layout = (props: Props) => {
|
||||||
granted,
|
granted,
|
||||||
tokens,
|
tokens,
|
||||||
activeTokens,
|
activeTokens,
|
||||||
|
blacklistedTokens,
|
||||||
createTransaction,
|
createTransaction,
|
||||||
processTransaction,
|
processTransaction,
|
||||||
fetchTransactions,
|
fetchTransactions,
|
||||||
|
activateTokensByBalance,
|
||||||
|
fetchTokens,
|
||||||
updateSafe,
|
updateSafe,
|
||||||
transactions,
|
transactions,
|
||||||
userAddress,
|
userAddress,
|
||||||
|
@ -156,8 +159,11 @@ const Layout = (props: Props) => {
|
||||||
ethBalance={ethBalance}
|
ethBalance={ethBalance}
|
||||||
tokens={tokens}
|
tokens={tokens}
|
||||||
activeTokens={activeTokens}
|
activeTokens={activeTokens}
|
||||||
|
blacklistedTokens={blacklistedTokens}
|
||||||
granted={granted}
|
granted={granted}
|
||||||
safeAddress={address}
|
safeAddress={address}
|
||||||
|
activateTokensByBalance={activateTokensByBalance}
|
||||||
|
fetchTokens={fetchTokens}
|
||||||
safeName={name}
|
safeName={name}
|
||||||
createTransaction={createTransaction}
|
createTransaction={createTransaction}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import processTransaction from '~/routes/safe/store/actions/processTransaction'
|
||||||
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
import fetchTransactions from '~/routes/safe/store/actions/fetchTransactions'
|
||||||
import updateSafe from '~/routes/safe/store/actions/updateSafe'
|
import updateSafe from '~/routes/safe/store/actions/updateSafe'
|
||||||
import fetchTokens from '~/logic/tokens/store/actions/fetchTokens'
|
import fetchTokens from '~/logic/tokens/store/actions/fetchTokens'
|
||||||
|
import activateTokensByBalance from '~/logic/tokens/store/actions/activateTokensByBalance'
|
||||||
|
|
||||||
export type Actions = {
|
export type Actions = {
|
||||||
fetchSafe: typeof fetchSafe,
|
fetchSafe: typeof fetchSafe,
|
||||||
|
@ -17,6 +18,7 @@ export type Actions = {
|
||||||
fetchTokens: typeof fetchTokens,
|
fetchTokens: typeof fetchTokens,
|
||||||
processTransaction: typeof processTransaction,
|
processTransaction: typeof processTransaction,
|
||||||
fetchEtherBalance: typeof fetchEtherBalance,
|
fetchEtherBalance: typeof fetchEtherBalance,
|
||||||
|
activateTokensByBalance: typeof activateTokensByBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -26,6 +28,7 @@ export default {
|
||||||
processTransaction,
|
processTransaction,
|
||||||
fetchTokens,
|
fetchTokens,
|
||||||
fetchTransactions,
|
fetchTransactions,
|
||||||
|
activateTokensByBalance,
|
||||||
updateSafe,
|
updateSafe,
|
||||||
fetchEtherBalance,
|
fetchEtherBalance,
|
||||||
checkAndUpdateSafeOwners,
|
checkAndUpdateSafeOwners,
|
||||||
|
|
|
@ -102,6 +102,7 @@ class SafeView extends React.Component<Props, State> {
|
||||||
safe,
|
safe,
|
||||||
provider,
|
provider,
|
||||||
activeTokens,
|
activeTokens,
|
||||||
|
blacklistedTokens,
|
||||||
granted,
|
granted,
|
||||||
userAddress,
|
userAddress,
|
||||||
network,
|
network,
|
||||||
|
@ -109,6 +110,8 @@ class SafeView extends React.Component<Props, State> {
|
||||||
createTransaction,
|
createTransaction,
|
||||||
processTransaction,
|
processTransaction,
|
||||||
fetchTransactions,
|
fetchTransactions,
|
||||||
|
activateTokensByBalance,
|
||||||
|
fetchTokens,
|
||||||
updateSafe,
|
updateSafe,
|
||||||
transactions,
|
transactions,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
@ -117,6 +120,7 @@ class SafeView extends React.Component<Props, State> {
|
||||||
<Page>
|
<Page>
|
||||||
<Layout
|
<Layout
|
||||||
activeTokens={activeTokens}
|
activeTokens={activeTokens}
|
||||||
|
blacklistedTokens={blacklistedTokens}
|
||||||
tokens={tokens}
|
tokens={tokens}
|
||||||
provider={provider}
|
provider={provider}
|
||||||
safe={safe}
|
safe={safe}
|
||||||
|
@ -126,6 +130,8 @@ class SafeView extends React.Component<Props, State> {
|
||||||
createTransaction={createTransaction}
|
createTransaction={createTransaction}
|
||||||
processTransaction={processTransaction}
|
processTransaction={processTransaction}
|
||||||
fetchTransactions={fetchTransactions}
|
fetchTransactions={fetchTransactions}
|
||||||
|
activateTokensByBalance={activateTokensByBalance}
|
||||||
|
fetchTokens={fetchTokens}
|
||||||
updateSafe={updateSafe}
|
updateSafe={updateSafe}
|
||||||
transactions={transactions}
|
transactions={transactions}
|
||||||
sendFunds={sendFunds}
|
sendFunds={sendFunds}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
safeSelector,
|
safeSelector,
|
||||||
safeActiveTokensSelector,
|
safeActiveTokensSelector,
|
||||||
safeBalancesSelector,
|
safeBalancesSelector,
|
||||||
|
safeBlacklistedTokensSelector,
|
||||||
type RouterProps,
|
type RouterProps,
|
||||||
type SafeSelectorProps,
|
type SafeSelectorProps,
|
||||||
} from '~/routes/safe/store/selectors'
|
} from '~/routes/safe/store/selectors'
|
||||||
|
@ -25,6 +26,7 @@ export type SelectorProps = {
|
||||||
provider: string,
|
provider: string,
|
||||||
tokens: List<Token>,
|
tokens: List<Token>,
|
||||||
activeTokens: List<Token>,
|
activeTokens: List<Token>,
|
||||||
|
blacklistedTokens: List<Token>,
|
||||||
userAddress: string,
|
userAddress: string,
|
||||||
network: string,
|
network: string,
|
||||||
safeUrl: string,
|
safeUrl: string,
|
||||||
|
@ -135,6 +137,7 @@ export default createStructuredSelector<Object, *>({
|
||||||
provider: providerNameSelector,
|
provider: providerNameSelector,
|
||||||
tokens: orderedTokenListSelector,
|
tokens: orderedTokenListSelector,
|
||||||
activeTokens: extendedSafeTokensSelector,
|
activeTokens: extendedSafeTokensSelector,
|
||||||
|
blacklistedTokens: safeBlacklistedTokensSelector,
|
||||||
granted: grantedSelector,
|
granted: grantedSelector,
|
||||||
userAddress: userAccountSelector,
|
userAddress: userAccountSelector,
|
||||||
network: networkSelector,
|
network: networkSelector,
|
||||||
|
|
|
@ -19,7 +19,7 @@ export const calculateBalanceOf = async (tokenAddress: string, safeAddress: stri
|
||||||
const token = await erc20Token.at(tokenAddress)
|
const token = await erc20Token.at(tokenAddress)
|
||||||
balance = await token.balanceOf(safeAddress)
|
balance = await token.balanceOf(safeAddress)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to fetch token balances: ', err)
|
console.error('Failed to fetch token balances: ', tokenAddress, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return new BigNumber(balance).div(10 ** decimals).toString()
|
return new BigNumber(balance).div(10 ** decimals).toString()
|
||||||
|
@ -50,7 +50,6 @@ const fetchTokenBalances = (safeAddress: string, tokens: List<Token>) => async (
|
||||||
|
|
||||||
dispatch(updateSafe({ address: safeAddress, balances }))
|
dispatch(updateSafe({ address: safeAddress, balances }))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line
|
|
||||||
console.error('Error when fetching token balances:', err)
|
console.error('Error when fetching token balances:', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// @flow
|
||||||
|
import { Set } from 'immutable'
|
||||||
|
import type { Dispatch as ReduxDispatch } from 'redux'
|
||||||
|
import { type GlobalState } from '~/store'
|
||||||
|
import updateSafe from './updateSafe'
|
||||||
|
|
||||||
|
const updateBlacklistedTokens = (safeAddress: string, blacklistedTokens: Set<string>) => async (
|
||||||
|
dispatch: ReduxDispatch<GlobalState>,
|
||||||
|
) => {
|
||||||
|
dispatch(updateSafe({ address: safeAddress, blacklistedTokens }))
|
||||||
|
}
|
||||||
|
|
||||||
|
export default updateBlacklistedTokens
|
|
@ -1,5 +1,5 @@
|
||||||
// @flow
|
// @flow
|
||||||
import type { Store, AnyAction } from 'redux'
|
import type { AnyAction, Store } from 'redux'
|
||||||
import { List } from 'immutable'
|
import { List } from 'immutable'
|
||||||
import { ADD_SAFE } from '~/routes/safe/store/actions/addSafe'
|
import { ADD_SAFE } from '~/routes/safe/store/actions/addSafe'
|
||||||
import { UPDATE_SAFE } from '~/routes/safe/store/actions/updateSafe'
|
import { UPDATE_SAFE } from '~/routes/safe/store/actions/updateSafe'
|
||||||
|
@ -10,10 +10,12 @@ import { REPLACE_SAFE_OWNER } from '~/routes/safe/store/actions/replaceSafeOwner
|
||||||
import { EDIT_SAFE_OWNER } from '~/routes/safe/store/actions/editSafeOwner'
|
import { EDIT_SAFE_OWNER } from '~/routes/safe/store/actions/editSafeOwner'
|
||||||
import { type GlobalState } from '~/store/'
|
import { type GlobalState } from '~/store/'
|
||||||
import {
|
import {
|
||||||
saveSafes, setOwners, removeOwners, saveDefaultSafe,
|
removeOwners,
|
||||||
|
saveDefaultSafe,
|
||||||
|
saveSafes,
|
||||||
|
setOwners,
|
||||||
} from '~/logic/safe/utils'
|
} from '~/logic/safe/utils'
|
||||||
import { safesMapSelector, getActiveTokensAddressesForAllSafes } from '~/routes/safe/store/selectors'
|
import { getActiveTokensAddressesForAllSafes, safesMapSelector } from '~/routes/safe/store/selectors'
|
||||||
|
|
||||||
import { tokensSelector } from '~/logic/tokens/store/selectors'
|
import { tokensSelector } from '~/logic/tokens/store/selectors'
|
||||||
import type { Token } from '~/logic/tokens/store/model/token'
|
import type { Token } from '~/logic/tokens/store/model/token'
|
||||||
import { makeOwner } from '~/routes/safe/store/models/owner'
|
import { makeOwner } from '~/routes/safe/store/models/owner'
|
||||||
|
|
|
@ -12,6 +12,7 @@ export type SafeProps = {
|
||||||
owners: List<Owner>,
|
owners: List<Owner>,
|
||||||
balances?: Map<string, string>,
|
balances?: Map<string, string>,
|
||||||
activeTokens: Set<string>,
|
activeTokens: Set<string>,
|
||||||
|
blacklistedTokens: Set<string>,
|
||||||
ethBalance?: string,
|
ethBalance?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ const SafeRecord: RecordFactory<SafeProps> = Record({
|
||||||
ethBalance: 0,
|
ethBalance: 0,
|
||||||
owners: List([]),
|
owners: List([]),
|
||||||
activeTokens: new Set(),
|
activeTokens: new Set(),
|
||||||
|
blacklistedTokens: new Set(),
|
||||||
balances: Map({}),
|
balances: Map({}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ export const buildSafe = (storedSafe: SafeProps) => {
|
||||||
const addresses = storedSafe.owners.map((owner: OwnerProps) => owner.address)
|
const addresses = storedSafe.owners.map((owner: OwnerProps) => owner.address)
|
||||||
const owners = buildOwnersFrom(Array.from(names), Array.from(addresses))
|
const owners = buildOwnersFrom(Array.from(names), Array.from(addresses))
|
||||||
const activeTokens = Set(storedSafe.activeTokens)
|
const activeTokens = Set(storedSafe.activeTokens)
|
||||||
|
const blacklistedTokens = Set(storedSafe.blacklistedTokens)
|
||||||
const balances = Map(storedSafe.balances)
|
const balances = Map(storedSafe.balances)
|
||||||
|
|
||||||
const safe: SafeProps = {
|
const safe: SafeProps = {
|
||||||
|
@ -29,6 +30,7 @@ export const buildSafe = (storedSafe: SafeProps) => {
|
||||||
owners,
|
owners,
|
||||||
balances,
|
balances,
|
||||||
activeTokens,
|
activeTokens,
|
||||||
|
blacklistedTokens,
|
||||||
}
|
}
|
||||||
|
|
||||||
return safe
|
return safe
|
||||||
|
|
|
@ -106,6 +106,21 @@ export const safeActiveTokensSelector: Selector<GlobalState, RouterProps, List<s
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const safeBlacklistedTokensSelector: Selector<GlobalState, RouterProps, List<string>> = createSelector(
|
||||||
|
safeSelector,
|
||||||
|
(safe: Safe) => {
|
||||||
|
if (!safe) {
|
||||||
|
return List()
|
||||||
|
}
|
||||||
|
|
||||||
|
return safe.blacklistedTokens
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
export const safeActiveTokensSelectorBySafe = (safeAddress: string, safes: Map<string, Safe>): List<string> => safes.get(safeAddress).get('activeTokens')
|
||||||
|
|
||||||
|
export const safeBlacklistedTokensSelectorBySafe = (safeAddress: string, safes: Map<string, Safe>): List<string> => safes.get(safeAddress).get('blacklistedTokens')
|
||||||
|
|
||||||
export const safeBalancesSelector: Selector<GlobalState, RouterProps, Map<string, string>> = createSelector(
|
export const safeBalancesSelector: Selector<GlobalState, RouterProps, Map<string, string>> = createSelector(
|
||||||
safeSelector,
|
safeSelector,
|
||||||
(safe: Safe) => {
|
(safe: Safe) => {
|
||||||
|
@ -132,7 +147,23 @@ export const getActiveTokensAddressesForAllSafes: Selector<GlobalState, any, Set
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export const getBlacklistedTokensAddressesForAllSafes: Selector<GlobalState, any, Set<string>> = createSelector(
|
||||||
|
safesListSelector,
|
||||||
|
(safes: List<Safe>) => {
|
||||||
|
const addresses = Set().withMutations((set) => {
|
||||||
|
safes.forEach((safe: Safe) => {
|
||||||
|
safe.blacklistedTokens.forEach((tokenAddress) => {
|
||||||
|
set.add(tokenAddress)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return addresses
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
export default createStructuredSelector<Object, *>({
|
export default createStructuredSelector<Object, *>({
|
||||||
safe: safeSelector,
|
safe: safeSelector,
|
||||||
tokens: safeActiveTokensSelector,
|
tokens: safeActiveTokensSelector,
|
||||||
|
blacklistedTokens: safeBlacklistedTokensSelector,
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue