Skip to content
This repository has been archived by the owner on Nov 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #103 from gnosis/99-app-state
Browse files Browse the repository at this point in the history
#99 Refactor redux store
  • Loading branch information
mmv08 authored Apr 22, 2019
2 parents 5d05861 + 24b51ba commit a689c3b
Show file tree
Hide file tree
Showing 78 changed files with 1,411 additions and 1,161 deletions.
32 changes: 16 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-final-form": "^4.1.0",
"react-hot-loader": "^4.8.2",
"react-hot-loader": "4.8.4",
"react-infinite-scroll-component": "^4.5.2",
"react-redux": "^6.0.1",
"react-redux": "7.0.2",
"react-router-dom": "^4.3.1",
"recompose": "^0.30.0",
"redux": "^4.0.1",
Expand Down Expand Up @@ -117,11 +117,11 @@
"@babel/preset-flow": "^7.0.0-beta.40",
"@babel/preset-react": "^7.0.0-beta.40",
"@sambego/storybook-state": "^1.0.7",
"@storybook/addon-actions": "^5.0.6",
"@storybook/addon-knobs": "^5.0.6",
"@storybook/addon-links": "^5.0.6",
"@storybook/react": "^5.0.6",
"autoprefixer": "^9.4.10",
"@storybook/addon-actions": "5.0.9",
"@storybook/addon-knobs": "5.0.9",
"@storybook/addon-links": "5.0.9",
"@storybook/react": "5.0.9",
"autoprefixer": "9.5.1",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
"babel-jest": "^24.1.0",
Expand All @@ -134,38 +134,38 @@
"detect-port": "^1.2.2",
"eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-plugin-flowtype": "^3.4.2",
"eslint-plugin-import": "^2.9.0",
"eslint-plugin-flowtype": "3.6.1",
"eslint-plugin-import": "2.17.2",
"eslint-plugin-jest": "^22.3.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.7.0",
"ethereumjs-abi": "^0.6.7",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^3.0.1",
"flow-bin": "0.96.0",
"flow-bin": "0.97.0",
"fs-extra": "^7.0.1",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.0.4",
"jest": "^24.1.0",
"json-loader": "^0.5.7",
"mini-css-extract-plugin": "^0.5.0",
"mini-css-extract-plugin": "0.6.0",
"postcss-loader": "^3.0.0",
"postcss-mixins": "^6.2.0",
"postcss-simple-vars": "^5.0.2",
"pre-commit": "^1.2.2",
"prettier-eslint-cli": "^4.7.1",
"run-with-testrpc": "^0.3.0",
"run-with-testrpc": "0.3.1",
"storybook-host": "^5.0.3",
"storybook-router": "^0.3.3",
"style-loader": "^0.23.1",
"truffle": "^5.0.10",
"truffle": "5.0.12",
"truffle-contract": "^4.0.11",
"truffle-solidity-loader": "^0.1.10",
"truffle-solidity-loader": "0.1.12",
"uglifyjs-webpack-plugin": "^2.1.2",
"webpack": "^4.1.1",
"webpack-bundle-analyzer": "^3.1.0",
"webpack-bundle-analyzer": "3.3.2",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.1.0",
"webpack-dev-server": "3.3.1",
"webpack-manifest-plugin": "^2.0.0-rc.2"
}
}
14 changes: 8 additions & 6 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ These instructions will get you a copy of the project up and running on your loc
What things you need to install the software and how to install them

```
npm install truffle // recommended usage of -g flag
npm install ganache-cli // recommended usage of -g flag
npm install flow-type // recommended usage of -g flag
yarn add truffle // recommended usage of -g flag
yarn add ganache-cli // recommended usage of -g flag
yarn add flow-type // recommended usage of -g flag
git clone https://github.com/gnosis/safe-contracts.git
```

We use [yarn](https://yarnpkg.com) in our infrastacture, so we decided to go with yarn in the README

### Installing

A step by step series of examples that tell you have to get a development env running
Expand All @@ -29,14 +31,14 @@ ganache-cli -b 3
Start the project in the other one
```
cd safe-contracts && truffle compile && truffle migrate && cd ..
npm install
npm start
yarn install
yarn start
```

## Running the tests

```
npm test
yarn test
```


Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import ReactDOM from 'react-dom'
import Root from '~/components/Root'
import { store } from '~/store'
import loadSafesFromStorage from '~/routes/safe/store/actions/loadSafesFromStorage'
import loadActiveTokens from '~/logic/tokens/store/actions/loadActiveTokens'

store.dispatch(loadActiveTokens())
store.dispatch(loadSafesFromStorage())

ReactDOM.render(<Root />, document.getElementById('root'))
4 changes: 2 additions & 2 deletions src/logic/safe/safeFrontendOperations.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// @flow
import { List } from 'immutable'
import { type Transaction } from '~/routes/safe/store/model/transaction'
import { type Transaction } from '~/routes/safe/store/models/transaction'
import { executeTransaction, approveTransaction } from '~/logic/safe/safeBlockchainOperations'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type Safe } from '~/routes/safe/store/model/safe'
import { type Safe } from '~/routes/safe/store/models/safe'
import { getGnosisSafeContract } from '~/logic/contracts/safeContracts'
import { storeSubject } from '~/utils/storage/transactions'

Expand Down
2 changes: 1 addition & 1 deletion src/logic/safe/utils/safeStorage.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @flow
import { type Owner } from '~/routes/safe/store/model/owner'
import { type Owner } from '~/routes/safe/store/models/owner'
import { List, Map } from 'immutable'
import { loadFromStorage, saveToStorage } from '~/utils/storage'

Expand Down
11 changes: 5 additions & 6 deletions src/logic/tokens/store/actions/addToken.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// @flow
import { createAction } from 'redux-actions'
import { type Token } from '~/logic/tokens/store/model/token'
import { setActiveTokens, getActiveTokens, setToken } from '~/logic/tokens/utils/tokensStorage'
import { saveActiveTokens, getActiveTokens, setToken } from '~/logic/tokens/utils/tokensStorage'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/index'
import { type GlobalState } from '~/store/'

export const ADD_TOKEN = 'ADD_TOKEN'

Expand All @@ -14,17 +14,16 @@ type AddTokenProps = {

export const addToken = createAction<string, *, *>(
ADD_TOKEN,
(safeAddress: string, token: Token): AddTokenProps => ({
safeAddress,
(token: Token): AddTokenProps => ({
token,
}),
)

const saveToken = (safeAddress: string, token: Token) => async (dispatch: ReduxDispatch<GlobalState>) => {
dispatch(addToken(safeAddress, token))
dispatch(addToken(token))

const activeTokens = await getActiveTokens(safeAddress)
await setActiveTokens(safeAddress, activeTokens.push(token.toJS()))
await saveActiveTokens(safeAddress, activeTokens.push(token.toJS()))
setToken(safeAddress, token)
}

Expand Down
21 changes: 0 additions & 21 deletions src/logic/tokens/store/actions/disableToken.js

This file was deleted.

22 changes: 0 additions & 22 deletions src/logic/tokens/store/actions/enableToken.js

This file was deleted.

65 changes: 12 additions & 53 deletions src/logic/tokens/store/actions/fetchTokens.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
// @flow
import { List, Map } from 'immutable'
import { List } from 'immutable'
import contract from 'truffle-contract'
import axios from 'axios'
import { BigNumber } from 'bignumber.js'
import type { Dispatch as ReduxDispatch } from 'redux'
import StandardToken from '@gnosis.pm/util-contracts/build/contracts/GnosisStandardToken.json'
import HumanFriendlyToken from '@gnosis.pm/util-contracts/build/contracts/HumanFriendlyToken.json'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { type GlobalState } from '~/store/index'
import { makeToken, type Token, type TokenProps } from '~/logic/tokens/store/model/token'
import { makeToken, type TokenProps } from '~/logic/tokens/store/model/token'
import { ensureOnce } from '~/utils/singleton'
import { getActiveTokens, getTokens } from '~/logic/tokens/utils/tokensStorage'
import { getSafeEthToken } from '~/logic/tokens/utils/tokenHelpers'
import saveTokens from './saveTokens'
import { getRelayUrl } from '~/config/index'

Expand All @@ -34,66 +31,28 @@ export const getHumanFriendlyToken = ensureOnce(createHumanFriendlyTokenContract

export const getStandardTokenContract = ensureOnce(createStandardTokenContract)

export const calculateBalanceOf = async (tokenAddress: string, address: string, decimals: number) => {
const erc20Token = await getStandardTokenContract()
let balance = 0

try {
const token = await erc20Token.at(tokenAddress)
balance = await token.balanceOf(address)
} catch (err) {
console.error('Failed to fetch token balances: ', err)
}

return new BigNumber(balance).div(10 ** decimals).toString()
}

export const fetchTokensData = async () => {
const fetchTokenList = async () => {
const apiUrl = getRelayUrl()
const url = `${apiUrl}/tokens`
const errMsg = 'Error querying safe balances'
return axios.get(url, errMsg)
}

export const fetchTokens = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
const tokens: List<TokenProps> = await getActiveTokens(safeAddress)
const ethBalance = await getSafeEthToken(safeAddress)
const customTokens = await getTokens(safeAddress)
const {
data: { results },
} = await fetchTokensData()

export const fetchTokens = () => async (dispatch: ReduxDispatch<GlobalState>) => {
try {
const balancesRecords = await Promise.all(
results.map(async (item: TokenProps) => {
const status = tokens.findIndex(activeToken => activeToken.name === item.name) !== -1
const funds = status ? await calculateBalanceOf(item.address, safeAddress, item.decimals) : '0'

return makeToken({ ...item, status, funds })
}),
)

const customTokenRecords = await Promise.all(
customTokens.map(async (item: TokenProps) => {
const status = tokens.findIndex(activeToken => activeToken.name === item.name) !== -1
const funds = status ? await calculateBalanceOf(item.address, safeAddress, item.decimals) : '0'
const {
data: { results: tokenList },
} = await fetchTokenList()

return makeToken({ ...item, status, funds })
}),
)
const tokens = List(tokenList.map((token: TokenProps) => makeToken(token)))

const balances: Map<string, Token> = Map().withMutations((map) => {
balancesRecords.forEach(record => map.set(record.address, record))
customTokenRecords.forEach(record => map.set(record.address, record))

map.set(ethBalance.address, ethBalance)
})

return dispatch(saveTokens(safeAddress, balances))
dispatch(saveTokens(tokens))
} catch (err) {
// eslint-disable-next-line
console.log('Error fetching tokens... ' + err)
console.log('Error fetching token list ' + err)

return Promise.resolve()
}
}

export default fetchTokens
24 changes: 24 additions & 0 deletions src/logic/tokens/store/actions/loadActiveTokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// @flow
import type { Dispatch as ReduxDispatch } from 'redux'
import { Map, List } from 'immutable'
import { type TokenProps, type Token, makeToken } from '~/logic/tokens/store/model/token'
import { type GlobalState } from '~/store/index'
import { getActiveTokens } from '~/logic/tokens/utils/tokensStorage'
import saveTokens from './saveTokens'

const loadActiveTokens = () => async (dispatch: ReduxDispatch<GlobalState>) => {
try {
const tokens: Map<string, TokenProps> = await getActiveTokens()

const tokenRecordsList: List<Token> = List(
Object.values(tokens).map(token => makeToken(token)),
)

dispatch(saveTokens(tokenRecordsList))
} catch (err) {
// eslint-disable-next-line
console.error('Error while loading active tokens from storage:', err)
}
}

export default loadActiveTokens
26 changes: 4 additions & 22 deletions src/logic/tokens/store/actions/saveTokens.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,19 @@
// @flow
import { Map, List } from 'immutable'
import { Map } from 'immutable'
import { createAction } from 'redux-actions'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type Token } from '~/logic/tokens/store/model/token'
import { ensureOnceAsync } from '~/utils/singleton'
import { type GlobalState } from '~/store/index'
import { setActiveTokens } from '~/logic/tokens/utils/tokensStorage'
import { calculateActiveErc20TokensFrom } from '~/logic/tokens/utils/tokenHelpers'

export const ADD_TOKENS = 'ADD_TOKENS'

const setTokensOnce = ensureOnceAsync(setActiveTokens)

type TokenProps = {
safeAddress: string,
tokens: Map<string, Token>,
}

export const addTokens = createAction<string, *, *>(
const addTokens = createAction<string, *, *>(
ADD_TOKENS,
(safeAddress: string, tokens: Map<string, Token>): TokenProps => ({
safeAddress,
(tokens: Map<string, Token>): TokenProps => ({
tokens,
}),
)

const saveTokens = (safeAddress: string, tokens: Map<string, Token>) => async (
dispatch: ReduxDispatch<GlobalState>,
) => {
dispatch(addTokens(safeAddress, tokens))

const activeAddresses: List<Token> = calculateActiveErc20TokensFrom(tokens.toList())
await setTokensOnce(safeAddress, activeAddresses)
}

export default saveTokens
export default addTokens
Loading

0 comments on commit a689c3b

Please sign in to comment.