immortaldb wip

This commit is contained in:
Mikhail Mikheev 2019-03-26 19:18:36 +04:00
parent 0e97f41c54
commit 7e150a2ff3
13 changed files with 80 additions and 70 deletions

36
package-lock.json generated
View File

@ -3432,6 +3432,15 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
},
"axios": {
"version": "0.18.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
"requires": {
"follow-redirects": "^1.3.0",
"is-buffer": "^1.1.5"
}
},
"axobject-query": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
@ -10206,7 +10215,6 @@
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
"integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
"dev": true,
"requires": {
"debug": "^3.2.6"
},
@ -10215,7 +10223,6 @@
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "^2.1.1"
}
@ -10223,8 +10230,7 @@
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"dev": true
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
@ -18270,6 +18276,11 @@
"postcss": "^7.0.14"
}
},
"idb-keyval": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-3.1.0.tgz",
"integrity": "sha512-iFwFN5n00KNNnVxlOOK280SJJfXWY7pbMUOQXdIXehvvc/mGCV/6T2Ae+Pk2KwAkkATDTwfMavOiDH5lrJKWXQ=="
},
"idna-uts46-hx": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz",
@ -18308,6 +18319,15 @@
"integrity": "sha512-3fmKM6ovaqDt0CdC9daXpNi5x/YCYS3i4cwLdTVkhJdk5jrDXoPs7lCm3IqM3yhfSnz4tjjxbRG2CziQ7m8ztg==",
"dev": true
},
"immortal-db": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/immortal-db/-/immortal-db-1.0.2.tgz",
"integrity": "sha512-7EaVr6vUaaqsl9Jnp+CY4FzA1jIQD+o1tFEY2+O4ibYgmVB+FEWDoyUNN/naq9ZfiYKw4+uly1fpxk0xyE358w==",
"requires": {
"idb-keyval": "^3.0.5",
"js-cookie": "^2.2.0"
}
},
"immutable": {
"version": "4.0.0-rc.12",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz",
@ -18600,8 +18620,7 @@
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"dev": true
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"is-callable": {
"version": "1.1.4",
@ -19532,6 +19551,11 @@
"nopt": "~4.0.1"
}
},
"js-cookie": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.0.tgz",
"integrity": "sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s="
},
"js-levenshtein": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",

View File

@ -67,10 +67,12 @@
"@gnosis.pm/util-contracts": "^2.0.0",
"@material-ui/core": "^3.0.1",
"@material-ui/icons": "^3.0.1",
"axios": "^0.18.0",
"bignumber.js": "^8.1.1",
"connected-react-router": "^6.3.1",
"final-form": "^4.2.1",
"history": "^4.7.2",
"immortal-db": "^1.0.2",
"immutable": "^4.0.0-rc.9",
"material-ui-search-bar": "^1.0.0-beta.13",
"optimize-css-assets-webpack-plugin": "^5.0.1",

View File

@ -1,11 +1,7 @@
// @flow
import { createAction } from 'redux-actions'
import { type Token } from '~/logic/tokens/store/model/token'
import {
setActiveTokenAddresses,
getActiveTokenAddresses,
setToken,
} from '~/logic/tokens/utils/activeTokensStorage'
import { setActiveTokenAddresses, getActiveTokenAddresses, setToken } from '~/logic/tokens/utils/tokensStorage'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/index'
@ -24,14 +20,13 @@ const addToken = createAction(
}),
)
const saveToken = (safeAddress: string, token: Token) => (dispatch: ReduxDispatch<GlobalState>) => {
const saveToken = (safeAddress: string, token: Token) => async (dispatch: ReduxDispatch<GlobalState>) => {
dispatch(addToken(safeAddress, token))
const tokenAddress = token.get('address')
const activeTokens = getActiveTokenAddresses(safeAddress)
setActiveTokenAddresses(safeAddress, activeTokens.push(tokenAddress))
const activeTokens = await getActiveTokenAddresses(safeAddress)
await setActiveTokenAddresses(safeAddress, activeTokens.push(tokenAddress))
setToken(safeAddress, token)
}
export default saveToken

View File

@ -5,7 +5,7 @@ import type { Dispatch as ReduxDispatch } from 'redux'
import { type Token } from '~/logic/tokens/store/model/token'
import { ensureOnce } from '~/utils/singleton'
import { type GlobalState } from '~/store/index'
import { setActiveTokenAddresses } from '~/logic/tokens/utils/activeTokensStorage'
import { setActiveTokenAddresses } from '~/logic/tokens/utils/tokensStorage'
import { calculateActiveErc20TokensFrom } from '~/logic/tokens/utils/tokenHelpers'
export const ADD_TOKENS = 'ADD_TOKENS'

View File

@ -3,7 +3,7 @@ import { createAction } from 'redux-actions'
import { type Token } from '~/logic/tokens/store/model/token'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/index'
import { removeFromActiveTokens } from '~/logic/tokens/utils/activeTokensStorage'
import { removeFromActiveTokens } from '~/logic/tokens/utils/tokensStorage'
export const DISABLE_TOKEN = 'DISABLE_TOKEN'

View File

@ -3,7 +3,7 @@ import { createAction } from 'redux-actions'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/index'
import { type Token } from '~/logic/tokens/store/model/token'
import { setActiveTokenAddresses, getActiveTokenAddresses } from '~/logic/tokens/utils/activeTokensStorage'
import { setActiveTokenAddresses, getActiveTokenAddresses } from '~/logic/tokens/utils/tokensStorage'
export const ENABLE_TOKEN = 'ENABLE_TOKEN'

View File

@ -1,6 +1,7 @@
// @flow
import { List, Map } 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'
@ -9,9 +10,8 @@ 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 { ensureOnce } from '~/utils/singleton'
import { getActiveTokenAddresses, getTokens } from '~/logic/tokens/utils/activeTokensStorage'
import { getActiveTokenAddresses, getTokens } from '~/logic/tokens/utils/tokensStorage'
import { getSafeEthToken } from '~/logic/tokens/utils/tokenHelpers'
import { enhancedFetch } from '~/utils/fetch'
import addTokens from './addTokens'
import { getRelayUrl } from '~/config/index'
@ -52,14 +52,16 @@ export const fetchTokensData = async () => {
const apiUrl = getRelayUrl()
const url = `${apiUrl}/tokens`
const errMsg = 'Error querying safe balances'
return enhancedFetch(url, errMsg)
return axios.get(url, errMsg)
}
export const fetchTokens = (safeAddress: string) => async (dispatch: ReduxDispatch<GlobalState>) => {
const tokens: List<string> = getActiveTokenAddresses(safeAddress)
const tokens: List<string> = await getActiveTokenAddresses(safeAddress)
const ethBalance = await getSafeEthToken(safeAddress)
const customTokens = getTokens(safeAddress)
const { results } = await fetchTokensData()
const customTokens = await getTokens(safeAddress)
const {
data: { results },
} = await fetchTokensData()
try {
const balancesRecords = await Promise.all(

View File

@ -1,7 +1,7 @@
// @flow
import { createAction } from 'redux-actions'
import { type Token } from '~/logic/tokens/store/model/token'
import { removeTokenFromStorage, removeFromActiveTokens } from '~/logic/tokens/utils/activeTokensStorage'
import { removeTokenFromStorage, removeFromActiveTokens } from '~/logic/tokens/utils/tokensStorage'
import { type GlobalState } from '~/store/index'
import type { Dispatch as ReduxDispatch } from 'redux'

View File

@ -1,6 +1,6 @@
// @flow
import { List } from 'immutable'
import { load } from '~/utils/localStorage'
import { ImmortalDB } from 'immortal-db'
import { type Token, type TokenProps } from '~/logic/tokens/store/model/token'
export const ACTIVE_TOKENS_KEY = 'ACTIVE_TOKENS'
@ -9,65 +9,60 @@ export const TOKENS_KEY = 'TOKENS'
const getActiveTokensKey = (safeAddress: string) => `${ACTIVE_TOKENS_KEY}-${safeAddress}`
const getTokensKey = (safeAddress: string) => `${TOKENS_KEY}-${safeAddress}`
export const setActiveTokenAddresses = (safeAddress: string, tokens: List<string>) => {
export const setActiveTokenAddresses = async (safeAddress: string, tokens: List<string>) => {
try {
const serializedState = JSON.stringify(tokens)
const key = getActiveTokensKey(safeAddress)
localStorage.setItem(key, serializedState)
await ImmortalDB.set(key, serializedState)
} catch (err) {
// eslint-disable-next-line
console.log('Error storing tokens in localstorage')
}
}
export const getActiveTokenAddresses = (safeAddress: string): List<string> => {
export const getActiveTokenAddresses = async (safeAddress: string): Promise<List<string>> => {
const key = getActiveTokensKey(safeAddress)
const data = load(key)
const data = await ImmortalDB.get(key)
return data ? List(data) : List()
}
export const storedTokensBefore = (safeAddress: string) => {
const key = getActiveTokensKey(safeAddress)
return localStorage.getItem(key) === null
}
export const getTokens = (safeAddress: string): List<TokenProps> => {
export const getTokens = async (safeAddress: string): Promise<List<TokenProps>> => {
const key = getTokensKey(safeAddress)
const data = load(key)
const data = await ImmortalDB.get(key)
return data ? List(data) : List()
}
export const setToken = (safeAddress: string, token: Token) => {
const data: List<TokenProps> = getTokens(safeAddress)
export const setToken = async (safeAddress: string, token: Token) => {
const data: List<TokenProps> = await getTokens(safeAddress)
try {
const serializedState = JSON.stringify(data.push(token))
const key = getTokensKey(safeAddress)
localStorage.setItem(key, serializedState)
ImmortalDB.set(key, serializedState)
} catch (err) {
// eslint-disable-next-line
console.log('Error adding token in localstorage')
}
}
export const removeTokenFromStorage = (safeAddress: string, token: Token) => {
const data: List<TokenProps> = getTokens(safeAddress)
export const removeTokenFromStorage = async (safeAddress: string, token: Token) => {
const data: List<TokenProps> = await getTokens(safeAddress)
try {
const index = data.indexOf(token)
const serializedState = JSON.stringify(data.remove(index))
const key = getTokensKey(safeAddress)
localStorage.setItem(key, serializedState)
await ImmortalDB.set(key, serializedState)
} catch (err) {
// eslint-disable-next-line
console.log('Error removing token in localstorage')
}
}
export const removeFromActiveTokens = (safeAddress: string, tokenAddress: string) => {
const activeTokens = getActiveTokenAddresses(safeAddress)
export const removeFromActiveTokens = async (safeAddress: string, tokenAddress: string) => {
const activeTokens = await getActiveTokenAddresses(safeAddress)
const index = activeTokens.indexOf(tokenAddress)
setActiveTokenAddresses(safeAddress, activeTokens.delete(index))
}

View File

@ -1,7 +1,7 @@
// @flow
import { BigNumber } from 'bignumber.js'
import axios from 'axios'
import { getWeb3 } from '~/logic/wallets/getWeb3'
import { enhancedFetch } from '~/utils/fetch'
// const MAINNET_NETWORK = 1
export const EMPTY_DATA = '0x'
@ -44,9 +44,9 @@ export const calculateGasPrice = async () => {
const url = 'https://ethgasstation.info/json/ethgasAPI.json'
const errMsg = 'Error querying gas station'
const json = await enhancedFetch(url, errMsg)
const { data } = await axios.get(url, errMsg)
return new BigNumber(json.average).multipliedBy(1e8).toString()
return new BigNumber(data.average).multipliedBy(1e8).toString()
}
export const calculateGasOf = async (data: Object, from: string, to: string) => {

View File

@ -1,5 +1,6 @@
// @flow
import { List, Map } from 'immutable'
import axios from 'axios'
import type { Dispatch as ReduxDispatch } from 'redux'
import { type GlobalState } from '~/store/index'
import { makeOwner } from '~/routes/safe/store/model/owner'
@ -7,7 +8,6 @@ import { makeTransaction, type Transaction } from '~/routes/safe/store/model/tra
import { makeConfirmation } from '~/routes/safe/store/model/confirmation'
import { loadSafeSubjects } from '~/utils/localStorage/transactions'
import { buildTxServiceUrlFrom, type TxServiceType } from '~/logic/safe/safeTxHistory'
import { enhancedFetch } from '~/utils/fetch'
import { getOwners } from '~/utils/localStorage'
import { EMPTY_DATA } from '~/logic/wallets/ethTransactions'
import addTransactions from './addTransactions'
@ -34,15 +34,17 @@ type TxServiceModel = {
const buildTransactionFrom = (safeAddress: string, tx: TxServiceModel, safeSubjects: Map<string, string>) => {
const name = safeSubjects.get(String(tx.nonce)) || 'Unknown'
const storedOwners = getOwners(safeAddress)
const confirmations = List(tx.confirmations.map((conf: ConfirmationServiceModel) => {
const ownerName = storedOwners.get(conf.owner.toLowerCase()) || 'UNKNOWN'
const confirmations = List(
tx.confirmations.map((conf: ConfirmationServiceModel) => {
const ownerName = storedOwners.get(conf.owner.toLowerCase()) || 'UNKNOWN'
return makeConfirmation({
owner: makeOwner({ address: conf.owner, name: ownerName }),
type: ((conf.type.toLowerCase(): any): TxServiceType),
hash: conf.transactionHash,
})
}))
return makeConfirmation({
owner: makeOwner({ address: conf.owner, name: ownerName }),
type: ((conf.type.toLowerCase(): any): TxServiceType),
hash: conf.transactionHash,
})
}),
)
return makeTransaction({
name,
@ -57,8 +59,8 @@ const buildTransactionFrom = (safeAddress: string, tx: TxServiceModel, safeSubje
export const loadSafeTransactions = async (safeAddress: string) => {
const url = buildTxServiceUrlFrom(safeAddress)
const response = await enhancedFetch(url, 'Error fetching txs information')
const transactions: TxServiceModel[] = response.results
const response = await axios.get(url)
const transactions: TxServiceModel[] = response.data.results
const safeSubjects = loadSafeSubjects(safeAddress)
const txsRecord = transactions.map((tx: TxServiceModel) => buildTransactionFrom(safeAddress, tx, safeSubjects))

View File

@ -11,7 +11,7 @@ import { travelToTokens } from '~/test/builder/safe.dom.utils'
import { sleep } from '~/utils/timer'
import { buildMathPropsFrom } from '~/test/utils/buildReactRouterProps'
import { tokenListSelector, activeTokensSelector } from '~/logic/tokens/store/selectors'
import { getActiveTokenAddresses } from '~/logic/tokens/utils/activeTokensStorage'
import { getActiveTokenAddresses } from '~/logic/tokens/utils/tokensStorage'
import { enableFirstToken, testToken } from '~/test/builder/tokens.dom.utils'
import * as fetchTokensModule from '~/logic/tokens/store/actions/fetchTokens'
import * as enhancedFetchModule from '~/utils/fetch'

View File

@ -1,10 +0,0 @@
// @flow
export const promisify = (inner: Function): Promise<any> =>
new Promise((resolve, reject) =>
inner((err, res) => {
if (err) {
reject(err)
} else {
resolve(res)
}
}))