diff --git a/src/components/layout/Paragraph/index.scss b/src/components/layout/Paragraph/index.scss
index ea3a5550..ed0652fd 100644
--- a/src/components/layout/Paragraph/index.scss
+++ b/src/components/layout/Paragraph/index.scss
@@ -4,15 +4,15 @@
}
.soft {
- color: #888888;
+ color: #888888;
}
.medium {
- color: #686868;
+ color: #686868;
}
.dark {
- color: black;
+ color: black;
}
.primary {
diff --git a/src/routes/open/components/Layout.test.js b/src/routes/open/components/Layout.test.js
index b41ed29f..4193d974 100644
--- a/src/routes/open/components/Layout.test.js
+++ b/src/routes/open/components/Layout.test.js
@@ -1,33 +1,18 @@
// @flow
-import * as React from 'react'
import TestUtils from 'react-dom/test-utils'
-import Open from '~/routes/open/container/Open'
-import { Provider } from 'react-redux'
-import { ConnectedRouter } from 'react-router-redux'
+import { store } from '~/store'
import { FIELD_NAME, FIELD_OWNERS, FIELD_CONFIRMATIONS, getOwnerNameBy, getOwnerAddressBy } from '~/routes/open/components/fields'
import { DEPLOYED_COMPONENT_ID } from '~/routes/open/components/FormConfirmation'
-import { history, store } from '~/store'
import { sleep } from '~/utils/timer'
import { getProviderInfo } from '~/wallets/getWeb3'
-import addProvider from '~/wallets/store/actions/addProvider'
-import { makeProvider } from '~/wallets/store/model/provider'
+import { renderSafe } from '~/routes/safe/store/test/builder/deployedSafe.builder'
describe('React DOM TESTS > Create Safe form', () => {
let open
let provider
beforeEach(async () => {
- // init app web3 instance
provider = await getProviderInfo()
- const walletRecord = makeProvider(provider)
- store.dispatch(addProvider(walletRecord))
-
- open = TestUtils.renderIntoDocument((
-
-
-
-
-
- ))
+ open = await renderSafe(store)
})
it('should create a 1 owner safe after rendering correctly the form', async () => {
diff --git a/src/routes/safe/component/Layout.jsx b/src/routes/safe/component/Layout.jsx
index 681b227e..e3b7f636 100644
--- a/src/routes/safe/component/Layout.jsx
+++ b/src/routes/safe/component/Layout.jsx
@@ -6,10 +6,10 @@ import GnoSafe from './Safe'
type Props = SelectorProps
-const Layout = ({ safe, provider }: Props) => (
+const Layout = ({ safe, balance, provider }: Props) => (
{ safe
- ?
+ ?
:
}
diff --git a/src/routes/safe/component/Layout.stories.js b/src/routes/safe/component/Layout.stories.js
index ab6db99d..83cfecea 100644
--- a/src/routes/safe/component/Layout.stories.js
+++ b/src/routes/safe/component/Layout.stories.js
@@ -2,7 +2,7 @@
import { storiesOf } from '@storybook/react'
import * as React from 'react'
import styles from '~/components/layout/PageFrame/index.scss'
-import { SafeFactory } from '~/routes/safe/store/test/builder/index.builder'
+import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import Component from './Layout'
@@ -14,12 +14,31 @@ const FrameDecorator = story => (
storiesOf('Routes /safe:address', module)
.addDecorator(FrameDecorator)
- .add('Safe undefined being connected', () => )
- .add('Safe undefined NOT connected', () => )
+ .add('Safe undefined being connected', () => (
+ {}}
+ />
+ ))
+ .add('Safe undefined NOT connected', () => (
+ {}}
+ />
+ ))
.add('Safe with 2 owners', () => {
const safe = SafeFactory.twoOwnersSafe
return (
-
+ {}}
+ />
)
})
diff --git a/src/routes/safe/component/Safe.jsx b/src/routes/safe/component/Safe.jsx
index 7c7b4dd9..69b86137 100644
--- a/src/routes/safe/component/Safe.jsx
+++ b/src/routes/safe/component/Safe.jsx
@@ -10,9 +10,10 @@ import { type Safe } from '~/routes/safe/store/model/safe'
type SafeProps = {
safe: Safe,
+ balance: string,
}
-const GnoSafe = ({ safe }: SafeProps) => (
+const GnoSafe = ({ safe, balance }: SafeProps) => (
@@ -21,6 +22,18 @@ const GnoSafe = ({ safe }: SafeProps) => (
+
+
+ Balance
+
+
+
+
+
+ {balance} - ETH
+
+
+
Address
diff --git a/src/routes/safe/container/actions.js b/src/routes/safe/container/actions.js
new file mode 100644
index 00000000..e489176c
--- /dev/null
+++ b/src/routes/safe/container/actions.js
@@ -0,0 +1,10 @@
+// @flow
+import fetchBalance from '~/routes/safe/store/actions/fetchBalance'
+
+export type Actions = {
+ fetchBalance: typeof fetchBalance,
+}
+
+export default {
+ fetchBalance,
+}
diff --git a/src/routes/safe/container/index.jsx b/src/routes/safe/container/index.jsx
index 348fd17f..e4575fac 100644
--- a/src/routes/safe/container/index.jsx
+++ b/src/routes/safe/container/index.jsx
@@ -4,19 +4,40 @@ import { connect } from 'react-redux'
import Page from '~/components/layout/Page'
import Layout from '~/routes/safe/component/Layout'
import selector, { type SelectorProps } from './selector'
+import actions, { type Actions } from './actions'
-type Props = SelectorProps
+type Props = Actions & SelectorProps
class SafeView extends React.PureComponent {
+ componentDidMount() {
+ this.intervalId = setInterval(() => {
+ const { safe, fetchBalance } = this.props
+ if (!safe) { return }
+
+ const safeAddress: string = safe.get('address')
+ fetchBalance(safeAddress)
+ }, 1500)
+ }
+
+ componentWillUnmount() {
+ clearInterval(this.intervalId)
+ }
+
+ intervalId: IntervalID
+
render() {
- const { safe, provider } = this.props
+ const { safe, provider, balance } = this.props
return (
-
+
)
}
}
-export default connect(selector)(SafeView)
+export default connect(selector, actions)(SafeView)
diff --git a/src/routes/safe/container/selector.js b/src/routes/safe/container/selector.js
index 86af6918..3ac175f5 100644
--- a/src/routes/safe/container/selector.js
+++ b/src/routes/safe/container/selector.js
@@ -1,14 +1,16 @@
// @flow
import { createStructuredSelector } from 'reselect'
-import { safeSelector, type SafeSelectorProps } from '~/routes/safe/store/selectors'
+import { balanceSelector, safeSelector, type SafeSelectorProps } from '~/routes/safe/store/selectors'
import { providerNameSelector } from '~/wallets/store/selectors/index'
export type SelectorProps = {
safe: SafeSelectorProps,
provider: string,
+ balance: string,
}
export default createStructuredSelector({
safe: safeSelector,
provider: providerNameSelector,
+ balance: balanceSelector,
})
diff --git a/src/routes/safe/store/actions/addBalance.js b/src/routes/safe/store/actions/addBalance.js
new file mode 100644
index 00000000..7051769b
--- /dev/null
+++ b/src/routes/safe/store/actions/addBalance.js
@@ -0,0 +1,19 @@
+// @flow
+import { createAction } from 'redux-actions'
+
+export const ADD_BALANCE = 'ADD_BALANCE'
+
+type BalanceProps = {
+ safeAddress: string,
+ funds: string,
+}
+
+const addBalance = createAction(
+ ADD_BALANCE,
+ (safeAddress: string, funds: string): BalanceProps => ({
+ safeAddress,
+ funds,
+ }),
+)
+
+export default addBalance
diff --git a/src/routes/safe/store/actions/fetchBalance.js b/src/routes/safe/store/actions/fetchBalance.js
new file mode 100644
index 00000000..430682d8
--- /dev/null
+++ b/src/routes/safe/store/actions/fetchBalance.js
@@ -0,0 +1,11 @@
+// @flow
+import type { Dispatch as ReduxDispatch } from 'redux'
+import { getBalanceInEtherOf } from '~/wallets/getWeb3'
+import { type GlobalState } from '~/store/index'
+import addBalance from './addBalance'
+
+export default (safeAddress: string) => async (dispatch: ReduxDispatch) => {
+ const balance = await getBalanceInEtherOf(safeAddress)
+
+ return dispatch(addBalance(safeAddress, balance))
+}
diff --git a/src/routes/safe/store/reducer/balances.js b/src/routes/safe/store/reducer/balances.js
new file mode 100644
index 00000000..518db150
--- /dev/null
+++ b/src/routes/safe/store/reducer/balances.js
@@ -0,0 +1,13 @@
+// @flow
+import { Map } from 'immutable'
+import { handleActions, type ActionType } from 'redux-actions'
+import addBalance, { ADD_BALANCE } from '~/routes/safe/store/actions/addBalance'
+
+export const BALANCE_REDUCER_ID = 'balances'
+
+export type State = Map
+
+export default handleActions({
+ [ADD_BALANCE]: (state: State, action: ActionType): State =>
+ state.set(action.payload.safeAddress, action.payload.funds),
+}, Map())
diff --git a/src/routes/safe/store/selectors/index.js b/src/routes/safe/store/selectors/index.js
index 4c403eb5..1bcd96f2 100644
--- a/src/routes/safe/store/selectors/index.js
+++ b/src/routes/safe/store/selectors/index.js
@@ -6,6 +6,7 @@ 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'
type RouterProps = {
match: Match,
@@ -13,6 +14,8 @@ type RouterProps = {
const safeAddessSelector = (state: GlobalState, props: RouterProps) => props.match.params[SAFE_PARAM_ADDRESS] || ''
+const balancesSelector = (state: GlobalState) => state[BALANCE_REDUCER_ID]
+
export type SafeSelectorProps = Safe | typeof undefined
export const safeSelector: Selector = createSelector(
@@ -27,6 +30,18 @@ export const safeSelector: Selector
},
)
+export const balanceSelector: Selector = createSelector(
+ balancesSelector,
+ safeAddessSelector,
+ (balances: Map, address: string) => {
+ if (!address) {
+ return '0'
+ }
+
+ return balances.get(address) || '0'
+ },
+)
+
export default createStructuredSelector({
safe: safeSelector,
})
diff --git a/src/routes/safe/store/test/balance.reducer.js b/src/routes/safe/store/test/balance.reducer.js
new file mode 100644
index 00000000..923fc449
--- /dev/null
+++ b/src/routes/safe/store/test/balance.reducer.js
@@ -0,0 +1,54 @@
+// @flow
+import { BALANCE_REDUCER_ID } from '~/routes/safe/store/reducer/balances'
+import fetchBalance from '~/routes/safe/store/actions/fetchBalance'
+import { aNewStore } from '~/store'
+import { getWeb3 } from '~/wallets/getWeb3'
+import { promisify } from '~/utils/promisify'
+import { aDeployedSafe } from './builder/deployedSafe.builder'
+
+const addEtherTo = async (address: string, eth: string) => {
+ const web3 = getWeb3()
+ const accounts = await promisify(cb => web3.eth.getAccounts(cb))
+ const txData = { from: accounts[0], to: address, value: web3.toWei(eth, 'ether') }
+ return promisify(cb => web3.eth.sendTransaction(txData, cb))
+}
+
+const balanceReducerTests = () => {
+ describe('Safe Actions[fetchBalance]', () => {
+ let store
+ beforeEach(async () => {
+ store = aNewStore()
+ })
+
+ it('reducer should return 0 to just deployed safe', async () => {
+ // GIVEN
+ const safeTx = await aDeployedSafe(store)
+ const address = safeTx.contractAddress
+
+ // WHEN
+ await store.dispatch(fetchBalance(address))
+
+ // THEN
+ const balances = store.getState()[BALANCE_REDUCER_ID]
+ expect(balances).not.toBe(undefined)
+ expect(balances.get(address)).toBe('0')
+ })
+
+ it('reducer should return 1.3456 ETH as funds to safe with 1 ETH', async () => {
+ // GIVEN
+ const safeTx = await aDeployedSafe(store)
+ const address = safeTx.contractAddress
+
+ // WHEN
+ await addEtherTo(address, '1.3456')
+ await store.dispatch(fetchBalance(address))
+
+ // THEN
+ const balances = store.getState()[BALANCE_REDUCER_ID]
+ expect(balances).not.toBe(undefined)
+ expect(balances.get(address)).toBe('1.3456')
+ })
+ })
+}
+
+export default balanceReducerTests
diff --git a/src/routes/safe/store/test/balance.selector.js b/src/routes/safe/store/test/balance.selector.js
new file mode 100644
index 00000000..b6b850e4
--- /dev/null
+++ b/src/routes/safe/store/test/balance.selector.js
@@ -0,0 +1,61 @@
+// @flow
+import { type Match } from 'react-router-dom'
+import addBalance from '~/routes/safe/store/actions/addBalance'
+import { aNewStore } from '~/store'
+import { balanceSelector } from '../selectors'
+
+const buildMathPropsFrom = (address): Match => ({
+ params: {
+ address,
+ },
+ isExact: true,
+ path: '',
+ url: '',
+})
+
+const balanceSelectorTests = () => {
+ describe('Safe Selector[balanceSelector]', () => {
+ it('should return 0 when safe address is not found', () => {
+ // GIVEN
+ const safeAddress = 'foo'
+ const match = buildMathPropsFrom(safeAddress)
+ const store = aNewStore()
+
+ // WHEN
+ const balance = balanceSelector(store.getState(), { match })
+
+ // THEN
+ expect(balance).toBe('0')
+ })
+
+ it('should return 0 when safe has no funds', async () => {
+ // GIVEN
+ const safeAddress = 'foo'
+ const match = buildMathPropsFrom(safeAddress)
+ const store = aNewStore()
+
+ // WHEN
+ await store.dispatch(addBalance('bar', '1'))
+ const balance = balanceSelector(store.getState(), { match })
+
+ // THEN
+ expect(balance).toBe('0')
+ })
+
+ it('should return safe funds', async () => {
+ // GIVEN
+ const safeAddress = 'foo'
+ const match = buildMathPropsFrom(safeAddress)
+ const store = aNewStore()
+
+ // WHEN
+ await store.dispatch(addBalance(safeAddress, '1.3456'))
+ const balance = balanceSelector(store.getState(), { match })
+
+ // THEN
+ expect(balance).toBe('1.3456')
+ })
+ })
+}
+
+export default balanceSelectorTests
diff --git a/src/routes/safe/store/test/builder/deployedSafe.builder.js b/src/routes/safe/store/test/builder/deployedSafe.builder.js
new file mode 100644
index 00000000..34bb71b0
--- /dev/null
+++ b/src/routes/safe/store/test/builder/deployedSafe.builder.js
@@ -0,0 +1,72 @@
+// @flow
+import * as React from 'react'
+import { type Store } from 'redux'
+import TestUtils from 'react-dom/test-utils'
+import { Provider } from 'react-redux'
+import { ConnectedRouter } from 'react-router-redux'
+import { DEPLOYED_COMPONENT_ID } from '~/routes/open/components/FormConfirmation'
+import Open from '~/routes/open/container/Open'
+import { history, type GlobalState } from '~/store'
+import { sleep } from '~/utils/timer'
+import { getProviderInfo } from '~/wallets/getWeb3'
+import addProvider from '~/wallets/store/actions/addProvider'
+import { makeProvider } from '~/wallets/store/model/provider'
+
+export const renderSafe = async (localStore: Store) => {
+ const provider = await getProviderInfo()
+ const walletRecord = makeProvider(provider)
+ localStore.dispatch(addProvider(walletRecord))
+
+ return (
+ TestUtils.renderIntoDocument((
+
+
+
+
+
+ ))
+ )
+}
+
+const deploySafe = async (safe: React$Component<{}>) => {
+ const inputs = TestUtils.scryRenderedDOMComponentsWithTag(safe, 'input')
+ const fieldName = inputs[0]
+ const fieldOwners = inputs[1]
+ const fieldConfirmations = inputs[2]
+
+ TestUtils.Simulate.change(fieldOwners, { target: { value: '1' } })
+ const inputsExpanded = TestUtils.scryRenderedDOMComponentsWithTag(safe, 'input')
+ const ownerName = inputsExpanded[2]
+
+ TestUtils.Simulate.change(fieldName, { target: { value: 'Adolfo Safe' } })
+ TestUtils.Simulate.change(fieldConfirmations, { target: { value: '1' } })
+ TestUtils.Simulate.change(ownerName, { target: { value: 'Adolfo Eth Account' } })
+
+ const form = TestUtils.findRenderedDOMComponentWithTag(safe, 'form')
+
+ TestUtils.Simulate.submit(form) // fill the form
+ TestUtils.Simulate.submit(form) // confirming data
+ TestUtils.Simulate.submit(form) // Executing transaction
+
+ // giving some time to the component for updating its state with safe
+ // before destroying its context
+ await sleep(1500)
+
+ // THEN
+ const deployed = TestUtils.findRenderedDOMComponentWithClass(safe, DEPLOYED_COMPONENT_ID)
+ if (!deployed) {
+ throw new Error()
+ }
+
+ const transactionHash = JSON.parse(deployed.getElementsByTagName('pre')[0].innerHTML)
+ delete transactionHash.logsBloom
+
+ return transactionHash
+}
+
+export const aDeployedSafe = async (specificStore: Store) => {
+ const safe: React$Component<{}> = await renderSafe(specificStore)
+ const deployedSafe = deploySafe(safe)
+
+ return deployedSafe
+}
diff --git a/src/routes/safe/store/test/builder/index.builder.js b/src/routes/safe/store/test/builder/safe.builder.js
similarity index 100%
rename from src/routes/safe/store/test/builder/index.builder.js
rename to src/routes/safe/store/test/builder/safe.builder.js
diff --git a/src/routes/safe/store/test/safe.reducer.js b/src/routes/safe/store/test/safe.reducer.js
index 72f58646..c9c241df 100644
--- a/src/routes/safe/store/test/safe.reducer.js
+++ b/src/routes/safe/store/test/safe.reducer.js
@@ -5,7 +5,7 @@ import safeReducer, { calculateInitialState, SAFE_REDUCER_ID } from '~/routes/sa
import addSafe from '~/routes/safe/store/actions/addSafe'
import * as SafeFields from '~/routes/open/components/fields'
import { getAccountsFrom, getNamesFrom } from '~/routes/open/utils/safeDataExtractor'
-import { SafeFactory } from './builder/index.builder'
+import { SafeFactory } from './builder/safe.builder'
const aStore = (initState) => {
const reducers = combineReducers({
diff --git a/src/routes/safe/store/test/safe.selector.js b/src/routes/safe/store/test/safe.selector.js
index 33f3d75b..c8ba8f71 100644
--- a/src/routes/safe/store/test/safe.selector.js
+++ b/src/routes/safe/store/test/safe.selector.js
@@ -3,7 +3,7 @@ import { Map } from 'immutable'
import { type Match } from 'react-router-dom'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import { type Safe } from '~/routes/safe/store/model/safe'
-import { SafeFactory } from '~/routes/safe/store/test/builder/index.builder'
+import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import { safeSelector } from '../selectors'
const buildMathPropsFrom = (address): Match => ({
@@ -19,7 +19,11 @@ const safeSelectorTests = () => {
describe('Safe Selector[safeSelector]', () => {
it('should return empty list when no safes', () => {
// GIVEN
- const reduxStore = { [SAFE_REDUCER_ID]: Map(), providers: undefined }
+ const reduxStore = {
+ [SAFE_REDUCER_ID]: Map(),
+ providers: undefined,
+ balances: undefined,
+ }
const match: Match = buildMathPropsFrom('fooAddress')
// WHEN
@@ -38,7 +42,11 @@ const safeSelectorTests = () => {
const match: Match = buildMathPropsFrom('fooAddress')
const undefMatch: Match = buildMathPropsFrom('inventedAddress')
- const reduxStore = { [SAFE_REDUCER_ID]: map, providers: undefined }
+ const reduxStore = {
+ [SAFE_REDUCER_ID]: map,
+ providers: undefined,
+ balances: undefined,
+ }
// WHEN
const oneOwnerSafe = safeSelector(reduxStore, { match })
diff --git a/src/routes/safe/store/test/safe.spec.js b/src/routes/safe/store/test/safe.spec.js
index 80febf06..ea07c3ee 100644
--- a/src/routes/safe/store/test/safe.spec.js
+++ b/src/routes/safe/store/test/safe.spec.js
@@ -1,11 +1,17 @@
// @flow
+import balanceReducerTests from './balance.reducer'
import safeReducerTests from './safe.reducer'
+import balanceSelectorTests from './balance.selector'
import safeSelectorTests from './safe.selector'
describe('Safe Test suite', () => {
// ACTIONS AND REDUCERS
safeReducerTests()
+ balanceReducerTests()
// SAFE SELECTOR
safeSelectorTests()
+
+ // BALANCE SELECTOR
+ balanceSelectorTests()
})
diff --git a/src/routes/safeList/components/Layout.stories.js b/src/routes/safeList/components/Layout.stories.js
index 74790891..2887270f 100644
--- a/src/routes/safeList/components/Layout.stories.js
+++ b/src/routes/safeList/components/Layout.stories.js
@@ -3,7 +3,7 @@ import { storiesOf } from '@storybook/react'
import { List } from 'immutable'
import * as React from 'react'
import styles from '~/components/layout/PageFrame/index.scss'
-import { SafeFactory } from '~/routes/safe/store/test/builder/index.builder'
+import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import Component from './Layout'
diff --git a/src/routes/safeList/store/test/safe.spec.js b/src/routes/safeList/store/test/safeList.spec.js
similarity index 100%
rename from src/routes/safeList/store/test/safe.spec.js
rename to src/routes/safeList/store/test/safeList.spec.js
diff --git a/src/routes/safeList/store/test/safes.selector.js b/src/routes/safeList/store/test/safes.selector.js
index 4fa5cb4c..808547df 100644
--- a/src/routes/safeList/store/test/safes.selector.js
+++ b/src/routes/safeList/store/test/safes.selector.js
@@ -2,14 +2,18 @@
import { List, Map } from 'immutable'
import { SAFE_REDUCER_ID } from '~/routes/safe/store/reducer/safe'
import { type Safe } from '~/routes/safe/store/model/safe'
-import { SafeFactory } from '~/routes/safe/store/test/builder/index.builder'
+import { SafeFactory } from '~/routes/safe/store/test/builder/safe.builder'
import { safesListSelector } from '../selectors'
const safesListSelectorTests = () => {
describe('Safes Selector[safesSelector]', () => {
it('should return empty list when no safes', () => {
// GIVEN
- const reduxStore = { [SAFE_REDUCER_ID]: Map(), providers: undefined }
+ const reduxStore = {
+ [SAFE_REDUCER_ID]: Map(),
+ providers: undefined,
+ balances: undefined,
+ }
const emptyList = List([])
// WHEN
@@ -25,7 +29,11 @@ const safesListSelectorTests = () => {
map = map.set('fooAddress', SafeFactory.oneOwnerSafe)
map = map.set('barAddress', SafeFactory.twoOwnersSafe)
- const reduxStore = { [SAFE_REDUCER_ID]: map, providers: undefined }
+ const reduxStore = {
+ [SAFE_REDUCER_ID]: map,
+ providers: undefined,
+ balances: undefined,
+ }
// WHEN
const safes = safesListSelector(reduxStore)
diff --git a/src/store/index.js b/src/store/index.js
index 57d1701e..882978f1 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -5,6 +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, calculateInitialState, 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'
export const history = createBrowserHistory()
@@ -18,14 +19,19 @@ const finalCreateStore = composeEnhancers(applyMiddleware(
export type GlobalState = {
providers: ProviderState,
safes: SafeState,
+ balances: BalancesState,
}
const reducers: Reducer = combineReducers({
routing: routerReducer,
[PROVIDER_REDUCER_ID]: provider,
[SAFE_REDUCER_ID]: safe,
+ [BALANCE_REDUCER_ID]: balances,
})
const initialState = { [SAFE_REDUCER_ID]: calculateInitialState() }
export const store: Store = createStore(reducers, initialState, finalCreateStore)
+
+export const aNewStore = (localState?: Object): Store =>
+ createStore(reducers, localState, finalCreateStore)
diff --git a/src/utils/singleton.js b/src/utils/singleton.js
new file mode 100644
index 00000000..5517a770
--- /dev/null
+++ b/src/utils/singleton.js
@@ -0,0 +1,14 @@
+// @flow
+export const ensureOnce = (fn: Function): Function => {
+ let executed = false
+ let response
+
+ return (...args) => {
+ if (executed) { return response }
+
+ executed = true
+ response = fn(args)
+
+ return response
+ }
+}
diff --git a/src/wallets/getWeb3.js b/src/wallets/getWeb3.js
index 66460ebd..aa57987b 100644
--- a/src/wallets/getWeb3.js
+++ b/src/wallets/getWeb3.js
@@ -1,4 +1,5 @@
// @flow
+import { BigNumber } from 'bignumber.js'
import Web3 from 'web3'
import type { ProviderProps } from '~/wallets/store/model/provider'
import { promisify } from '~/utils/promisify'
@@ -42,16 +43,11 @@ export const getProviderInfo: Function = async (): Promise => {
}
}
-export const ensureOnce = (fn: Function): Function => {
- let executed = false
- let response
-
- return (...args) => {
- if (executed) { return response }
-
- executed = true
- response = fn(args)
-
- return response
+export const getBalanceInEtherOf = async (safeAddress: string) => {
+ const funds: BigNumber = await promisify(cb => web3.eth.getBalance(safeAddress, cb))
+ if (!funds) {
+ return '0'
}
+
+ return web3.fromWei(funds.toNumber(), 'ether').toString()
}