Browse Source

Listen to network changes

develop
Ezerous 4 years ago
parent
commit
a4bf2c5994
  1. 2
      package.json
  2. 2
      src/Drizzle.js
  3. 2
      src/accountBalances/accountBalancesMiddleware.js
  4. 6
      src/accounts/accountsMiddleware.js
  5. 10
      src/drizzleStatus/drizzleStatusSaga.js
  6. 40
      src/index.js
  7. 4
      src/rootSaga.js
  8. 8
      src/web3/web3Actions.js
  9. 21
      src/web3/web3Middleware.js
  10. 5
      src/web3/web3Reducer.js
  11. 26
      src/web3/web3Saga.js

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "@ezerous/drizzle", "name": "@ezerous/drizzle",
"version": "0.1.0", "version": "0.2.0",
"description": "A reactive data-store for web3 and smart contracts.", "description": "A reactive data-store for web3 and smart contracts.",
"license": "MIT", "license": "MIT",
"author": "Ezerous <ezerous@gmail.com>", "author": "Ezerous <ezerous@gmail.com>",

2
src/Drizzle.js

@ -6,7 +6,7 @@ import * as ContractActions from './contracts/constants'
import * as DrizzleActions from './drizzleStatus/drizzleActions' import * as DrizzleActions from './drizzleStatus/drizzleActions'
// Load as promise so that async Drizzle initialization can still resolve // 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 hasNavigator = typeof navigator !== 'undefined'
const hasWindow = typeof window !== 'undefined' const hasWindow = typeof window !== 'undefined'
const hasDocument = typeof document !== 'undefined' const hasDocument = typeof document !== 'undefined'

2
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 { accountBalancesFetching } from './accountBalancesActions'
import { ACCOUNTS_FETCHED } from '../accounts/accountsActions' import { ACCOUNTS_FETCHED } from '../accounts/accountsActions'

6
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' import { accountsFetched, accountsListening } from './accountsActions'
export const accountsMiddleware = () => store => next => action => { export const accountsMiddleware = web3 => store => next => action => {
const { type } = action const { type } = action
if (type === WEB3_INITIALIZED) { if (type === WEB3_INITIALIZED) {
if(!window.ethereum) if(!window.ethereum)
console.warn('No Metamask detected, not subscribed to account changes!') console.warn('No Metamask detected, not subscribed to account changes!')
else { else {
const { web3 } = action; web3 = action.web3;
window.ethereum.on('accountsChanged', accounts => { window.ethereum.on('accountsChanged', accounts => {
// For some reason accounts here are returned with lowercase letters, so we need to patch them // For some reason accounts here are returned with lowercase letters, so we need to patch them
let patchedAccounts = Array.from(accounts); let patchedAccounts = Array.from(accounts);

10
src/drizzleStatus/drizzleStatusSaga.js

@ -7,7 +7,7 @@ import { getAccountBalances } from '../accountBalances/accountBalancesSaga'
import * as DrizzleActions from './drizzleActions' import * as DrizzleActions from './drizzleActions'
import * as BlocksActions from '../blocks/blockActions' 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) { export function * initializeDrizzle (action) {
try { try {
@ -35,10 +35,10 @@ export function * initializeDrizzle (action) {
yield call(getAccountBalances, { web3 }) yield call(getAccountBalances, { web3 })
// Instantiate contracts passed through via options. // Instantiate contracts passed through via options.
for (var i = 0; i < options.contracts.length; i++) { for (let i = 0; i < options.contracts.length; i++) {
var contractConfig = options.contracts[i] const contractConfig = options.contracts[i]
var events = [] let events = []
var contractName = contractConfig.contractName const contractName = contractConfig.contractName
if (contractName in options.events) { if (contractName in options.events) {
events = options.events[contractName] events = options.events[contractName]

40
src/index.js

@ -7,53 +7,27 @@ import * as EventActions from './contracts/constants'
import * as AccountActions from './accounts/accountsActions' import * as AccountActions from './accounts/accountsActions'
// Reducers // Reducers
import accountsReducer from './accounts/accountsReducer' import drizzleReducers from './reducer'
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'
// Middleware // Middleware
import drizzleMiddleware from './drizzle-middleware' import drizzleMiddleware from './drizzle-middleware'
import accountsMiddleware from './accounts/accountsMiddleware' import accountsMiddleware from './accounts/accountsMiddleware'
import accountBalancesMiddleware from './accountBalances/accountBalancesMiddleware' import accountBalancesMiddleware from './accountBalances/accountBalancesMiddleware'
import web3Middleware from './web3/web3Middleware'
// Sagas // Sagas
import accountBalancesSaga from './accountBalances/accountBalancesSaga' import drizzleSagas from './rootSaga'
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
}
const drizzleMiddlewares = [ const drizzleMiddlewares = [
drizzleMiddleware, drizzleMiddleware,
accountsMiddleware, accountsMiddleware,
accountBalancesMiddleware accountBalancesMiddleware,
] web3Middleware
const drizzleSagas = [
accountBalancesSaga,
blocksSaga,
contractsSaga,
drizzleStatusSaga
] ]
const drizzleActions = { const drizzleActions = {
AccountActions, account: AccountActions,
EventActions event: EventActions
} }
export { export {

4
src/rootSaga.js

@ -2,10 +2,12 @@ import accountBalancesSaga from './accountBalances/accountBalancesSaga'
import blocksSaga from './blocks/blocksSaga' import blocksSaga from './blocks/blocksSaga'
import contractsSaga from './contracts/contractsSaga' import contractsSaga from './contracts/contractsSaga'
import drizzleStatusSaga from './drizzleStatus/drizzleStatusSaga' import drizzleStatusSaga from './drizzleStatus/drizzleStatusSaga'
import web3Saga from './web3/web3Saga'
export default [ export default [
accountBalancesSaga, accountBalancesSaga,
blocksSaga, blocksSaga,
contractsSaga, contractsSaga,
drizzleStatusSaga drizzleStatusSaga,
web3Saga
] ]

8
src/web3/constants.js → src/web3/web3Actions.js

@ -4,6 +4,7 @@ export const WEB3_FAILED = 'WEB3_FAILED'
export const WEB3_USER_DENIED = 'WEB3_USER_DENIED' export const WEB3_USER_DENIED = 'WEB3_USER_DENIED'
export const NETWORK_ID_FETCHED = 'NETWORK_ID_FETCHED' 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_ID_FAILED = 'NETWORK_ID_FAILED'
export const NETWORK_MISMATCH = 'NETWORK_MISMATCH' export const NETWORK_MISMATCH = 'NETWORK_MISMATCH'
@ -15,3 +16,10 @@ export const NETWORK_IDS = {
kovan: 42, kovan: 42,
ganache: 5777 ganache: 5777
} }
export function networkIdChanged (web3) {
return {
type: NETWORK_ID_CHANGED,
web3
}
}

21
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

5
src/web3/web3Reducer.js

@ -1,4 +1,4 @@
import * as Action from './constants' import * as Action from './web3Actions'
const initialState = { const initialState = {
status: '' 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 { return {
...state, ...state,
networkId: action.networkId networkId: action.networkId

26
src/web3/web3Saga.js

@ -1,12 +1,11 @@
import { call, put } from 'redux-saga/effects' import { call, put, takeLatest } from 'redux-saga/effects'
import * as Action from './constants' import * as Action from './web3Actions'
const Web3 = require('web3'); const Web3 = require('web3');
/* /*
* Initialization * Initialization
*/ */
export function * initializeWeb3 (options) { export function * initializeWeb3 (options) {
try { try {
let web3 = {} let web3 = {}
@ -35,7 +34,6 @@ export function * initializeWeb3 (options) {
} catch (error) { } catch (error) {
console.error(error) console.error(error)
yield put({ type: Action.WEB3_FAILED }) yield put({ type: Action.WEB3_FAILED })
return
} }
} else if (typeof window.web3 !== 'undefined') { } else if (typeof window.web3 !== 'undefined') {
// Checking if Web3 has been injected by the browser (Mist/MetaMask) // 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 }) { export function * getNetworkId ({ web3 }) {
try { 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 return networkId
} catch (error) { } 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 fetching network ID:');
console.error(error) console.error(error);
} }
} }
function * web3Saga () {
yield takeLatest(Action.NETWORK_ID_CHANGED, getNetworkId);
}
export default web3Saga

Loading…
Cancel
Save