diff --git a/src/components/Header/assets/gnosis-safe-icon.svg b/src/components/Header/assets/gnosis-safe-icon.svg
new file mode 100644
index 00000000..7c7d342a
--- /dev/null
+++ b/src/components/Header/assets/gnosis-safe-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/components/Header/assets/metamask.svg b/src/components/Header/assets/metamask-icon.svg
similarity index 100%
rename from src/components/Header/assets/metamask.svg
rename to src/components/Header/assets/metamask-icon.svg
diff --git a/src/components/Header/component/ProviderDetails/UserDetails.jsx b/src/components/Header/component/ProviderDetails/UserDetails.jsx
index e90b3bbc..4304541d 100644
--- a/src/components/Header/component/ProviderDetails/UserDetails.jsx
+++ b/src/components/Header/component/ProviderDetails/UserDetails.jsx
@@ -21,7 +21,8 @@ import { shortVersionOf } from '~/logic/wallets/ethAddresses'
import { getEtherScanLink } from '~/logic/wallets/getWeb3'
import CircleDot from '~/components/Header/component/CircleDot'
-const metamask = require('../../assets/metamask.svg')
+const metamaskIcon = require('../../assets/metamask-icon.svg')
+const safeIcon = require('../../assets/gnosis-safe-icon.svg')
const dot = require('../../assets/dotRinkeby.svg')
type Props = {
@@ -132,7 +133,6 @@ const UserDetails = ({
Status
- {' '}
@@ -144,10 +144,12 @@ const UserDetails = ({
Client
- {' '}
-
+ {provider === 'safe'
+ ?
+ :
+ }
{upperFirst(provider)}
@@ -156,7 +158,6 @@ const UserDetails = ({
Network
- {' '}
diff --git a/src/components/Header/index.jsx b/src/components/Header/index.jsx
index 4ff64c7f..a45b2611 100644
--- a/src/components/Header/index.jsx
+++ b/src/components/Header/index.jsx
@@ -4,6 +4,7 @@ import { connect } from 'react-redux'
import { logComponentStack, type Info } from '~/utils/logBoundaries'
import { SharedSnackbarConsumer, type Variant } from '~/components/SharedSnackBar/Context'
import { WALLET_ERROR_MSG } from '~/logic/wallets/store/actions'
+import { getProviderInfo } from '~/logic/wallets/getWeb3'
import ProviderAccesible from './component/ProviderInfo/ProviderAccesible'
import UserDetails from './component/ProviderDetails/UserDetails'
import ProviderDisconnected from './component/ProviderInfo/ProviderDisconnected'
@@ -30,16 +31,35 @@ class HeaderComponent extends React.PureComponent {
this.onConnect()
}
+ componentDidCatch(error: Error, info: Info) {
+ const { openSnackbar } = this.props
+ this.setState({ hasError: true })
+ openSnackbar(WALLET_ERROR_MSG, 'error')
+
+ logComponentStack(error, info)
+ }
+
onDisconnect = () => {
const { removeProvider, openSnackbar } = this.props
+ clearInterval(this.providerListener)
removeProvider(openSnackbar)
}
- onConnect = () => {
+ onConnect = async () => {
const { fetchProvider, openSnackbar } = this.props
- fetchProvider(openSnackbar)
+ clearInterval(this.providerListener)
+ let currentProvider: ProviderProps = await getProviderInfo()
+ fetchProvider(currentProvider, openSnackbar)
+
+ this.providerListener = setInterval(async () => {
+ const newProvider: ProviderProps = await getProviderInfo()
+ if (JSON.stringify(currentProvider) !== JSON.stringify(newProvider)) {
+ fetchProvider(newProvider, openSnackbar)
+ }
+ currentProvider = newProvider
+ }, 2000)
}
getProviderInfoBased = () => {
@@ -76,14 +96,6 @@ class HeaderComponent extends React.PureComponent {
)
}
- componentDidCatch(error: Error, info: Info) {
- const { openSnackbar } = this.props
- this.setState({ hasError: true })
- openSnackbar(WALLET_ERROR_MSG, 'error')
-
- logComponentStack(error, info)
- }
-
render() {
const info = this.getProviderInfoBased()
const details = this.getProviderDetailsBased()
diff --git a/src/components/layout/Hairline/index.js b/src/components/layout/Hairline/index.js
index b23445d8..223244f0 100644
--- a/src/components/layout/Hairline/index.js
+++ b/src/components/layout/Hairline/index.js
@@ -14,7 +14,7 @@ const calculateStyleFrom = (color?: string, margin?: Size) => ({
type Props = {
margin?: Size,
color?: string,
- style?: Object
+ style?: Object,
}
const Hairline = ({ margin, color, style }: Props) => {
diff --git a/src/logic/contracts/safeContracts.js b/src/logic/contracts/safeContracts.js
index e2108346..cc4cab95 100644
--- a/src/logic/contracts/safeContracts.js
+++ b/src/logic/contracts/safeContracts.js
@@ -75,7 +75,7 @@ export const deploySafeContract = async (safeAccounts: string[], numConfirmation
export const getGnosisSafeInstanceAt = async (safeAddress: string) => {
const web3 = getWeb3()
- const GnosisSafe = getGnosisSafeContract(web3)
+ const GnosisSafe = await getGnosisSafeContract(web3)
const gnosisSafe = await GnosisSafe.at(safeAddress)
return gnosisSafe
diff --git a/src/logic/tokens/store/actions/fetchTokens.js b/src/logic/tokens/store/actions/fetchTokens.js
index 204dc54a..04d8a1c3 100644
--- a/src/logic/tokens/store/actions/fetchTokens.js
+++ b/src/logic/tokens/store/actions/fetchTokens.js
@@ -15,9 +15,9 @@ const createStandardTokenContract = async () => {
const web3 = getWeb3()
const erc20Token = await contract(StandardToken)
erc20Token.setProvider(web3.currentProvider)
-
return erc20Token
}
+
const createHumanFriendlyTokenContract = async () => {
const web3 = getWeb3()
const humanErc20Token = await contract(HumanFriendlyToken)
diff --git a/src/logic/tokens/store/actions/loadActiveTokens.js b/src/logic/tokens/store/actions/loadActiveTokens.js
index 7ca0aa80..e93e35fd 100644
--- a/src/logic/tokens/store/actions/loadActiveTokens.js
+++ b/src/logic/tokens/store/actions/loadActiveTokens.js
@@ -9,7 +9,6 @@ import saveTokens from './saveTokens'
const loadActiveTokens = () => async (dispatch: ReduxDispatch) => {
try {
const tokens: Map = await getActiveTokens()
-
const tokenRecordsList: List = List(
Object.values(tokens).map((token: TokenProps): Token => makeToken(token)),
)
diff --git a/src/logic/wallets/getWeb3.js b/src/logic/wallets/getWeb3.js
index aecfaaa4..390f6b43 100644
--- a/src/logic/wallets/getWeb3.js
+++ b/src/logic/wallets/getWeb3.js
@@ -12,6 +12,7 @@ export const ETHEREUM_NETWORK = {
}
export const WALLET_PROVIDER = {
+ SAFE: 'SAFE',
METAMASK: 'METAMASK',
PARITY: 'PARITY',
REMOTE: 'REMOTE',
@@ -36,12 +37,23 @@ export const openTxInEtherScan = (tx: string, network: string) => `https://${net
export const getEtherScanLink = (address: string, network: string) => `https://${network}.etherscan.io/address/${address}`
let web3
-export const getWeb3 = () => web3 || new Web3(window.web3.currentProvider)
+export const getWeb3 = () => web3 || (window.web3 && new Web3(window.web3.currentProvider)) || (window.ethereum && new Web3(window.ethereum))
-const isMetamask: Function = (web3Provider): boolean => {
- const isMetamaskConstructor = web3Provider.currentProvider.constructor.name === 'MetamaskInpageProvider'
+const getProviderName: Function = (web3Provider): boolean => {
+ let name
- return isMetamaskConstructor || web3Provider.currentProvider.isMetaMask
+ switch (web3Provider.currentProvider.constructor.name) {
+ case 'SafeWeb3Provider':
+ name = WALLET_PROVIDER.SAFE
+ break
+ case 'MetamaskInpageProvider':
+ name = WALLET_PROVIDER.METAMASK
+ break
+ default:
+ name = 'UNKNOWN'
+ }
+
+ return name
}
const getAccountFrom: Function = async (web3Provider): Promise => {
@@ -57,7 +69,14 @@ const getNetworkIdFrom = async (web3Provider) => {
}
export const getProviderInfo: Function = async (): Promise => {
- if (typeof window.web3 === 'undefined') {
+ let web3Provider
+
+ if (window.ethereum) {
+ web3Provider = window.ethereum
+ await web3Provider.enable()
+ } else if (window.web3) {
+ web3Provider = window.web3.currentProvider
+ } else {
return {
name: '',
available: false,
@@ -67,15 +86,9 @@ export const getProviderInfo: Function = async (): Promise => {
}
}
- // Use MetaMask's provider.
- web3 = new Web3(window.web3.currentProvider)
+ web3 = new Web3(web3Provider)
- if (process.env.NODE_ENV !== 'test') {
- // eslint-disable-next-line
- console.log('Injected web3 detected.')
- }
-
- const name = isMetamask(window.web3) ? WALLET_PROVIDER.METAMASK : 'UNKNOWN'
+ const name = getProviderName(web3)
const account = await getAccountFrom(web3)
const network = await getNetworkIdFrom(web3)
diff --git a/src/logic/wallets/store/actions/fetchProvider.js b/src/logic/wallets/store/actions/fetchProvider.js
index 306664b0..c19f52ce 100644
--- a/src/logic/wallets/store/actions/fetchProvider.js
+++ b/src/logic/wallets/store/actions/fetchProvider.js
@@ -1,6 +1,6 @@
// @flow
import type { Dispatch as ReduxDispatch } from 'redux'
-import { getProviderInfo, ETHEREUM_NETWORK_IDS, ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3'
+import { ETHEREUM_NETWORK_IDS, ETHEREUM_NETWORK } from '~/logic/wallets/getWeb3'
import type { ProviderProps } from '~/logic/wallets/store/model/provider'
import { makeProvider } from '~/logic/wallets/store/model/provider'
import addProvider from './addProvider'
@@ -44,10 +44,7 @@ const handleProviderNotification = (openSnackbar: Function, provider: ProviderPr
openSnackbar(msg, variant)
}
-export default (openSnackbar: Function) => async (dispatch: ReduxDispatch<*>) => {
- const provider: ProviderProps = await getProviderInfo()
-
+export default (provider: ProviderProps, openSnackbar: Function) => (dispatch: ReduxDispatch<*>) => {
handleProviderNotification(openSnackbar, provider)
-
processProviderResponse(dispatch, provider)
}
diff --git a/src/logic/wallets/store/test/provider.reducer.js b/src/logic/wallets/store/test/provider.reducer.js
index 5cdb3c30..c2d648c6 100644
--- a/src/logic/wallets/store/test/provider.reducer.js
+++ b/src/logic/wallets/store/test/provider.reducer.js
@@ -20,9 +20,9 @@ const providerReducerTests = () => {
store = createStore(reducers, compose(...enhancers))
})
- it('reducer should return default Provider record when no Metamask is loaded', () => {
+ it('reducer should return default Provider record when no provider is loaded', () => {
// GIVEN
- const emptyResponse: ProviderProps = {
+ const emptyProvider: ProviderProps = {
name: '',
loaded: false,
available: false,
@@ -31,17 +31,17 @@ const providerReducerTests = () => {
}
// WHEN
- processProviderResponse(store.dispatch, emptyResponse)
+ processProviderResponse(store.dispatch, emptyProvider)
const provider = store.getState()[PROVIDER_REDUCER_ID]
// THEN
- expect(makeProvider(emptyResponse)).toEqual(provider)
+ expect(makeProvider(emptyProvider)).toEqual(provider)
})
it('reducer should return avaiable with its default value when is loaded but not available', () => {
// GIVEN
- const metamaskLoaded: ProviderProps = {
- name: 'METAMASK',
+ const providerLoaded: ProviderProps = {
+ name: 'SAFE',
loaded: true,
available: false,
account: '',
@@ -49,17 +49,17 @@ const providerReducerTests = () => {
}
// WHEN
- processProviderResponse(store.dispatch, metamaskLoaded)
+ processProviderResponse(store.dispatch, providerLoaded)
const provider = store.getState()[PROVIDER_REDUCER_ID]
// THEN
- expect(makeProvider(metamaskLoaded)).toEqual(provider)
+ expect(makeProvider(providerLoaded)).toEqual(provider)
})
- it('reducer should return metamask provider when it is loaded and available', () => {
+ it('reducer should return provider when it is loaded and available', () => {
// GIVEN
- const metamask: ProviderProps = {
- name: 'METAMASK',
+ const providerLoaded: ProviderProps = {
+ name: 'SAFE',
loaded: true,
available: true,
account: '',
@@ -67,11 +67,11 @@ const providerReducerTests = () => {
}
// WHEN
- processProviderResponse(store.dispatch, metamask)
+ processProviderResponse(store.dispatch, providerLoaded)
const provider = store.getState()[PROVIDER_REDUCER_ID]
// THEN
- expect(makeProvider(metamask)).toEqual(provider)
+ expect(makeProvider(providerLoaded)).toEqual(provider)
})
})
}
diff --git a/src/routes/safe/store/actions/addSafe.js b/src/routes/safe/store/actions/addSafe.js
index 0753e14d..97f3a312 100644
--- a/src/routes/safe/store/actions/addSafe.js
+++ b/src/routes/safe/store/actions/addSafe.js
@@ -25,13 +25,9 @@ export const addSafe = createAction(
}),
)
-const saveSafe = (
- name: string,
- address: string,
- threshold: number,
- ownersName: string[],
- ownersAddress: string[],
-) => (dispatch: ReduxDispatch) => {
+const saveSafe = (name: string, address: string, threshold: number, ownersName: string[], ownersAddress: string[]) => (
+ dispatch: ReduxDispatch,
+) => {
const owners: List = buildOwnersFrom(ownersName, ownersAddress)
const safe: Safe = SafeRecord({
diff --git a/src/routes/safe/store/actions/fetchTokenBalances.js b/src/routes/safe/store/actions/fetchTokenBalances.js
index a9b3d503..d9dbcd91 100644
--- a/src/routes/safe/store/actions/fetchTokenBalances.js
+++ b/src/routes/safe/store/actions/fetchTokenBalances.js
@@ -13,7 +13,6 @@ export const calculateBalanceOf = async (tokenAddress: string, safeAddress: stri
if (tokenAddress === ETH_ADDRESS) {
return '0'
}
-
const erc20Token = await getStandardTokenContract()
let balance = 0
@@ -33,15 +32,16 @@ const fetchTokenBalances = (safeAddress: string, tokens: List) => async (
if (!safeAddress || !tokens || !tokens.size) {
return
}
-
try {
const withBalances = await Promise.all(
- tokens.map(async token => TokenBalanceRecord({
- address: token.address,
- balance: await calculateBalanceOf(token.address, safeAddress, token.decimals),
- })),
+ tokens.map(async (token) => {
+ const balance = await calculateBalanceOf(token.address, safeAddress, token.decimals)
+ return TokenBalanceRecord({
+ address: token.address,
+ balance,
+ })
+ }),
)
-
dispatch(updateSafe({ address: safeAddress, balances: List(withBalances) }))
} catch (err) {
// eslint-disable-next-line
diff --git a/src/routes/welcome/components/Layout.stories.js b/src/routes/welcome/components/Layout.stories.js
index fc696c66..d5b5c62c 100644
--- a/src/routes/welcome/components/Layout.stories.js
+++ b/src/routes/welcome/components/Layout.stories.js
@@ -9,15 +9,19 @@ const FrameDecorator = story => {story()}
storiesOf('Routes /welcome', module)
.addDecorator(FrameDecorator)
+ .add('Welcome with Gnosis Safe connected', () => {
+ const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], 'SAFE')
+ return {}} />
+ })
.add('Welcome with Metamask connected', () => {
- const provider = select('Status by Provider', ['', 'UNKNOWN', 'METAMASK', 'PARITY'], 'METAMASK')
+ const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], 'METAMASK')
return {}} />
})
.add('Welcome with unknown wallet', () => {
- const provider = select('Status by Provider', ['', 'UNKNOWN', 'METAMASK', 'PARITY'], 'UNKNOWN')
+ const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], 'UNKNOWN')
return {}} />
})
.add('Welcome without wallet connected', () => {
- const provider = select('Status by Provider', ['', 'UNKNOWN', 'METAMASK', 'PARITY'], '')
+ const provider = select('Status by Provider', ['', 'UNKNOWN', 'SAFE', 'METAMASK', 'PARITY'], '')
return {}} />
})
diff --git a/src/test/safe.dom.load.test.js b/src/test/safe.dom.load.test.js
index d909127b..7b07b7ed 100644
--- a/src/test/safe.dom.load.test.js
+++ b/src/test/safe.dom.load.test.js
@@ -30,7 +30,6 @@ afterAll(() => {
console.error = originalError
})
-
const renderLoadSafe = async (localStore: Store) => {
const provider = await getProviderInfo()
const walletRecord = makeProvider(provider)