1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-24 19:10:22 +01:00
metamask-extension/ui/app/reducers/app.js

779 lines
19 KiB
JavaScript
Raw Normal View History

const extend = require('xtend')
const actions = require('../actions')
const txHelper = require('../../lib/tx-helper')
const log = require('loglevel')
module.exports = reduceApp
2016-06-21 22:18:32 +02:00
function reduceApp (state, action) {
log.debug('App Reducer got ' + action.type)
// clone and defaults
const selectedAddress = state.metamask.selectedAddress
2017-03-31 21:38:20 +02:00
const hasUnconfActions = checkUnconfActions(state)
let name = 'accounts'
if (selectedAddress) {
name = 'accountDetail'
}
2017-03-31 21:38:20 +02:00
if (hasUnconfActions) {
2017-02-24 01:00:43 +01:00
log.debug('pending txs detected, defaulting to conf-tx view.')
name = 'confTx'
}
var defaultView = {
name,
detailView: null,
context: selectedAddress,
}
// confirm seed words
var seedWords = state.metamask.seedWords
var seedConfView = {
name: 'createVaultComplete',
seedWords,
}
// default state
var appState = extend({
shouldClose: false,
2016-05-18 21:30:03 +02:00
menuOpen: false,
modal: {
open: false,
modalState: {
name: null,
props: {},
},
previousModalState: {
name: null,
2017-11-02 13:15:59 +01:00
},
},
sidebar: {
isOpen: false,
transitionName: '',
type: '',
},
2018-07-19 08:31:02 +02:00
alertOpen: false,
alertMessage: null,
2018-07-25 02:32:20 +02:00
qrCodeData: null,
networkDropdownOpen: false,
2016-10-25 22:24:03 +02:00
currentView: seedWords ? seedConfView : defaultView,
accountDetail: {
subview: 'transactions',
},
2017-08-03 23:48:19 +02:00
// Used to render transition direction
transForward: true,
// Used to display loading indicator
isLoading: false,
// Used to display error text
warning: null,
buyView: {},
isMouseUser: false,
gasIsLoading: false,
networkNonce: null,
2018-08-14 01:29:43 +02:00
defaultHdPaths: {
trezor: `m/44'/60'/0'/0`,
2018-08-14 07:26:18 +02:00
ledger: `m/44'/60'/0'/0/0`,
2018-08-14 01:29:43 +02:00
},
}, state.appState)
switch (action.type) {
// dropdown methods
case actions.NETWORK_DROPDOWN_OPEN:
return extend(appState, {
networkDropdownOpen: true,
})
case actions.NETWORK_DROPDOWN_CLOSE:
return extend(appState, {
networkDropdownOpen: false,
})
2017-08-02 22:03:36 +02:00
// sidebar methods
case actions.SIDEBAR_OPEN:
return extend(appState, {
sidebar: {
...action.value,
isOpen: true,
},
2017-08-02 22:03:36 +02:00
})
case actions.SIDEBAR_CLOSE:
return extend(appState, {
sidebar: {
...appState.sidebar,
isOpen: false,
},
2017-08-02 22:03:36 +02:00
})
2018-07-25 02:32:20 +02:00
// alert methods
2018-07-19 08:31:02 +02:00
case actions.ALERT_OPEN:
return extend(appState, {
alertOpen: true,
alertMessage: action.value,
})
case actions.ALERT_CLOSE:
return extend(appState, {
alertOpen: false,
alertMessage: null,
})
2018-07-30 23:50:05 +02:00
// qr scanner methods
2018-07-25 02:32:20 +02:00
case actions.QR_CODE_DETECTED:
return extend(appState, {
qrCodeData: action.value,
})
2018-07-19 08:31:02 +02:00
// modal methods:
case actions.MODAL_OPEN:
const { name, ...modalProps } = action.payload
return extend(appState, {
modal: {
open: true,
modalState: {
name: name,
props: { ...modalProps },
},
previousModalState: { ...appState.modal.modalState },
},
})
case actions.MODAL_CLOSE:
return extend(appState, {
modal: Object.assign(
state.appState.modal,
{ open: false },
{ modalState: { name: null, props: {} } },
2017-11-02 13:15:59 +01:00
{ previousModalState: appState.modal.modalState},
),
})
// transition methods
case actions.TRANSITION_FORWARD:
return extend(appState, {
transForward: true,
})
case actions.TRANSITION_BACKWARD:
return extend(appState, {
transForward: false,
})
// intialize
2016-06-21 22:18:32 +02:00
case actions.SHOW_CREATE_VAULT:
return extend(appState, {
currentView: {
name: 'createVault',
},
transForward: true,
warning: null,
})
2016-06-21 22:18:32 +02:00
case actions.SHOW_RESTORE_VAULT:
return extend(appState, {
currentView: {
name: 'restoreVault',
},
transForward: true,
forgottenPassword: true,
2016-06-21 22:18:32 +02:00
})
case actions.FORGOT_PASSWORD:
const newState = extend(appState, {
2018-03-03 03:14:05 +01:00
forgottenPassword: action.value,
2016-06-21 22:18:32 +02:00
})
if (action.value) {
newState.currentView = {
name: 'restoreVault',
}
}
return newState
2016-06-21 22:18:32 +02:00
case actions.SHOW_INIT_MENU:
return extend(appState, {
currentView: defaultView,
transForward: false,
})
2016-06-21 22:18:32 +02:00
case actions.SHOW_CONFIG_PAGE:
return extend(appState, {
currentView: {
name: 'config',
context: appState.currentView.context,
},
transForward: action.value,
})
case actions.SHOW_ADD_TOKEN_PAGE:
return extend(appState, {
currentView: {
name: 'add-token',
context: appState.currentView.context,
},
transForward: action.value,
})
2018-08-07 23:40:45 +02:00
case actions.SHOW_ADD_SUGGESTED_TOKEN_PAGE:
return extend(appState, {
currentView: {
name: 'add-suggested-token',
context: appState.currentView.context,
},
transForward: action.value,
})
case actions.SHOW_IMPORT_PAGE:
return extend(appState, {
currentView: {
name: 'import-menu',
},
transForward: true,
warning: null,
})
case actions.SHOW_NEW_ACCOUNT_PAGE:
return extend(appState, {
currentView: {
name: 'new-account-page',
context: action.formToSelect,
},
transForward: true,
warning: null,
})
case actions.SET_NEW_ACCOUNT_FORM:
return extend(appState, {
currentView: {
name: appState.currentView.name,
context: action.formToSelect,
},
})
2016-06-21 22:18:32 +02:00
case actions.SHOW_INFO_PAGE:
return extend(appState, {
currentView: {
name: 'info',
context: appState.currentView.context,
},
transForward: true,
})
case actions.CREATE_NEW_VAULT_IN_PROGRESS:
2016-06-21 22:18:32 +02:00
return extend(appState, {
currentView: {
name: 'createVault',
inProgress: true,
},
transForward: true,
isLoading: true,
})
2016-06-21 22:18:32 +02:00
case actions.SHOW_NEW_VAULT_SEED:
return extend(appState, {
currentView: {
name: 'createVaultComplete',
seedWords: action.value,
},
transForward: true,
isLoading: false,
})
2016-11-04 20:00:56 +01:00
case actions.NEW_ACCOUNT_SCREEN:
return extend(appState, {
currentView: {
name: 'new-account',
context: appState.currentView.context,
},
transForward: true,
})
2016-06-21 22:18:32 +02:00
case actions.SHOW_SEND_PAGE:
return extend(appState, {
currentView: {
name: 'sendTransaction',
context: appState.currentView.context,
},
transForward: true,
warning: null,
})
2017-09-07 13:24:03 +02:00
case actions.SHOW_SEND_TOKEN_PAGE:
return extend(appState, {
currentView: {
name: 'sendToken',
context: appState.currentView.context,
},
transForward: true,
warning: null,
})
2016-10-15 19:48:12 +02:00
case actions.SHOW_NEW_KEYCHAIN:
return extend(appState, {
currentView: {
name: 'newKeychain',
2016-10-20 18:50:29 +02:00
context: appState.currentView.context,
2016-10-15 19:48:12 +02:00
},
transForward: true,
})
2016-06-21 22:18:32 +02:00
// unlock
2016-06-21 22:18:32 +02:00
case actions.UNLOCK_METAMASK:
return extend(appState, {
forgottenPassword: appState.forgottenPassword ? !appState.forgottenPassword : null,
2016-06-21 22:18:32 +02:00
detailView: {},
transForward: true,
isLoading: false,
warning: null,
})
case actions.LOCK_METAMASK:
return extend(appState, {
currentView: defaultView,
transForward: false,
2016-06-21 22:18:32 +02:00
warning: null,
})
case actions.BACK_TO_INIT_MENU:
return extend(appState, {
warning: null,
transForward: false,
forgottenPassword: true,
currentView: {
name: 'InitMenu',
},
})
case actions.BACK_TO_UNLOCK_VIEW:
return extend(appState, {
warning: null,
transForward: true,
forgottenPassword: false,
currentView: {
name: 'UnlockScreen',
},
})
2016-06-21 22:18:32 +02:00
// reveal seed words
case actions.REVEAL_SEED_CONFIRMATION:
return extend(appState, {
currentView: {
2016-06-21 22:18:32 +02:00
name: 'reveal-seed-conf',
},
2016-06-21 22:18:32 +02:00
transForward: true,
warning: null,
})
2016-06-21 22:18:32 +02:00
// accounts
case actions.SET_SELECTED_ACCOUNT:
return extend(appState, {
2016-06-21 22:18:32 +02:00
activeAddress: action.value,
})
case actions.GO_HOME:
return extend(appState, {
currentView: extend(appState.currentView, {
name: 'accountDetail',
}),
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
transForward: false,
warning: null,
2016-06-21 22:18:32 +02:00
})
case actions.SHOW_ACCOUNT_DETAIL:
return extend(appState, {
forgottenPassword: appState.forgottenPassword ? !appState.forgottenPassword : null,
currentView: {
name: 'accountDetail',
2016-06-21 22:56:04 +02:00
context: action.value,
},
accountDetail: {
subview: 'transactions',
2016-06-21 22:18:32 +02:00
accountExport: 'none',
privateKey: '',
},
2016-06-21 22:18:32 +02:00
transForward: false,
})
2016-06-21 22:18:32 +02:00
case actions.BACK_TO_ACCOUNT_DETAIL:
return extend(appState, {
currentView: {
name: 'accountDetail',
context: action.value,
},
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
transForward: false,
})
case actions.SHOW_ACCOUNTS_PAGE:
return extend(appState, {
currentView: {
name: seedWords ? 'createVaultComplete' : 'accounts',
seedWords,
},
transForward: true,
isLoading: false,
warning: null,
2016-06-21 22:18:32 +02:00
scrollToBottom: false,
forgottenPassword: false,
2016-06-21 22:18:32 +02:00
})
case actions.SHOW_NOTICE:
return extend(appState, {
transForward: true,
isLoading: false,
})
2016-06-21 22:18:32 +02:00
case actions.REVEAL_ACCOUNT:
return extend(appState, {
scrollToBottom: true,
})
case actions.SHOW_CONF_TX_PAGE:
return extend(appState, {
currentView: {
name: 'confTx',
context: action.id ? indexForPending(state, action.id) : 0,
2016-06-21 22:18:32 +02:00
},
transForward: action.transForward,
warning: null,
isLoading: false,
2016-06-21 22:18:32 +02:00
})
case actions.SHOW_CONF_MSG_PAGE:
return extend(appState, {
currentView: {
2017-03-31 21:38:20 +02:00
name: hasUnconfActions ? 'confTx' : 'account-detail',
2016-06-21 22:18:32 +02:00
context: 0,
},
transForward: true,
warning: null,
isLoading: false,
2016-06-21 22:18:32 +02:00
})
case actions.COMPLETED_TX:
2017-02-24 01:00:43 +01:00
log.debug('reducing COMPLETED_TX for tx ' + action.value)
const otherUnconfActions = getUnconfActionList(state)
.filter(tx => tx.id !== action.value)
const hasOtherUnconfActions = otherUnconfActions.length > 0
if (hasOtherUnconfActions) {
log.debug('reducer detected txs - rendering confTx view')
return extend(appState, {
transForward: false,
currentView: {
name: 'confTx',
context: 0,
},
warning: null,
})
} else {
log.debug('attempting to close popup')
return extend(appState, {
// indicate notification should close
shouldClose: true,
transForward: false,
warning: null,
currentView: {
name: 'accountDetail',
context: state.metamask.selectedAddress,
},
accountDetail: {
subview: 'transactions',
},
})
}
2016-06-21 22:18:32 +02:00
case actions.NEXT_TX:
return extend(appState, {
transForward: true,
currentView: {
name: 'confTx',
context: ++appState.currentView.context,
warning: null,
},
})
case actions.VIEW_PENDING_TX:
const context = indexForPending(state, action.value)
return extend(appState, {
transForward: true,
currentView: {
name: 'confTx',
context,
warning: null,
},
})
case actions.PREVIOUS_TX:
return extend(appState, {
transForward: false,
currentView: {
name: 'confTx',
context: --appState.currentView.context,
warning: null,
},
})
case actions.TRANSACTION_ERROR:
return extend(appState, {
currentView: {
name: 'confTx',
errorMessage: 'There was a problem submitting this transaction.',
},
})
case actions.UNLOCK_FAILED:
return extend(appState, {
warning: action.value || 'Incorrect password. Try again.',
2016-06-21 22:18:32 +02:00
})
case actions.UNLOCK_SUCCEEDED:
return extend(appState, {
warning: '',
})
2018-08-14 01:29:43 +02:00
case actions.SET_HARDWARE_WALLET_DEFAULT_HD_PATH:
const { device, path } = action.value
const newDefaults = {...appState.defaultHdPaths}
newDefaults[device] = path
return extend(appState, {
defaultHdPaths: newDefaults,
})
2016-06-21 22:18:32 +02:00
case actions.SHOW_LOADING:
return extend(appState, {
isLoading: true,
loadingMessage: action.value,
2016-06-21 22:18:32 +02:00
})
case actions.HIDE_LOADING:
return extend(appState, {
isLoading: false,
})
2016-08-10 22:51:14 +02:00
case actions.SHOW_SUB_LOADING_INDICATION:
return extend(appState, {
isSubLoading: true,
})
case actions.HIDE_SUB_LOADING_INDICATION:
return extend(appState, {
isSubLoading: false,
})
2016-06-21 22:18:32 +02:00
case actions.CLEAR_SEED_WORD_CACHE:
return extend(appState, {
transForward: true,
currentView: {},
isLoading: false,
accountDetail: {
subview: 'transactions',
accountExport: 'none',
privateKey: '',
},
})
case actions.DISPLAY_WARNING:
return extend(appState, {
warning: action.value,
isLoading: false,
2016-06-21 22:18:32 +02:00
})
case actions.HIDE_WARNING:
return extend(appState, {
warning: undefined,
})
case actions.REQUEST_ACCOUNT_EXPORT:
return extend(appState, {
transForward: true,
currentView: {
name: 'accountDetail',
context: appState.currentView.context,
},
accountDetail: {
subview: 'export',
accountExport: 'requested',
},
})
case actions.EXPORT_ACCOUNT:
return extend(appState, {
accountDetail: {
subview: 'export',
accountExport: 'completed',
},
})
case actions.SHOW_PRIVATE_KEY:
return extend(appState, {
accountDetail: {
subview: 'export',
accountExport: 'completed',
privateKey: action.value,
},
})
case actions.BUY_ETH_VIEW:
return extend(appState, {
transForward: true,
currentView: {
name: 'buyEth',
context: appState.currentView.name,
},
identity: state.metamask.identities[action.value],
buyView: {
subview: 'Coinbase',
2017-01-10 21:18:39 +01:00
amount: '15.00',
buyAddress: action.value,
2016-08-10 22:51:14 +02:00
formView: {
coinbase: true,
shapeshift: false,
},
},
})
case actions.ONBOARDING_BUY_ETH_VIEW:
return extend(appState, {
transForward: true,
currentView: {
name: 'onboardingBuyEth',
context: appState.currentView.name,
},
identity: state.metamask.identities[action.value],
})
2016-08-10 22:51:14 +02:00
case actions.COINBASE_SUBVIEW:
return extend(appState, {
buyView: {
subview: 'Coinbase',
2016-08-10 22:51:14 +02:00
formView: {
coinbase: true,
shapeshift: false,
},
buyAddress: appState.buyView.buyAddress,
amount: appState.buyView.amount,
2016-08-10 22:51:14 +02:00
},
})
case actions.SHAPESHIFT_SUBVIEW:
return extend(appState, {
buyView: {
subview: 'ShapeShift',
2016-08-10 22:51:14 +02:00
formView: {
coinbase: false,
shapeshift: true,
marketinfo: action.value.marketinfo,
coinOptions: action.value.coinOptions,
},
buyAddress: action.value.buyAddress || appState.buyView.buyAddress,
amount: appState.buyView.amount || 0,
2016-08-10 22:51:14 +02:00
},
})
case actions.PAIR_UPDATE:
return extend(appState, {
buyView: {
subview: 'ShapeShift',
2016-08-10 22:51:14 +02:00
formView: {
coinbase: false,
shapeshift: true,
marketinfo: action.value.marketinfo,
coinOptions: appState.buyView.formView.coinOptions,
2016-08-10 22:51:14 +02:00
},
buyAddress: appState.buyView.buyAddress,
amount: appState.buyView.amount,
2016-08-10 22:51:14 +02:00
warning: null,
},
})
case actions.SHOW_QR:
2016-08-10 22:51:14 +02:00
return extend(appState, {
qrRequested: true,
transForward: true,
Qr: {
message: action.value.message,
data: action.value.data,
},
})
2016-08-18 19:40:35 +02:00
case actions.SHOW_QR_VIEW:
return extend(appState, {
currentView: {
name: 'qr',
context: appState.currentView.context,
},
transForward: true,
Qr: {
message: action.value.message,
data: action.value.data,
},
})
case actions.SET_MOUSE_USER_STATE:
return extend(appState, {
isMouseUser: action.value,
})
case actions.GAS_LOADING_STARTED:
return extend(appState, {
gasIsLoading: true,
})
case actions.GAS_LOADING_FINISHED:
return extend(appState, {
gasIsLoading: false,
2018-07-03 00:49:33 +02:00
})
case actions.SET_NETWORK_NONCE:
return extend(appState, {
networkNonce: action.value,
})
2016-08-19 00:20:26 +02:00
default:
2016-06-21 22:18:32 +02:00
return appState
}
}
2017-03-31 21:38:20 +02:00
function checkUnconfActions (state) {
const unconfActionList = getUnconfActionList(state)
const hasUnconfActions = unconfActionList.length > 0
return hasUnconfActions
}
function getUnconfActionList (state) {
const { unapprovedTxs, unapprovedMsgs,
2017-09-29 18:24:08 +02:00
unapprovedPersonalMsgs, unapprovedTypedMessages, network } = state.metamask
2017-09-29 18:24:08 +02:00
const unconfActionList = txHelper(unapprovedTxs, unapprovedMsgs, unapprovedPersonalMsgs, unapprovedTypedMessages, network)
2017-03-31 21:38:20 +02:00
return unconfActionList
}
2016-06-21 22:18:32 +02:00
function indexForPending (state, txId) {
2017-03-31 21:38:20 +02:00
const unconfTxList = getUnconfActionList(state)
const match = unconfTxList.find((tx) => tx.id === txId)
const index = unconfTxList.indexOf(match)
return index
}
// function indexForLastPending (state) {
// return getUnconfActionList(state).length
// }