diff --git a/package.json b/package.json index 3d5db05..4ababd0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ezerous/drizzle", - "version": "0.1.0", + "version": "0.2.0", "description": "A reactive data-store for web3 and smart contracts.", "license": "MIT", "author": "Ezerous ", diff --git a/src/Drizzle.js b/src/Drizzle.js index 02c50ec..ee40798 100644 --- a/src/Drizzle.js +++ b/src/Drizzle.js @@ -6,7 +6,7 @@ import * as ContractActions from './contracts/constants' import * as DrizzleActions from './drizzleStatus/drizzleActions' // Load as promise so that async Drizzle initialization can still resolve -var isEnvReadyPromise = new Promise((resolve, reject) => { +const isEnvReadyPromise = new Promise((resolve) => { const hasNavigator = typeof navigator !== 'undefined' const hasWindow = typeof window !== 'undefined' const hasDocument = typeof document !== 'undefined' diff --git a/src/accountBalances/accountBalancesMiddleware.js b/src/accountBalances/accountBalancesMiddleware.js index dcf3fc0..d784474 100644 --- a/src/accountBalances/accountBalancesMiddleware.js +++ b/src/accountBalances/accountBalancesMiddleware.js @@ -1,4 +1,4 @@ -import { WEB3_INITIALIZED } from '../web3/constants' +import { WEB3_INITIALIZED } from '../web3/web3Actions' import { accountBalancesFetching } from './accountBalancesActions' import { ACCOUNTS_FETCHED } from '../accounts/accountsActions' diff --git a/src/accounts/accountsMiddleware.js b/src/accounts/accountsMiddleware.js index 73c3151..4c9128f 100644 --- a/src/accounts/accountsMiddleware.js +++ b/src/accounts/accountsMiddleware.js @@ -1,14 +1,14 @@ -import { WEB3_INITIALIZED } from '../web3/constants' +import { WEB3_INITIALIZED } from '../web3/web3Actions' import { accountsFetched, accountsListening } from './accountsActions' -export const accountsMiddleware = () => store => next => action => { +export const accountsMiddleware = web3 => store => next => action => { const { type } = action if (type === WEB3_INITIALIZED) { if(!window.ethereum) console.warn('No Metamask detected, not subscribed to account changes!') else { - const { web3 } = action; + web3 = action.web3; window.ethereum.on('accountsChanged', accounts => { // For some reason accounts here are returned with lowercase letters, so we need to patch them let patchedAccounts = Array.from(accounts); diff --git a/src/drizzleStatus/drizzleStatusSaga.js b/src/drizzleStatus/drizzleStatusSaga.js index db28571..1e37b09 100644 --- a/src/drizzleStatus/drizzleStatusSaga.js +++ b/src/drizzleStatus/drizzleStatusSaga.js @@ -7,7 +7,7 @@ import { getAccountBalances } from '../accountBalances/accountBalancesSaga' import * as DrizzleActions from './drizzleActions' import * as BlocksActions from '../blocks/blockActions' -import { NETWORK_IDS, NETWORK_MISMATCH } from '../web3/constants' +import { NETWORK_IDS, NETWORK_MISMATCH } from '../web3/web3Actions' export function * initializeDrizzle (action) { try { @@ -35,10 +35,10 @@ export function * initializeDrizzle (action) { yield call(getAccountBalances, { web3 }) // Instantiate contracts passed through via options. - for (var i = 0; i < options.contracts.length; i++) { - var contractConfig = options.contracts[i] - var events = [] - var contractName = contractConfig.contractName + for (let i = 0; i < options.contracts.length; i++) { + const contractConfig = options.contracts[i] + let events = [] + const contractName = contractConfig.contractName if (contractName in options.events) { events = options.events[contractName] diff --git a/src/index.js b/src/index.js index 83a3eb3..1f48a64 100644 --- a/src/index.js +++ b/src/index.js @@ -7,53 +7,27 @@ import * as EventActions from './contracts/constants' import * as AccountActions from './accounts/accountsActions' // Reducers -import accountsReducer from './accounts/accountsReducer' -import accountBalancesReducer from './accountBalances/accountBalancesReducer' -import blocksReducer from './blocks/blocksReducer' -import contractsReducer from './contracts/contractsReducer' -import drizzleStatusReducer from './drizzleStatus/drizzleStatusReducer' -import transactionsReducer from './transactions/transactionsReducer' -import transactionStackReducer from './transactions/transactionStackReducer' -import web3Reducer from './web3/web3Reducer' +import drizzleReducers from './reducer' // Middleware import drizzleMiddleware from './drizzle-middleware' import accountsMiddleware from './accounts/accountsMiddleware' import accountBalancesMiddleware from './accountBalances/accountBalancesMiddleware' +import web3Middleware from './web3/web3Middleware' // Sagas -import accountBalancesSaga from './accountBalances/accountBalancesSaga' -import blocksSaga from './blocks/blocksSaga' -import contractsSaga from './contracts/contractsSaga' -import drizzleStatusSaga from './drizzleStatus/drizzleStatusSaga' - -const drizzleReducers = { - accounts: accountsReducer, - accountBalances: accountBalancesReducer, - contracts: contractsReducer, - currentBlock: blocksReducer, - drizzleStatus: drizzleStatusReducer, - transactions: transactionsReducer, - transactionStack: transactionStackReducer, - web3: web3Reducer -} +import drizzleSagas from './rootSaga' const drizzleMiddlewares = [ drizzleMiddleware, accountsMiddleware, - accountBalancesMiddleware -] - -const drizzleSagas = [ - accountBalancesSaga, - blocksSaga, - contractsSaga, - drizzleStatusSaga + accountBalancesMiddleware, + web3Middleware ] const drizzleActions = { - AccountActions, - EventActions + account: AccountActions, + event: EventActions } export { diff --git a/src/rootSaga.js b/src/rootSaga.js index d165edc..e592e9a 100644 --- a/src/rootSaga.js +++ b/src/rootSaga.js @@ -2,10 +2,12 @@ import accountBalancesSaga from './accountBalances/accountBalancesSaga' import blocksSaga from './blocks/blocksSaga' import contractsSaga from './contracts/contractsSaga' import drizzleStatusSaga from './drizzleStatus/drizzleStatusSaga' +import web3Saga from './web3/web3Saga' export default [ accountBalancesSaga, blocksSaga, contractsSaga, - drizzleStatusSaga + drizzleStatusSaga, + web3Saga ] diff --git a/src/web3/constants.js b/src/web3/web3Actions.js similarity index 74% rename from src/web3/constants.js rename to src/web3/web3Actions.js index 2943c92..6b5ead3 100644 --- a/src/web3/constants.js +++ b/src/web3/web3Actions.js @@ -4,6 +4,7 @@ export const WEB3_FAILED = 'WEB3_FAILED' export const WEB3_USER_DENIED = 'WEB3_USER_DENIED' export const NETWORK_ID_FETCHED = 'NETWORK_ID_FETCHED' +export const NETWORK_ID_CHANGED = 'NETWORK_ID_CHANGED' export const NETWORK_ID_FAILED = 'NETWORK_ID_FAILED' export const NETWORK_MISMATCH = 'NETWORK_MISMATCH' @@ -15,3 +16,10 @@ export const NETWORK_IDS = { kovan: 42, ganache: 5777 } + +export function networkIdChanged (web3) { + return { + type: NETWORK_ID_CHANGED, + web3 + } +} diff --git a/src/web3/web3Middleware.js b/src/web3/web3Middleware.js new file mode 100644 index 0000000..02a3aaa --- /dev/null +++ b/src/web3/web3Middleware.js @@ -0,0 +1,21 @@ +import { networkIdChanged, WEB3_INITIALIZED } from './web3Actions' + +export const web3Middleware = web3 => store => next => action => { + const { type } = action + + if (type === WEB3_INITIALIZED) { + if(!window.ethereum) + console.warn('No Metamask detected, not subscribed to network changes!') + else { + web3 = action.web3; + window.ethereum.on('networkChanged', () => { + // We could have listened to 'networkChanged' but it is deprecated (EIP-1193) + store.dispatch(networkIdChanged(web3)); + }); + } + } + return next(action) +} + +const initializedMiddleware = web3Middleware(undefined) +export default initializedMiddleware diff --git a/src/web3/web3Reducer.js b/src/web3/web3Reducer.js index e29677e..b81c50a 100644 --- a/src/web3/web3Reducer.js +++ b/src/web3/web3Reducer.js @@ -1,4 +1,4 @@ -import * as Action from './constants' +import * as Action from './web3Actions' const initialState = { status: '' @@ -33,7 +33,8 @@ const web3Reducer = (state = initialState, action) => { } } - if (action.type === Action.NETWORK_ID_FETCHED) { + if (action.type === Action.NETWORK_ID_FETCHED + || action.type === Action.NETWORK_ID_CHANGED) { return { ...state, networkId: action.networkId diff --git a/src/web3/web3Saga.js b/src/web3/web3Saga.js index cb13747..eeff7b5 100644 --- a/src/web3/web3Saga.js +++ b/src/web3/web3Saga.js @@ -1,12 +1,11 @@ -import { call, put } from 'redux-saga/effects' -import * as Action from './constants' +import { call, put, takeLatest } from 'redux-saga/effects' +import * as Action from './web3Actions' const Web3 = require('web3'); /* * Initialization */ - export function * initializeWeb3 (options) { try { let web3 = {} @@ -35,7 +34,6 @@ export function * initializeWeb3 (options) { } catch (error) { console.error(error) yield put({ type: Action.WEB3_FAILED }) - return } } else if (typeof window.web3 !== 'undefined') { // Checking if Web3 has been injected by the browser (Mist/MetaMask) @@ -71,20 +69,26 @@ export function * initializeWeb3 (options) { } /* - * Network ID + * Fetch Network ID */ - export function * getNetworkId ({ web3 }) { try { - const networkId = yield call(web3.eth.net.getId) + const networkId = yield call(web3.eth.net.getId); - yield put({ type: Action.NETWORK_ID_FETCHED, networkId }) + yield put({ type: Action.NETWORK_ID_FETCHED, networkId }); return networkId } catch (error) { - yield put({ type: Action.NETWORK_ID_FAILED, error }) + yield put({ type: Action.NETWORK_ID_FAILED, error }); - console.error('Error fetching network ID:') - console.error(error) + console.error('Error fetching network ID:'); + console.error(error); } } + +function * web3Saga () { + yield takeLatest(Action.NETWORK_ID_CHANGED, getNetworkId); +} + +export default web3Saga +