mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-30 16:18:07 +01:00
fe28e0d134
* Cleanup beforeunload handler after transaction is resolved The notification window was updated to reject transactions upon close in #6340. A handler that rejects the transaction was added to `window.onbeforeunload`, and it was cleared in `actions.js` if it was confirmed or rejected. However, the `onbeforeunload` handler remained uncleared if the transaction was resolved in another window. This results in the transaction being rejected when the notification window closes, even long after the transaction is submitted and confirmed. This has been the cause of many problems with the Firefox e2e tests. Instead the `onbeforeunload` handler is cleared in the `componentWillUnmount` lifecycle function, alongside where it's set in the first place. This ensures that it's correctly unset regardless of how the transaction was resolved, and it better matches user expectations. * Fix indentation and remove redundant export The `run-all.sh` Bash script now uses consistent indentation, and is consistent about only re-exporting the Ganache arguments when they change. * Ensure transactions are completed before checking balance Various intermittent e2e test failures appear to be caused by React re-rendering the transaction list during the test, as the transaction goes from pending to confirmed. To avoid this race condition, the transaction is now explicitly looked for in the confirmed transaction list in each of the tests using this pattern. * Enable all e2e tests on Firefox The remaining tests that were disabled on Firefox now work correctly. Only a few timing adjustments were needed. * Update Firefox used in CI Firefox v70 is now used on CI instead of v68. This necessitated rewriting the function where the extension ID was obtained because the Firefox extensions page was redesigned.
2957 lines
74 KiB
JavaScript
2957 lines
74 KiB
JavaScript
const abi = require('human-standard-token-abi')
|
|
const pify = require('pify')
|
|
const getBuyEthUrl = require('../../../app/scripts/lib/buy-eth-url')
|
|
const { getTokenAddressFromTokenObject, checksumAddress } = require('../helpers/utils/util')
|
|
const {
|
|
calcTokenBalance,
|
|
estimateGas,
|
|
} = require('../pages/send/send.utils')
|
|
const ethUtil = require('ethereumjs-util')
|
|
const { fetchLocale } = require('../helpers/utils/i18n-helper')
|
|
const { getMethodDataAsync } = require('../helpers/utils/transactions.util')
|
|
const { fetchSymbolAndDecimals } = require('../helpers/utils/token-util')
|
|
import switchDirection from '../helpers/utils/switch-direction'
|
|
const log = require('loglevel')
|
|
const { ENVIRONMENT_TYPE_NOTIFICATION } = require('../../../app/scripts/lib/enums')
|
|
const { hasUnconfirmedTransactions } = require('../helpers/utils/confirm-tx.util')
|
|
const gasDuck = require('../ducks/gas/gas.duck')
|
|
const WebcamUtils = require('../../lib/webcam-utils')
|
|
|
|
var actions = {
|
|
_setBackgroundConnection: _setBackgroundConnection,
|
|
|
|
GO_HOME: 'GO_HOME',
|
|
goHome: goHome,
|
|
// modal state
|
|
MODAL_OPEN: 'UI_MODAL_OPEN',
|
|
MODAL_CLOSE: 'UI_MODAL_CLOSE',
|
|
showModal: showModal,
|
|
hideModal: hideModal,
|
|
// notification state
|
|
CLOSE_NOTIFICATION_WINDOW: 'CLOSE_NOTIFICATION_WINDOW',
|
|
closeNotifacationWindow: closeNotifacationWindow,
|
|
// sidebar state
|
|
SIDEBAR_OPEN: 'UI_SIDEBAR_OPEN',
|
|
SIDEBAR_CLOSE: 'UI_SIDEBAR_CLOSE',
|
|
showSidebar: showSidebar,
|
|
hideSidebar: hideSidebar,
|
|
// sidebar state
|
|
ALERT_OPEN: 'UI_ALERT_OPEN',
|
|
ALERT_CLOSE: 'UI_ALERT_CLOSE',
|
|
showAlert: showAlert,
|
|
hideAlert: hideAlert,
|
|
QR_CODE_DETECTED: 'UI_QR_CODE_DETECTED',
|
|
qrCodeDetected,
|
|
// network dropdown open
|
|
NETWORK_DROPDOWN_OPEN: 'UI_NETWORK_DROPDOWN_OPEN',
|
|
NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE',
|
|
showNetworkDropdown: showNetworkDropdown,
|
|
hideNetworkDropdown: hideNetworkDropdown,
|
|
// menu state/
|
|
getNetworkStatus: 'getNetworkStatus',
|
|
// transition state
|
|
TRANSITION_FORWARD: 'TRANSITION_FORWARD',
|
|
TRANSITION_BACKWARD: 'TRANSITION_BACKWARD',
|
|
transitionForward,
|
|
transitionBackward,
|
|
// remote state
|
|
UPDATE_METAMASK_STATE: 'UPDATE_METAMASK_STATE',
|
|
updateMetamaskState: updateMetamaskState,
|
|
markAccountsFound,
|
|
// intialize screen
|
|
CREATE_NEW_VAULT_IN_PROGRESS: 'CREATE_NEW_VAULT_IN_PROGRESS',
|
|
SHOW_CREATE_VAULT: 'SHOW_CREATE_VAULT',
|
|
SHOW_RESTORE_VAULT: 'SHOW_RESTORE_VAULT',
|
|
fetchInfoToSync,
|
|
FORGOT_PASSWORD: 'FORGOT_PASSWORD',
|
|
forgotPassword: forgotPassword,
|
|
markPasswordForgotten,
|
|
unMarkPasswordForgotten,
|
|
SHOW_INIT_MENU: 'SHOW_INIT_MENU',
|
|
SHOW_INFO_PAGE: 'SHOW_INFO_PAGE',
|
|
SHOW_IMPORT_PAGE: 'SHOW_IMPORT_PAGE',
|
|
SHOW_NEW_ACCOUNT_PAGE: 'SHOW_NEW_ACCOUNT_PAGE',
|
|
SET_NEW_ACCOUNT_FORM: 'SET_NEW_ACCOUNT_FORM',
|
|
unlockMetamask: unlockMetamask,
|
|
unlockFailed: unlockFailed,
|
|
unlockSucceeded,
|
|
showCreateVault: showCreateVault,
|
|
showRestoreVault: showRestoreVault,
|
|
showInitializeMenu: showInitializeMenu,
|
|
showImportPage,
|
|
showNewAccountPage,
|
|
setNewAccountForm,
|
|
createNewVaultAndRestore: createNewVaultAndRestore,
|
|
createNewVaultInProgress: createNewVaultInProgress,
|
|
createNewVaultAndGetSeedPhrase,
|
|
unlockAndGetSeedPhrase,
|
|
addNewKeyring,
|
|
importNewAccount,
|
|
addNewAccount,
|
|
connectHardware,
|
|
checkHardwareStatus,
|
|
forgetDevice,
|
|
unlockHardwareWalletAccount,
|
|
NEW_ACCOUNT_SCREEN: 'NEW_ACCOUNT_SCREEN',
|
|
navigateToNewAccountScreen,
|
|
resetAccount,
|
|
removeAccount,
|
|
showInfoPage: showInfoPage,
|
|
CLOSE_WELCOME_SCREEN: 'CLOSE_WELCOME_SCREEN',
|
|
closeWelcomeScreen,
|
|
// seed recovery actions
|
|
REVEAL_SEED_CONFIRMATION: 'REVEAL_SEED_CONFIRMATION',
|
|
revealSeedConfirmation: revealSeedConfirmation,
|
|
requestRevealSeedWords,
|
|
// unlock screen
|
|
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
|
|
UNLOCK_FAILED: 'UNLOCK_FAILED',
|
|
UNLOCK_SUCCEEDED: 'UNLOCK_SUCCEEDED',
|
|
UNLOCK_METAMASK: 'UNLOCK_METAMASK',
|
|
LOCK_METAMASK: 'LOCK_METAMASK',
|
|
tryUnlockMetamask: tryUnlockMetamask,
|
|
lockMetamask: lockMetamask,
|
|
unlockInProgress: unlockInProgress,
|
|
// error handling
|
|
displayWarning: displayWarning,
|
|
DISPLAY_WARNING: 'DISPLAY_WARNING',
|
|
HIDE_WARNING: 'HIDE_WARNING',
|
|
hideWarning: hideWarning,
|
|
// accounts screen
|
|
SET_SELECTED_ACCOUNT: 'SET_SELECTED_ACCOUNT',
|
|
SET_SELECTED_TOKEN: 'SET_SELECTED_TOKEN',
|
|
setSelectedToken,
|
|
SHOW_ACCOUNT_DETAIL: 'SHOW_ACCOUNT_DETAIL',
|
|
SHOW_ACCOUNTS_PAGE: 'SHOW_ACCOUNTS_PAGE',
|
|
SHOW_CONF_TX_PAGE: 'SHOW_CONF_TX_PAGE',
|
|
SHOW_CONF_MSG_PAGE: 'SHOW_CONF_MSG_PAGE',
|
|
SET_CURRENT_FIAT: 'SET_CURRENT_FIAT',
|
|
showQrScanner,
|
|
setCurrentCurrency,
|
|
setCurrentAccountTab,
|
|
// account detail screen
|
|
SHOW_SEND_PAGE: 'SHOW_SEND_PAGE',
|
|
showSendPage: showSendPage,
|
|
SHOW_SEND_TOKEN_PAGE: 'SHOW_SEND_TOKEN_PAGE',
|
|
showSendTokenPage,
|
|
ADD_TO_ADDRESS_BOOK: 'ADD_TO_ADDRESS_BOOK',
|
|
addToAddressBook: addToAddressBook,
|
|
REMOVE_FROM_ADDRESS_BOOK: 'REMOVE_FROM_ADDRESS_BOOK',
|
|
removeFromAddressBook: removeFromAddressBook,
|
|
REQUEST_ACCOUNT_EXPORT: 'REQUEST_ACCOUNT_EXPORT',
|
|
requestExportAccount: requestExportAccount,
|
|
EXPORT_ACCOUNT: 'EXPORT_ACCOUNT',
|
|
exportAccount: exportAccount,
|
|
SHOW_PRIVATE_KEY: 'SHOW_PRIVATE_KEY',
|
|
showPrivateKey: showPrivateKey,
|
|
exportAccountComplete,
|
|
SET_ACCOUNT_LABEL: 'SET_ACCOUNT_LABEL',
|
|
setAccountLabel,
|
|
updateNetworkNonce,
|
|
SET_NETWORK_NONCE: 'SET_NETWORK_NONCE',
|
|
// tx conf screen
|
|
COMPLETED_TX: 'COMPLETED_TX',
|
|
TRANSACTION_ERROR: 'TRANSACTION_ERROR',
|
|
NEXT_TX: 'NEXT_TX',
|
|
PREVIOUS_TX: 'PREV_TX',
|
|
EDIT_TX: 'EDIT_TX',
|
|
signMsg: signMsg,
|
|
cancelMsg: cancelMsg,
|
|
signPersonalMsg,
|
|
cancelPersonalMsg,
|
|
signTypedMsg,
|
|
cancelTypedMsg,
|
|
sendTx: sendTx,
|
|
signTx: signTx,
|
|
signTokenTx: signTokenTx,
|
|
updateTransaction,
|
|
updateAndApproveTx,
|
|
cancelTx: cancelTx,
|
|
cancelTxs,
|
|
completedTx: completedTx,
|
|
txError: txError,
|
|
nextTx: nextTx,
|
|
editTx,
|
|
previousTx: previousTx,
|
|
cancelAllTx: cancelAllTx,
|
|
viewPendingTx: viewPendingTx,
|
|
VIEW_PENDING_TX: 'VIEW_PENDING_TX',
|
|
updateTransactionParams,
|
|
UPDATE_TRANSACTION_PARAMS: 'UPDATE_TRANSACTION_PARAMS',
|
|
setNextNonce,
|
|
SET_NEXT_NONCE: 'SET_NEXT_NONCE',
|
|
getNextNonce,
|
|
// send screen
|
|
UPDATE_GAS_LIMIT: 'UPDATE_GAS_LIMIT',
|
|
UPDATE_GAS_PRICE: 'UPDATE_GAS_PRICE',
|
|
UPDATE_GAS_TOTAL: 'UPDATE_GAS_TOTAL',
|
|
UPDATE_SEND_FROM: 'UPDATE_SEND_FROM',
|
|
UPDATE_SEND_HEX_DATA: 'UPDATE_SEND_HEX_DATA',
|
|
UPDATE_SEND_TOKEN_BALANCE: 'UPDATE_SEND_TOKEN_BALANCE',
|
|
UPDATE_SEND_TO: 'UPDATE_SEND_TO',
|
|
UPDATE_SEND_AMOUNT: 'UPDATE_SEND_AMOUNT',
|
|
UPDATE_SEND_MEMO: 'UPDATE_SEND_MEMO',
|
|
UPDATE_SEND_ERRORS: 'UPDATE_SEND_ERRORS',
|
|
UPDATE_MAX_MODE: 'UPDATE_MAX_MODE',
|
|
UPDATE_SEND: 'UPDATE_SEND',
|
|
CLEAR_SEND: 'CLEAR_SEND',
|
|
OPEN_FROM_DROPDOWN: 'OPEN_FROM_DROPDOWN',
|
|
CLOSE_FROM_DROPDOWN: 'CLOSE_FROM_DROPDOWN',
|
|
GAS_LOADING_STARTED: 'GAS_LOADING_STARTED',
|
|
GAS_LOADING_FINISHED: 'GAS_LOADING_FINISHED',
|
|
UPDATE_SEND_ENS_RESOLUTION: 'UPDATE_SEND_ENS_RESOLUTION',
|
|
UPDATE_SEND_ENS_RESOLUTION_ERROR: 'UPDATE_SEND_ENS_RESOLUTION_ERROR',
|
|
updateSendEnsResolution,
|
|
updateSendEnsResolutionError,
|
|
setGasLimit,
|
|
setGasPrice,
|
|
updateGasData,
|
|
setGasTotal,
|
|
setSendTokenBalance,
|
|
updateSendTokenBalance,
|
|
updateSendHexData,
|
|
updateSendTo,
|
|
updateSendAmount,
|
|
updateSendMemo,
|
|
setMaxModeTo,
|
|
updateSend,
|
|
updateSendErrors,
|
|
clearSend,
|
|
setSelectedAddress,
|
|
gasLoadingStarted,
|
|
gasLoadingFinished,
|
|
// app messages
|
|
showAccountDetail: showAccountDetail,
|
|
BACK_TO_ACCOUNT_DETAIL: 'BACK_TO_ACCOUNT_DETAIL',
|
|
backToAccountDetail: backToAccountDetail,
|
|
showAccountsPage: showAccountsPage,
|
|
showConfTxPage: showConfTxPage,
|
|
// config screen
|
|
SHOW_CONFIG_PAGE: 'SHOW_CONFIG_PAGE',
|
|
SET_RPC_TARGET: 'SET_RPC_TARGET',
|
|
SET_DEFAULT_RPC_TARGET: 'SET_DEFAULT_RPC_TARGET',
|
|
SET_PROVIDER_TYPE: 'SET_PROVIDER_TYPE',
|
|
SET_PREVIOUS_PROVIDER: 'SET_PREVIOUS_PROVIDER',
|
|
showConfigPage,
|
|
SHOW_ADD_TOKEN_PAGE: 'SHOW_ADD_TOKEN_PAGE',
|
|
SHOW_ADD_SUGGESTED_TOKEN_PAGE: 'SHOW_ADD_SUGGESTED_TOKEN_PAGE',
|
|
showAddTokenPage,
|
|
showAddSuggestedTokenPage,
|
|
addToken,
|
|
addTokens,
|
|
removeToken,
|
|
updateTokens,
|
|
removeSuggestedTokens,
|
|
addKnownMethodData,
|
|
UPDATE_TOKENS: 'UPDATE_TOKENS',
|
|
updateAndSetCustomRpc: updateAndSetCustomRpc,
|
|
setRpcTarget: setRpcTarget,
|
|
delRpcTarget: delRpcTarget,
|
|
editRpc: editRpc,
|
|
setProviderType: setProviderType,
|
|
SET_HARDWARE_WALLET_DEFAULT_HD_PATH: 'SET_HARDWARE_WALLET_DEFAULT_HD_PATH',
|
|
setHardwareWalletDefaultHdPath,
|
|
updateProviderType,
|
|
// loading overlay
|
|
SHOW_LOADING: 'SHOW_LOADING_INDICATION',
|
|
HIDE_LOADING: 'HIDE_LOADING_INDICATION',
|
|
showLoadingIndication: showLoadingIndication,
|
|
hideLoadingIndication: hideLoadingIndication,
|
|
// buy Eth with coinbase
|
|
onboardingBuyEthView,
|
|
ONBOARDING_BUY_ETH_VIEW: 'ONBOARDING_BUY_ETH_VIEW',
|
|
BUY_ETH: 'BUY_ETH',
|
|
buyEth: buyEth,
|
|
buyEthView: buyEthView,
|
|
buyWithShapeShift,
|
|
BUY_ETH_VIEW: 'BUY_ETH_VIEW',
|
|
COINBASE_SUBVIEW: 'COINBASE_SUBVIEW',
|
|
coinBaseSubview: coinBaseSubview,
|
|
SHAPESHIFT_SUBVIEW: 'SHAPESHIFT_SUBVIEW',
|
|
shapeShiftSubview: shapeShiftSubview,
|
|
PAIR_UPDATE: 'PAIR_UPDATE',
|
|
pairUpdate: pairUpdate,
|
|
coinShiftRquest: coinShiftRquest,
|
|
SHOW_SUB_LOADING_INDICATION: 'SHOW_SUB_LOADING_INDICATION',
|
|
showSubLoadingIndication: showSubLoadingIndication,
|
|
HIDE_SUB_LOADING_INDICATION: 'HIDE_SUB_LOADING_INDICATION',
|
|
hideSubLoadingIndication: hideSubLoadingIndication,
|
|
// QR STUFF:
|
|
SHOW_QR: 'SHOW_QR',
|
|
showQrView: showQrView,
|
|
reshowQrCode: reshowQrCode,
|
|
SHOW_QR_VIEW: 'SHOW_QR_VIEW',
|
|
// FORGOT PASSWORD:
|
|
BACK_TO_INIT_MENU: 'BACK_TO_INIT_MENU',
|
|
goBackToInitView: goBackToInitView,
|
|
RECOVERY_IN_PROGRESS: 'RECOVERY_IN_PROGRESS',
|
|
BACK_TO_UNLOCK_VIEW: 'BACK_TO_UNLOCK_VIEW',
|
|
backToUnlockView: backToUnlockView,
|
|
// SHOWING KEYCHAIN
|
|
SHOW_NEW_KEYCHAIN: 'SHOW_NEW_KEYCHAIN',
|
|
showNewKeychain: showNewKeychain,
|
|
|
|
callBackgroundThenUpdate,
|
|
forceUpdateMetamaskState,
|
|
|
|
TOGGLE_ACCOUNT_MENU: 'TOGGLE_ACCOUNT_MENU',
|
|
toggleAccountMenu,
|
|
|
|
useEtherscanProvider,
|
|
|
|
SET_USE_BLOCKIE: 'SET_USE_BLOCKIE',
|
|
setUseBlockie,
|
|
SET_USE_NONCEFIELD: 'SET_USE_NONCEFIELD',
|
|
setUseNonceField,
|
|
UPDATE_CUSTOM_NONCE: 'UPDATE_CUSTOM_NONCE',
|
|
updateCustomNonce,
|
|
|
|
SET_PARTICIPATE_IN_METAMETRICS: 'SET_PARTICIPATE_IN_METAMETRICS',
|
|
SET_METAMETRICS_SEND_COUNT: 'SET_METAMETRICS_SEND_COUNT',
|
|
setParticipateInMetaMetrics,
|
|
setMetaMetricsSendCount,
|
|
|
|
// locale
|
|
SET_CURRENT_LOCALE: 'SET_CURRENT_LOCALE',
|
|
setCurrentLocale,
|
|
updateCurrentLocale,
|
|
//
|
|
// Feature Flags
|
|
setFeatureFlag,
|
|
updateFeatureFlags,
|
|
UPDATE_FEATURE_FLAGS: 'UPDATE_FEATURE_FLAGS',
|
|
|
|
// Preferences
|
|
setPreference,
|
|
updatePreferences,
|
|
UPDATE_PREFERENCES: 'UPDATE_PREFERENCES',
|
|
setUseNativeCurrencyAsPrimaryCurrencyPreference,
|
|
setShowFiatConversionOnTestnetsPreference,
|
|
setAutoLogoutTimeLimit,
|
|
unsetMigratedPrivacyMode,
|
|
|
|
// Onboarding
|
|
setCompletedOnboarding,
|
|
completeOnboarding,
|
|
COMPLETE_ONBOARDING: 'COMPLETE_ONBOARDING',
|
|
|
|
setMouseUserState,
|
|
SET_MOUSE_USER_STATE: 'SET_MOUSE_USER_STATE',
|
|
|
|
// Network
|
|
updateNetworkEndpointType,
|
|
UPDATE_NETWORK_ENDPOINT_TYPE: 'UPDATE_NETWORK_ENDPOINT_TYPE',
|
|
|
|
retryTransaction,
|
|
SET_PENDING_TOKENS: 'SET_PENDING_TOKENS',
|
|
CLEAR_PENDING_TOKENS: 'CLEAR_PENDING_TOKENS',
|
|
setPendingTokens,
|
|
clearPendingTokens,
|
|
|
|
createCancelTransaction,
|
|
createSpeedUpTransaction,
|
|
createRetryTransaction,
|
|
|
|
approveProviderRequestByOrigin,
|
|
rejectProviderRequestByOrigin,
|
|
clearApprovedOrigins,
|
|
|
|
setFirstTimeFlowType,
|
|
SET_FIRST_TIME_FLOW_TYPE: 'SET_FIRST_TIME_FLOW_TYPE',
|
|
|
|
SET_SELECTED_SETTINGS_RPC_URL: 'SET_SELECTED_SETTINGS_RPC_URL',
|
|
setSelectedSettingsRpcUrl,
|
|
SET_NETWORKS_TAB_ADD_MODE: 'SET_NETWORKS_TAB_ADD_MODE',
|
|
setNetworksTabAddMode,
|
|
|
|
// AppStateController-related actions
|
|
SET_LAST_ACTIVE_TIME: 'SET_LAST_ACTIVE_TIME',
|
|
setLastActiveTime,
|
|
|
|
getContractMethodData,
|
|
loadingMethoDataStarted,
|
|
loadingMethoDataFinished,
|
|
LOADING_METHOD_DATA_STARTED: 'LOADING_METHOD_DATA_STARTED',
|
|
LOADING_METHOD_DATA_FINISHED: 'LOADING_METHOD_DATA_FINISHED',
|
|
|
|
getTokenParams,
|
|
loadingTokenParamsStarted,
|
|
LOADING_TOKEN_PARAMS_STARTED: 'LOADING_TOKEN_PARAMS_STARTED',
|
|
loadingTokenParamsFinished,
|
|
LOADING_TOKEN_PARAMS_FINISHED: 'LOADING_TOKEN_PARAMS_FINISHED',
|
|
|
|
setSeedPhraseBackedUp,
|
|
verifySeedPhrase,
|
|
hideSeedPhraseBackupAfterOnboarding,
|
|
SET_SEED_PHRASE_BACKED_UP_TO_TRUE: 'SET_SEED_PHRASE_BACKED_UP_TO_TRUE',
|
|
|
|
initializeThreeBox,
|
|
restoreFromThreeBox,
|
|
getThreeBoxLastUpdated,
|
|
setThreeBoxSyncingPermission,
|
|
setShowRestorePromptToFalse,
|
|
turnThreeBoxSyncingOn,
|
|
turnThreeBoxSyncingOnAndInitialize,
|
|
}
|
|
|
|
module.exports = actions
|
|
|
|
var background = null
|
|
function _setBackgroundConnection (backgroundConnection) {
|
|
background = backgroundConnection
|
|
}
|
|
|
|
function goHome () {
|
|
return {
|
|
type: actions.GO_HOME,
|
|
}
|
|
}
|
|
|
|
// async actions
|
|
|
|
function tryUnlockMetamask (password) {
|
|
return dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
dispatch(actions.unlockInProgress())
|
|
log.debug(`background.submitPassword`)
|
|
|
|
return new Promise((resolve, reject) => {
|
|
background.submitPassword(password, error => {
|
|
if (error) {
|
|
return reject(error)
|
|
}
|
|
|
|
resolve()
|
|
})
|
|
})
|
|
.then(() => {
|
|
dispatch(actions.unlockSucceeded())
|
|
return forceUpdateMetamaskState(dispatch)
|
|
})
|
|
.then(() => {
|
|
return new Promise((resolve, reject) => {
|
|
background.verifySeedPhrase(err => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
resolve()
|
|
})
|
|
})
|
|
})
|
|
.then(() => {
|
|
dispatch(actions.transitionForward())
|
|
dispatch(actions.hideLoadingIndication())
|
|
})
|
|
.catch(err => {
|
|
dispatch(actions.unlockFailed(err.message))
|
|
dispatch(actions.hideLoadingIndication())
|
|
return Promise.reject(err)
|
|
})
|
|
}
|
|
}
|
|
|
|
function transitionForward () {
|
|
return {
|
|
type: this.TRANSITION_FORWARD,
|
|
}
|
|
}
|
|
|
|
function transitionBackward () {
|
|
return {
|
|
type: this.TRANSITION_BACKWARD,
|
|
}
|
|
}
|
|
|
|
function createNewVaultAndRestore (password, seed) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.createNewVaultAndRestore`)
|
|
let vault
|
|
return new Promise((resolve, reject) => {
|
|
background.createNewVaultAndRestore(password, seed, (err, _vault) => {
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
vault = _vault
|
|
resolve()
|
|
})
|
|
})
|
|
.then(() => dispatch(actions.unMarkPasswordForgotten()))
|
|
.then(() => {
|
|
dispatch(actions.showAccountsPage())
|
|
dispatch(actions.hideLoadingIndication())
|
|
return vault
|
|
})
|
|
.catch(err => {
|
|
dispatch(actions.displayWarning(err.message))
|
|
dispatch(actions.hideLoadingIndication())
|
|
return Promise.reject(err)
|
|
})
|
|
}
|
|
}
|
|
|
|
function createNewVaultAndGetSeedPhrase (password) {
|
|
return async dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
|
|
try {
|
|
await createNewVault(password)
|
|
const seedWords = await verifySeedPhrase()
|
|
dispatch(actions.hideLoadingIndication())
|
|
return seedWords
|
|
} catch (error) {
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.displayWarning(error.message))
|
|
throw new Error(error.message)
|
|
}
|
|
}
|
|
}
|
|
|
|
function unlockAndGetSeedPhrase (password) {
|
|
return async dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
|
|
try {
|
|
await submitPassword(password)
|
|
const seedWords = await verifySeedPhrase()
|
|
await forceUpdateMetamaskState(dispatch)
|
|
dispatch(actions.hideLoadingIndication())
|
|
return seedWords
|
|
} catch (error) {
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.displayWarning(error.message))
|
|
throw new Error(error.message)
|
|
}
|
|
}
|
|
}
|
|
|
|
function revealSeedConfirmation () {
|
|
return {
|
|
type: this.REVEAL_SEED_CONFIRMATION,
|
|
}
|
|
}
|
|
|
|
function submitPassword (password) {
|
|
return new Promise((resolve, reject) => {
|
|
background.submitPassword(password, error => {
|
|
if (error) {
|
|
return reject(error)
|
|
}
|
|
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
|
|
function createNewVault (password) {
|
|
return new Promise((resolve, reject) => {
|
|
background.createNewVaultAndKeychain(password, error => {
|
|
if (error) {
|
|
return reject(error)
|
|
}
|
|
|
|
resolve(true)
|
|
})
|
|
})
|
|
}
|
|
|
|
function verifyPassword (password) {
|
|
return new Promise((resolve, reject) => {
|
|
background.submitPassword(password, error => {
|
|
if (error) {
|
|
return reject(error)
|
|
}
|
|
|
|
resolve(true)
|
|
})
|
|
})
|
|
}
|
|
|
|
function verifySeedPhrase () {
|
|
return new Promise((resolve, reject) => {
|
|
background.verifySeedPhrase((error, seedWords) => {
|
|
if (error) {
|
|
return reject(error)
|
|
}
|
|
|
|
resolve(seedWords)
|
|
})
|
|
})
|
|
}
|
|
|
|
function requestRevealSeedWords (password) {
|
|
return async dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.submitPassword`)
|
|
|
|
try {
|
|
await verifyPassword(password)
|
|
const seedWords = await verifySeedPhrase()
|
|
dispatch(actions.hideLoadingIndication())
|
|
return seedWords
|
|
} catch (error) {
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.displayWarning(error.message))
|
|
throw new Error(error.message)
|
|
}
|
|
}
|
|
}
|
|
|
|
function fetchInfoToSync () {
|
|
return dispatch => {
|
|
log.debug(`background.fetchInfoToSync`)
|
|
return new Promise((resolve, reject) => {
|
|
background.fetchInfoToSync((err, result) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
resolve(result)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function resetAccount () {
|
|
return dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
|
|
return new Promise((resolve, reject) => {
|
|
background.resetAccount((err, account) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
log.info('Transaction history reset for ' + account)
|
|
dispatch(actions.showAccountsPage())
|
|
resolve(account)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function removeAccount (address) {
|
|
return dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
|
|
return new Promise((resolve, reject) => {
|
|
background.removeAccount(address, (err, account) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
log.info('Account removed: ' + account)
|
|
dispatch(actions.showAccountsPage())
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function addNewKeyring (type, opts) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.addNewKeyring`)
|
|
background.addNewKeyring(type, opts, (err) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) return dispatch(actions.displayWarning(err.message))
|
|
dispatch(actions.showAccountsPage())
|
|
})
|
|
}
|
|
}
|
|
|
|
function importNewAccount (strategy, args) {
|
|
return async (dispatch) => {
|
|
let newState
|
|
dispatch(actions.showLoadingIndication('This may take a while, please be patient.'))
|
|
try {
|
|
log.debug(`background.importAccountWithStrategy`)
|
|
await pify(background.importAccountWithStrategy).call(background, strategy, args)
|
|
log.debug(`background.getState`)
|
|
newState = await pify(background.getState).call(background)
|
|
} catch (err) {
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.displayWarning(err.message))
|
|
throw err
|
|
}
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
if (newState.selectedAddress) {
|
|
dispatch({
|
|
type: actions.SHOW_ACCOUNT_DETAIL,
|
|
value: newState.selectedAddress,
|
|
})
|
|
}
|
|
return newState
|
|
}
|
|
}
|
|
|
|
function navigateToNewAccountScreen () {
|
|
return {
|
|
type: this.NEW_ACCOUNT_SCREEN,
|
|
}
|
|
}
|
|
|
|
function addNewAccount () {
|
|
log.debug(`background.addNewAccount`)
|
|
return (dispatch, getState) => {
|
|
const oldIdentities = getState().metamask.identities
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.addNewAccount((err, { identities: newIdentities}) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
const newAccountAddress = Object.keys(newIdentities).find(address => !oldIdentities[address])
|
|
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
forceUpdateMetamaskState(dispatch)
|
|
return resolve(newAccountAddress)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function checkHardwareStatus (deviceName, hdPath) {
|
|
log.debug(`background.checkHardwareStatus`, deviceName, hdPath)
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.checkHardwareStatus(deviceName, hdPath, (err, unlocked) => {
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
forceUpdateMetamaskState(dispatch)
|
|
return resolve(unlocked)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function forgetDevice (deviceName) {
|
|
log.debug(`background.forgetDevice`, deviceName)
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.forgetDevice(deviceName, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
forceUpdateMetamaskState(dispatch)
|
|
return resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function connectHardware (deviceName, page, hdPath) {
|
|
log.debug(`background.connectHardware`, deviceName, page, hdPath)
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.connectHardware(deviceName, page, hdPath, (err, accounts) => {
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
forceUpdateMetamaskState(dispatch)
|
|
return resolve(accounts)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function unlockHardwareWalletAccount (index, deviceName, hdPath) {
|
|
log.debug(`background.unlockHardwareWalletAccount`, index, deviceName, hdPath)
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.unlockHardwareWalletAccount(index, deviceName, hdPath, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.hideLoadingIndication())
|
|
return resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function showInfoPage () {
|
|
return {
|
|
type: actions.SHOW_INFO_PAGE,
|
|
}
|
|
}
|
|
|
|
function showQrScanner (ROUTE) {
|
|
return (dispatch) => {
|
|
return WebcamUtils.checkStatus()
|
|
.then(status => {
|
|
if (!status.environmentReady) {
|
|
// We need to switch to fullscreen mode to ask for permission
|
|
global.platform.openExtensionInBrowser(`${ROUTE}`, `scan=true`)
|
|
} else {
|
|
dispatch(actions.showModal({
|
|
name: 'QR_SCANNER',
|
|
}))
|
|
}
|
|
}).catch(e => {
|
|
dispatch(actions.showModal({
|
|
name: 'QR_SCANNER',
|
|
error: true,
|
|
errorType: e.type,
|
|
}))
|
|
})
|
|
}
|
|
}
|
|
|
|
function setCurrentCurrency (currencyCode) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.setCurrentCurrency`)
|
|
background.setCurrentCurrency(currencyCode, (err, data) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
log.error(err.stack)
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
dispatch({
|
|
type: actions.SET_CURRENT_FIAT,
|
|
value: {
|
|
currentCurrency: data.currentCurrency,
|
|
conversionRate: data.conversionRate,
|
|
conversionDate: data.conversionDate,
|
|
},
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function signMsg (msgData) {
|
|
log.debug('action - signMsg')
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
log.debug(`actions calling background.signMessage`)
|
|
background.signMessage(msgData, (err, newState) => {
|
|
log.debug('signMessage called back')
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.completedTx(msgData.metamaskId))
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return resolve(msgData)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function signPersonalMsg (msgData) {
|
|
log.debug('action - signPersonalMsg')
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
log.debug(`actions calling background.signPersonalMessage`)
|
|
background.signPersonalMessage(msgData, (err, newState) => {
|
|
log.debug('signPersonalMessage called back')
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.completedTx(msgData.metamaskId))
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return resolve(msgData)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function signTypedMsg (msgData) {
|
|
log.debug('action - signTypedMsg')
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
log.debug(`actions calling background.signTypedMessage`)
|
|
background.signTypedMessage(msgData, (err, newState) => {
|
|
log.debug('signTypedMessage called back')
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.completedTx(msgData.metamaskId))
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return resolve(msgData)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function signTx (txData) {
|
|
return (dispatch) => {
|
|
global.ethQuery.sendTransaction(txData, (err) => {
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
})
|
|
dispatch(actions.showConfTxPage({}))
|
|
}
|
|
}
|
|
|
|
function setGasLimit (gasLimit) {
|
|
return {
|
|
type: actions.UPDATE_GAS_LIMIT,
|
|
value: gasLimit,
|
|
}
|
|
}
|
|
|
|
function setGasPrice (gasPrice) {
|
|
return {
|
|
type: actions.UPDATE_GAS_PRICE,
|
|
value: gasPrice,
|
|
}
|
|
}
|
|
|
|
function setGasTotal (gasTotal) {
|
|
return {
|
|
type: actions.UPDATE_GAS_TOTAL,
|
|
value: gasTotal,
|
|
}
|
|
}
|
|
|
|
function updateGasData ({
|
|
gasPrice,
|
|
blockGasLimit,
|
|
selectedAddress,
|
|
selectedToken,
|
|
to,
|
|
value,
|
|
data,
|
|
}) {
|
|
return (dispatch) => {
|
|
dispatch(actions.gasLoadingStarted())
|
|
return estimateGas({
|
|
estimateGasMethod: background.estimateGas,
|
|
blockGasLimit,
|
|
selectedAddress,
|
|
selectedToken,
|
|
to,
|
|
value,
|
|
estimateGasPrice: gasPrice,
|
|
data,
|
|
})
|
|
.then(gas => {
|
|
dispatch(actions.setGasLimit(gas))
|
|
dispatch(gasDuck.setCustomGasLimit(gas))
|
|
dispatch(updateSendErrors({ gasLoadingError: null }))
|
|
dispatch(actions.gasLoadingFinished())
|
|
})
|
|
.catch(err => {
|
|
log.error(err)
|
|
dispatch(updateSendErrors({ gasLoadingError: 'gasLoadingError' }))
|
|
dispatch(actions.gasLoadingFinished())
|
|
})
|
|
}
|
|
}
|
|
|
|
function gasLoadingStarted () {
|
|
return {
|
|
type: actions.GAS_LOADING_STARTED,
|
|
}
|
|
}
|
|
|
|
function gasLoadingFinished () {
|
|
return {
|
|
type: actions.GAS_LOADING_FINISHED,
|
|
}
|
|
}
|
|
|
|
function updateSendTokenBalance ({
|
|
selectedToken,
|
|
tokenContract,
|
|
address,
|
|
}) {
|
|
return (dispatch) => {
|
|
const tokenBalancePromise = tokenContract
|
|
? tokenContract.balanceOf(address)
|
|
: Promise.resolve()
|
|
return tokenBalancePromise
|
|
.then(usersToken => {
|
|
if (usersToken) {
|
|
const newTokenBalance = calcTokenBalance({ selectedToken, usersToken })
|
|
dispatch(setSendTokenBalance(newTokenBalance))
|
|
}
|
|
})
|
|
.catch(err => {
|
|
log.error(err)
|
|
updateSendErrors({ tokenBalance: 'tokenBalanceError' })
|
|
})
|
|
}
|
|
}
|
|
|
|
function updateSendErrors (errorObject) {
|
|
return {
|
|
type: actions.UPDATE_SEND_ERRORS,
|
|
value: errorObject,
|
|
}
|
|
}
|
|
|
|
function setSendTokenBalance (tokenBalance) {
|
|
return {
|
|
type: actions.UPDATE_SEND_TOKEN_BALANCE,
|
|
value: tokenBalance,
|
|
}
|
|
}
|
|
|
|
function updateSendHexData (value) {
|
|
return {
|
|
type: actions.UPDATE_SEND_HEX_DATA,
|
|
value,
|
|
}
|
|
}
|
|
|
|
function updateSendTo (to, nickname = '') {
|
|
return {
|
|
type: actions.UPDATE_SEND_TO,
|
|
value: { to, nickname },
|
|
}
|
|
}
|
|
|
|
function updateSendAmount (amount) {
|
|
return {
|
|
type: actions.UPDATE_SEND_AMOUNT,
|
|
value: amount,
|
|
}
|
|
}
|
|
|
|
function updateCustomNonce (value) {
|
|
return {
|
|
type: actions.UPDATE_CUSTOM_NONCE,
|
|
value: value,
|
|
}
|
|
}
|
|
|
|
function updateSendMemo (memo) {
|
|
return {
|
|
type: actions.UPDATE_SEND_MEMO,
|
|
value: memo,
|
|
}
|
|
}
|
|
|
|
function setMaxModeTo (bool) {
|
|
return {
|
|
type: actions.UPDATE_MAX_MODE,
|
|
value: bool,
|
|
}
|
|
}
|
|
|
|
function updateSend (newSend) {
|
|
return {
|
|
type: actions.UPDATE_SEND,
|
|
value: newSend,
|
|
}
|
|
}
|
|
|
|
function clearSend () {
|
|
return {
|
|
type: actions.CLEAR_SEND,
|
|
}
|
|
}
|
|
|
|
function updateSendEnsResolution (ensResolution) {
|
|
return {
|
|
type: actions.UPDATE_SEND_ENS_RESOLUTION,
|
|
payload: ensResolution,
|
|
}
|
|
}
|
|
|
|
function updateSendEnsResolutionError (errorMessage) {
|
|
return {
|
|
type: actions.UPDATE_SEND_ENS_RESOLUTION_ERROR,
|
|
payload: errorMessage,
|
|
}
|
|
}
|
|
|
|
|
|
function sendTx (txData) {
|
|
log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`)
|
|
return (dispatch, getState) => {
|
|
log.debug(`actions calling background.approveTransaction`)
|
|
background.approveTransaction(txData.id, (err) => {
|
|
if (err) {
|
|
dispatch(actions.txError(err))
|
|
return log.error(err.message)
|
|
}
|
|
dispatch(actions.completedTx(txData.id))
|
|
|
|
if (global.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION &&
|
|
!hasUnconfirmedTransactions(getState())) {
|
|
return global.platform.closeCurrentWindow()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
function signTokenTx (tokenAddress, toAddress, amount, txData) {
|
|
return dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
const token = global.eth.contract(abi).at(tokenAddress)
|
|
token.transfer(toAddress, ethUtil.addHexPrefix(amount), txData)
|
|
.catch(err => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.displayWarning(err.message))
|
|
})
|
|
dispatch(actions.showConfTxPage({}))
|
|
}
|
|
}
|
|
|
|
const updateMetamaskStateFromBackground = () => {
|
|
log.debug(`background.getState`)
|
|
|
|
return new Promise((resolve, reject) => {
|
|
background.getState((error, newState) => {
|
|
if (error) {
|
|
return reject(error)
|
|
}
|
|
|
|
resolve(newState)
|
|
})
|
|
})
|
|
}
|
|
|
|
function updateTransaction (txData) {
|
|
log.info('actions: updateTx: ' + JSON.stringify(txData))
|
|
return dispatch => {
|
|
log.debug(`actions calling background.updateTx`)
|
|
dispatch(actions.showLoadingIndication())
|
|
|
|
return new Promise((resolve, reject) => {
|
|
background.updateTransaction(txData, (err) => {
|
|
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
|
|
if (err) {
|
|
dispatch(actions.txError(err))
|
|
dispatch(actions.goHome())
|
|
log.error(err.message)
|
|
return reject(err)
|
|
}
|
|
|
|
resolve(txData)
|
|
})
|
|
})
|
|
.then(() => updateMetamaskStateFromBackground())
|
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
|
.then(() => {
|
|
dispatch(actions.showConfTxPage({ id: txData.id }))
|
|
dispatch(actions.hideLoadingIndication())
|
|
return txData
|
|
})
|
|
}
|
|
}
|
|
|
|
function updateAndApproveTx (txData) {
|
|
log.info('actions: updateAndApproveTx: ' + JSON.stringify(txData))
|
|
return (dispatch) => {
|
|
log.debug(`actions calling background.updateAndApproveTx`)
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.updateAndApproveTransaction(txData, err => {
|
|
dispatch(actions.updateTransactionParams(txData.id, txData.txParams))
|
|
dispatch(actions.clearSend())
|
|
|
|
if (err) {
|
|
dispatch(actions.txError(err))
|
|
dispatch(actions.goHome())
|
|
log.error(err.message)
|
|
return reject(err)
|
|
}
|
|
|
|
resolve(txData)
|
|
})
|
|
})
|
|
.then(() => updateMetamaskStateFromBackground())
|
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
|
.then(() => {
|
|
dispatch(actions.clearSend())
|
|
dispatch(actions.completedTx(txData.id))
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.updateCustomNonce(''))
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return txData
|
|
})
|
|
.catch((err) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
return Promise.reject(err)
|
|
})
|
|
}
|
|
}
|
|
|
|
function completedTx (id) {
|
|
return {
|
|
type: actions.COMPLETED_TX,
|
|
value: id,
|
|
}
|
|
}
|
|
|
|
function updateTransactionParams (id, txParams) {
|
|
return {
|
|
type: actions.UPDATE_TRANSACTION_PARAMS,
|
|
id,
|
|
value: txParams,
|
|
}
|
|
}
|
|
|
|
function txError (err) {
|
|
return {
|
|
type: actions.TRANSACTION_ERROR,
|
|
message: err.message,
|
|
}
|
|
}
|
|
|
|
function cancelMsg (msgData) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
log.debug(`background.cancelMessage`)
|
|
background.cancelMessage(msgData.id, (err, newState) => {
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.completedTx(msgData.id))
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return resolve(msgData)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function cancelPersonalMsg (msgData) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
const id = msgData.id
|
|
background.cancelPersonalMessage(id, (err, newState) => {
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.completedTx(id))
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return resolve(msgData)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function cancelTypedMsg (msgData) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
const id = msgData.id
|
|
background.cancelTypedMessage(id, (err, newState) => {
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.completedTx(id))
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return resolve(msgData)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function cancelTx (txData) {
|
|
return (dispatch) => {
|
|
log.debug(`background.cancelTransaction`)
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.cancelTransaction(txData.id, err => {
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
|
|
resolve()
|
|
})
|
|
})
|
|
.then(() => updateMetamaskStateFromBackground())
|
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
|
.then(() => {
|
|
dispatch(actions.clearSend())
|
|
dispatch(actions.completedTx(txData.id))
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(closeCurrentNotificationWindow())
|
|
|
|
return txData
|
|
})
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Cancels all of the given transactions
|
|
* @param {Array<object>} txDataList a list of tx data objects
|
|
* @return {function(*): Promise<void>}
|
|
*/
|
|
function cancelTxs (txDataList) {
|
|
return async (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
const txIds = txDataList.map(({id}) => id)
|
|
const cancellations = txIds.map((id) => new Promise((resolve, reject) => {
|
|
background.cancelTransaction(id, (err) => {
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
|
|
resolve()
|
|
})
|
|
}))
|
|
|
|
await Promise.all(cancellations)
|
|
const newState = await updateMetamaskStateFromBackground()
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.clearSend())
|
|
|
|
txIds.forEach((id) => {
|
|
dispatch(actions.completedTx(id))
|
|
})
|
|
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (global.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) {
|
|
return global.platform.closeCurrentWindow()
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @deprecated
|
|
* @param {Array<object>} txsData
|
|
* @return {Function}
|
|
*/
|
|
function cancelAllTx (txsData) {
|
|
return (dispatch) => {
|
|
txsData.forEach((txData, i) => {
|
|
background.cancelTransaction(txData.id, () => {
|
|
dispatch(actions.completedTx(txData.id))
|
|
if (i === txsData.length - 1) {
|
|
dispatch(actions.goHome())
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
//
|
|
// initialize screen
|
|
//
|
|
|
|
function showCreateVault () {
|
|
return {
|
|
type: actions.SHOW_CREATE_VAULT,
|
|
}
|
|
}
|
|
|
|
function showRestoreVault () {
|
|
return {
|
|
type: actions.SHOW_RESTORE_VAULT,
|
|
}
|
|
}
|
|
|
|
function markPasswordForgotten () {
|
|
return (dispatch) => {
|
|
return background.markPasswordForgotten(() => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch(actions.forgotPassword())
|
|
forceUpdateMetamaskState(dispatch)
|
|
})
|
|
}
|
|
}
|
|
|
|
function unMarkPasswordForgotten () {
|
|
return dispatch => {
|
|
return new Promise(resolve => {
|
|
background.unMarkPasswordForgotten(() => {
|
|
dispatch(actions.forgotPassword(false))
|
|
resolve()
|
|
})
|
|
})
|
|
.then(() => forceUpdateMetamaskState(dispatch))
|
|
}
|
|
}
|
|
|
|
function forgotPassword (forgotPasswordState = true) {
|
|
return {
|
|
type: actions.FORGOT_PASSWORD,
|
|
value: forgotPasswordState,
|
|
}
|
|
}
|
|
|
|
function showInitializeMenu () {
|
|
return {
|
|
type: actions.SHOW_INIT_MENU,
|
|
}
|
|
}
|
|
|
|
function showImportPage () {
|
|
return {
|
|
type: actions.SHOW_IMPORT_PAGE,
|
|
}
|
|
}
|
|
|
|
function showNewAccountPage (formToSelect) {
|
|
return {
|
|
type: actions.SHOW_NEW_ACCOUNT_PAGE,
|
|
formToSelect,
|
|
}
|
|
}
|
|
|
|
function setNewAccountForm (formToSelect) {
|
|
return {
|
|
type: actions.SET_NEW_ACCOUNT_FORM,
|
|
formToSelect,
|
|
}
|
|
}
|
|
|
|
function createNewVaultInProgress () {
|
|
return {
|
|
type: actions.CREATE_NEW_VAULT_IN_PROGRESS,
|
|
}
|
|
}
|
|
|
|
function closeWelcomeScreen () {
|
|
return {
|
|
type: actions.CLOSE_WELCOME_SCREEN,
|
|
}
|
|
}
|
|
|
|
function backToUnlockView () {
|
|
return {
|
|
type: actions.BACK_TO_UNLOCK_VIEW,
|
|
}
|
|
}
|
|
|
|
function showNewKeychain () {
|
|
return {
|
|
type: actions.SHOW_NEW_KEYCHAIN,
|
|
}
|
|
}
|
|
|
|
//
|
|
// unlock screen
|
|
//
|
|
|
|
function unlockInProgress () {
|
|
return {
|
|
type: actions.UNLOCK_IN_PROGRESS,
|
|
}
|
|
}
|
|
|
|
function unlockFailed (message) {
|
|
return {
|
|
type: actions.UNLOCK_FAILED,
|
|
value: message,
|
|
}
|
|
}
|
|
|
|
function unlockSucceeded (message) {
|
|
return {
|
|
type: actions.UNLOCK_SUCCEEDED,
|
|
value: message,
|
|
}
|
|
}
|
|
|
|
function unlockMetamask (account) {
|
|
return {
|
|
type: actions.UNLOCK_METAMASK,
|
|
value: account,
|
|
}
|
|
}
|
|
|
|
function updateMetamaskState (newState) {
|
|
return {
|
|
type: actions.UPDATE_METAMASK_STATE,
|
|
value: newState,
|
|
}
|
|
}
|
|
|
|
const backgroundSetLocked = () => {
|
|
return new Promise((resolve, reject) => {
|
|
background.setLocked(error => {
|
|
if (error) {
|
|
return reject(error)
|
|
}
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
|
|
function lockMetamask () {
|
|
log.debug(`background.setLocked`)
|
|
|
|
return dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
|
|
return backgroundSetLocked()
|
|
.then(() => updateMetamaskStateFromBackground())
|
|
.catch(error => {
|
|
dispatch(actions.displayWarning(error.message))
|
|
return Promise.reject(error)
|
|
})
|
|
.then(newState => {
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch({ type: actions.LOCK_METAMASK })
|
|
})
|
|
.catch(() => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
dispatch({ type: actions.LOCK_METAMASK })
|
|
})
|
|
}
|
|
}
|
|
|
|
function setCurrentAccountTab (newTabName) {
|
|
log.debug(`background.setCurrentAccountTab: ${newTabName}`)
|
|
return callBackgroundThenUpdateNoSpinner(background.setCurrentAccountTab, newTabName)
|
|
}
|
|
|
|
function setSelectedToken (tokenAddress) {
|
|
return {
|
|
type: actions.SET_SELECTED_TOKEN,
|
|
value: tokenAddress || null,
|
|
}
|
|
}
|
|
|
|
function setSelectedAddress (address) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.setSelectedAddress`)
|
|
background.setSelectedAddress(address, (err) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
function showAccountDetail (address) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.setSelectedAddress`)
|
|
background.setSelectedAddress(address, (err, tokens) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
dispatch(updateTokens(tokens))
|
|
dispatch({
|
|
type: actions.SHOW_ACCOUNT_DETAIL,
|
|
value: address,
|
|
})
|
|
dispatch(actions.setSelectedToken())
|
|
})
|
|
}
|
|
}
|
|
|
|
function backToAccountDetail (address) {
|
|
return {
|
|
type: actions.BACK_TO_ACCOUNT_DETAIL,
|
|
value: address,
|
|
}
|
|
}
|
|
|
|
function showAccountsPage () {
|
|
return {
|
|
type: actions.SHOW_ACCOUNTS_PAGE,
|
|
}
|
|
}
|
|
|
|
function showConfTxPage ({transForward = true, id}) {
|
|
return {
|
|
type: actions.SHOW_CONF_TX_PAGE,
|
|
transForward,
|
|
id,
|
|
}
|
|
}
|
|
|
|
function nextTx () {
|
|
return {
|
|
type: actions.NEXT_TX,
|
|
}
|
|
}
|
|
|
|
function viewPendingTx (txId) {
|
|
return {
|
|
type: actions.VIEW_PENDING_TX,
|
|
value: txId,
|
|
}
|
|
}
|
|
|
|
function previousTx () {
|
|
return {
|
|
type: actions.PREVIOUS_TX,
|
|
}
|
|
}
|
|
|
|
function editTx (txId) {
|
|
return {
|
|
type: actions.EDIT_TX,
|
|
value: txId,
|
|
}
|
|
}
|
|
|
|
function showConfigPage (transitionForward = true) {
|
|
return {
|
|
type: actions.SHOW_CONFIG_PAGE,
|
|
value: transitionForward,
|
|
}
|
|
}
|
|
|
|
function showAddTokenPage (transitionForward = true) {
|
|
return {
|
|
type: actions.SHOW_ADD_TOKEN_PAGE,
|
|
value: transitionForward,
|
|
}
|
|
}
|
|
|
|
function showAddSuggestedTokenPage (transitionForward = true) {
|
|
return {
|
|
type: actions.SHOW_ADD_SUGGESTED_TOKEN_PAGE,
|
|
value: transitionForward,
|
|
}
|
|
}
|
|
|
|
function addToken (address, symbol, decimals, image) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.addToken(address, symbol, decimals, image, (err, tokens) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
dispatch(actions.updateTokens(tokens))
|
|
resolve(tokens)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function removeToken (address) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.removeToken(address, (err, tokens) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
dispatch(actions.updateTokens(tokens))
|
|
resolve(tokens)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function addTokens (tokens) {
|
|
return dispatch => {
|
|
if (Array.isArray(tokens)) {
|
|
dispatch(actions.setSelectedToken(getTokenAddressFromTokenObject(tokens[0])))
|
|
return Promise.all(tokens.map(({ address, symbol, decimals }) => (
|
|
dispatch(addToken(address, symbol, decimals))
|
|
)))
|
|
} else {
|
|
dispatch(actions.setSelectedToken(getTokenAddressFromTokenObject(tokens)))
|
|
return Promise.all(
|
|
Object
|
|
.entries(tokens)
|
|
.map(([_, { address, symbol, decimals }]) => (
|
|
dispatch(addToken(address, symbol, decimals))
|
|
))
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
function removeSuggestedTokens () {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve) => {
|
|
background.removeSuggestedTokens((err, suggestedTokens) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
}
|
|
dispatch(actions.clearPendingTokens())
|
|
if (global.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION) {
|
|
return global.platform.closeCurrentWindow()
|
|
}
|
|
resolve(suggestedTokens)
|
|
})
|
|
})
|
|
.then(() => updateMetamaskStateFromBackground())
|
|
.then(suggestedTokens => dispatch(actions.updateMetamaskState({...suggestedTokens})))
|
|
}
|
|
}
|
|
|
|
function addKnownMethodData (fourBytePrefix, methodData) {
|
|
return () => {
|
|
background.addKnownMethodData(fourBytePrefix, methodData)
|
|
}
|
|
}
|
|
|
|
function updateTokens (newTokens) {
|
|
return {
|
|
type: actions.UPDATE_TOKENS,
|
|
newTokens,
|
|
}
|
|
}
|
|
|
|
function clearPendingTokens () {
|
|
return {
|
|
type: actions.CLEAR_PENDING_TOKENS,
|
|
}
|
|
}
|
|
|
|
function goBackToInitView () {
|
|
return {
|
|
type: actions.BACK_TO_INIT_MENU,
|
|
}
|
|
}
|
|
|
|
function markAccountsFound () {
|
|
log.debug(`background.markAccountsFound`)
|
|
return callBackgroundThenUpdate(background.markAccountsFound)
|
|
}
|
|
|
|
function retryTransaction (txId, gasPrice) {
|
|
log.debug(`background.retryTransaction`)
|
|
let newTxId
|
|
|
|
return dispatch => {
|
|
return new Promise((resolve, reject) => {
|
|
background.retryTransaction(txId, gasPrice, (err, newState) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
const { selectedAddressTxList } = newState
|
|
const { id } = selectedAddressTxList[selectedAddressTxList.length - 1]
|
|
newTxId = id
|
|
resolve(newState)
|
|
})
|
|
})
|
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
|
.then(() => newTxId)
|
|
}
|
|
}
|
|
|
|
function createCancelTransaction (txId, customGasPrice) {
|
|
log.debug('background.cancelTransaction')
|
|
let newTxId
|
|
|
|
return dispatch => {
|
|
return new Promise((resolve, reject) => {
|
|
background.createCancelTransaction(txId, customGasPrice, (err, newState) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
const { selectedAddressTxList } = newState
|
|
const { id } = selectedAddressTxList[selectedAddressTxList.length - 1]
|
|
newTxId = id
|
|
resolve(newState)
|
|
})
|
|
})
|
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
|
.then(() => newTxId)
|
|
}
|
|
}
|
|
|
|
function createSpeedUpTransaction (txId, customGasPrice) {
|
|
log.debug('background.createSpeedUpTransaction')
|
|
let newTx
|
|
|
|
return dispatch => {
|
|
return new Promise((resolve, reject) => {
|
|
background.createSpeedUpTransaction(txId, customGasPrice, (err, newState) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
const { selectedAddressTxList } = newState
|
|
newTx = selectedAddressTxList[selectedAddressTxList.length - 1]
|
|
resolve(newState)
|
|
})
|
|
})
|
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
|
.then(() => newTx)
|
|
}
|
|
}
|
|
|
|
function createRetryTransaction (txId, customGasPrice) {
|
|
log.debug('background.createRetryTransaction')
|
|
let newTx
|
|
|
|
return dispatch => {
|
|
return new Promise((resolve, reject) => {
|
|
background.createSpeedUpTransaction(txId, customGasPrice, (err, newState) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
const { selectedAddressTxList } = newState
|
|
newTx = selectedAddressTxList[selectedAddressTxList.length - 1]
|
|
resolve(newState)
|
|
})
|
|
})
|
|
.then(newState => dispatch(actions.updateMetamaskState(newState)))
|
|
.then(() => newTx)
|
|
}
|
|
}
|
|
|
|
//
|
|
// config
|
|
//
|
|
|
|
function setProviderType (type) {
|
|
return (dispatch, getState) => {
|
|
const { type: currentProviderType } = getState().metamask.provider
|
|
log.debug(`background.setProviderType`, type)
|
|
background.setProviderType(type, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
return dispatch(actions.displayWarning('Had a problem changing networks!'))
|
|
}
|
|
dispatch(setPreviousProvider(currentProviderType))
|
|
dispatch(actions.updateProviderType(type))
|
|
dispatch(actions.setSelectedToken())
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
function updateProviderType (type) {
|
|
return {
|
|
type: actions.SET_PROVIDER_TYPE,
|
|
value: type,
|
|
}
|
|
}
|
|
|
|
function setPreviousProvider (type) {
|
|
return {
|
|
type: actions.SET_PREVIOUS_PROVIDER,
|
|
value: type,
|
|
}
|
|
}
|
|
|
|
function updateAndSetCustomRpc (newRpc, chainId, ticker = 'ETH', nickname, rpcPrefs) {
|
|
return (dispatch) => {
|
|
log.debug(`background.updateAndSetCustomRpc: ${newRpc} ${chainId} ${ticker} ${nickname}`)
|
|
background.updateAndSetCustomRpc(newRpc, chainId, ticker, nickname || newRpc, rpcPrefs, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
return dispatch(actions.displayWarning('Had a problem changing networks!'))
|
|
}
|
|
dispatch({
|
|
type: actions.SET_RPC_TARGET,
|
|
value: newRpc,
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function editRpc (oldRpc, newRpc, chainId, ticker = 'ETH', nickname, rpcPrefs) {
|
|
return (dispatch) => {
|
|
log.debug(`background.delRpcTarget: ${oldRpc}`)
|
|
background.delCustomRpc(oldRpc, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
return dispatch(self.displayWarning('Had a problem removing network!'))
|
|
}
|
|
dispatch(actions.setSelectedToken())
|
|
background.updateAndSetCustomRpc(newRpc, chainId, ticker, nickname || newRpc, rpcPrefs, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
return dispatch(actions.displayWarning('Had a problem changing networks!'))
|
|
}
|
|
dispatch({
|
|
type: actions.SET_RPC_TARGET,
|
|
value: newRpc,
|
|
})
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function setRpcTarget (newRpc, chainId, ticker = 'ETH', nickname) {
|
|
return (dispatch) => {
|
|
log.debug(`background.setRpcTarget: ${newRpc} ${chainId} ${ticker} ${nickname}`)
|
|
background.setCustomRpc(newRpc, chainId, ticker, nickname || newRpc, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
return dispatch(actions.displayWarning('Had a problem changing networks!'))
|
|
}
|
|
dispatch(actions.setSelectedToken())
|
|
})
|
|
}
|
|
}
|
|
|
|
function delRpcTarget (oldRpc) {
|
|
return (dispatch) => {
|
|
log.debug(`background.delRpcTarget: ${oldRpc}`)
|
|
return new Promise((resolve, reject) => {
|
|
background.delCustomRpc(oldRpc, (err) => {
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(self.displayWarning('Had a problem removing network!'))
|
|
return reject(err)
|
|
}
|
|
dispatch(actions.setSelectedToken())
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
// Calls the addressBookController to add a new address.
|
|
function addToAddressBook (recipient, nickname = '', memo = '') {
|
|
log.debug(`background.addToAddressBook`)
|
|
|
|
return (dispatch, getState) => {
|
|
const chainId = getState().metamask.network
|
|
background.setAddressBook(checksumAddress(recipient), nickname, chainId, memo, (err, set) => {
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(displayWarning('Address book failed to update'))
|
|
throw err
|
|
}
|
|
if (!set) {
|
|
return dispatch(displayWarning('Address book failed to update'))
|
|
}
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @description Calls the addressBookController to remove an existing address.
|
|
* @param {String} addressToRemove - Address of the entry to remove from the address book
|
|
*/
|
|
function removeFromAddressBook (chainId, addressToRemove) {
|
|
log.debug(`background.removeFromAddressBook`)
|
|
|
|
return () => {
|
|
background.removeFromAddressBook(chainId, checksumAddress(addressToRemove))
|
|
}
|
|
}
|
|
|
|
function useEtherscanProvider () {
|
|
log.debug(`background.useEtherscanProvider`)
|
|
background.useEtherscanProvider()
|
|
return {
|
|
type: actions.USE_ETHERSCAN_PROVIDER,
|
|
}
|
|
}
|
|
|
|
function showNetworkDropdown () {
|
|
return {
|
|
type: actions.NETWORK_DROPDOWN_OPEN,
|
|
}
|
|
}
|
|
|
|
function hideNetworkDropdown () {
|
|
return {
|
|
type: actions.NETWORK_DROPDOWN_CLOSE,
|
|
}
|
|
}
|
|
|
|
|
|
function showModal (payload) {
|
|
return {
|
|
type: actions.MODAL_OPEN,
|
|
payload,
|
|
}
|
|
}
|
|
|
|
function hideModal (payload) {
|
|
return {
|
|
type: actions.MODAL_CLOSE,
|
|
payload,
|
|
}
|
|
}
|
|
|
|
function closeCurrentNotificationWindow () {
|
|
return (dispatch, getState) => {
|
|
if (global.METAMASK_UI_TYPE === ENVIRONMENT_TYPE_NOTIFICATION &&
|
|
!hasUnconfirmedTransactions(getState())) {
|
|
global.platform.closeCurrentWindow()
|
|
|
|
dispatch(closeNotifacationWindow())
|
|
}
|
|
}
|
|
}
|
|
|
|
function closeNotifacationWindow () {
|
|
return {
|
|
type: actions.CLOSE_NOTIFICATION_WINDOW,
|
|
}
|
|
}
|
|
|
|
function showSidebar ({ transitionName, type, props }) {
|
|
return {
|
|
type: actions.SIDEBAR_OPEN,
|
|
value: {
|
|
transitionName,
|
|
type,
|
|
props,
|
|
},
|
|
}
|
|
}
|
|
|
|
function hideSidebar () {
|
|
return {
|
|
type: actions.SIDEBAR_CLOSE,
|
|
}
|
|
}
|
|
|
|
function showAlert (msg) {
|
|
return {
|
|
type: actions.ALERT_OPEN,
|
|
value: msg,
|
|
}
|
|
}
|
|
|
|
function hideAlert () {
|
|
return {
|
|
type: actions.ALERT_CLOSE,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This action will receive two types of values via qrCodeData
|
|
* an object with the following structure {type, values}
|
|
* or null (used to clear the previous value)
|
|
*/
|
|
function qrCodeDetected (qrCodeData) {
|
|
return {
|
|
type: actions.QR_CODE_DETECTED,
|
|
value: qrCodeData,
|
|
}
|
|
}
|
|
|
|
function showLoadingIndication (message) {
|
|
return {
|
|
type: actions.SHOW_LOADING,
|
|
value: message,
|
|
}
|
|
}
|
|
|
|
function setHardwareWalletDefaultHdPath ({ device, path }) {
|
|
return {
|
|
type: actions.SET_HARDWARE_WALLET_DEFAULT_HD_PATH,
|
|
value: {device, path},
|
|
}
|
|
}
|
|
|
|
function hideLoadingIndication () {
|
|
return {
|
|
type: actions.HIDE_LOADING,
|
|
}
|
|
}
|
|
|
|
function showSubLoadingIndication () {
|
|
return {
|
|
type: actions.SHOW_SUB_LOADING_INDICATION,
|
|
}
|
|
}
|
|
|
|
function hideSubLoadingIndication () {
|
|
return {
|
|
type: actions.HIDE_SUB_LOADING_INDICATION,
|
|
}
|
|
}
|
|
|
|
function displayWarning (text) {
|
|
return {
|
|
type: actions.DISPLAY_WARNING,
|
|
value: text,
|
|
}
|
|
}
|
|
|
|
function hideWarning () {
|
|
return {
|
|
type: actions.HIDE_WARNING,
|
|
}
|
|
}
|
|
|
|
function requestExportAccount () {
|
|
return {
|
|
type: actions.REQUEST_ACCOUNT_EXPORT,
|
|
}
|
|
}
|
|
|
|
function exportAccount (password, address) {
|
|
var self = this
|
|
|
|
return function (dispatch) {
|
|
dispatch(self.showLoadingIndication())
|
|
|
|
log.debug(`background.submitPassword`)
|
|
return new Promise((resolve, reject) => {
|
|
background.submitPassword(password, function (err) {
|
|
if (err) {
|
|
log.error('Error in submiting password.')
|
|
dispatch(self.hideLoadingIndication())
|
|
dispatch(self.displayWarning('Incorrect Password.'))
|
|
return reject(err)
|
|
}
|
|
log.debug(`background.exportAccount`)
|
|
return background.exportAccount(address, function (err, result) {
|
|
dispatch(self.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
log.error(err)
|
|
dispatch(self.displayWarning('Had a problem exporting the account.'))
|
|
return reject(err)
|
|
}
|
|
|
|
// dispatch(self.exportAccountComplete())
|
|
dispatch(self.showPrivateKey(result))
|
|
|
|
return resolve(result)
|
|
})
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function exportAccountComplete () {
|
|
return {
|
|
type: actions.EXPORT_ACCOUNT,
|
|
}
|
|
}
|
|
|
|
function showPrivateKey (key) {
|
|
return {
|
|
type: actions.SHOW_PRIVATE_KEY,
|
|
value: key,
|
|
}
|
|
}
|
|
|
|
function setAccountLabel (account, label) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.setAccountLabel`)
|
|
|
|
return new Promise((resolve, reject) => {
|
|
background.setAccountLabel(account, label, (err) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch({
|
|
type: actions.SET_ACCOUNT_LABEL,
|
|
value: { account, label },
|
|
})
|
|
|
|
resolve(account)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function showSendPage () {
|
|
return {
|
|
type: actions.SHOW_SEND_PAGE,
|
|
}
|
|
}
|
|
|
|
function showSendTokenPage () {
|
|
return {
|
|
type: actions.SHOW_SEND_TOKEN_PAGE,
|
|
}
|
|
}
|
|
|
|
function buyEth (opts) {
|
|
return (dispatch) => {
|
|
const url = getBuyEthUrl(opts)
|
|
global.platform.openWindow({ url })
|
|
dispatch({
|
|
type: actions.BUY_ETH,
|
|
})
|
|
}
|
|
}
|
|
|
|
function onboardingBuyEthView (address) {
|
|
return {
|
|
type: actions.ONBOARDING_BUY_ETH_VIEW,
|
|
value: address,
|
|
}
|
|
}
|
|
|
|
function buyEthView (address) {
|
|
return {
|
|
type: actions.BUY_ETH_VIEW,
|
|
value: address,
|
|
}
|
|
}
|
|
|
|
function coinBaseSubview () {
|
|
return {
|
|
type: actions.COINBASE_SUBVIEW,
|
|
}
|
|
}
|
|
|
|
function pairUpdate (coin) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showSubLoadingIndication())
|
|
dispatch(actions.hideWarning())
|
|
shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => {
|
|
dispatch(actions.hideSubLoadingIndication())
|
|
if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error))
|
|
dispatch({
|
|
type: actions.PAIR_UPDATE,
|
|
value: {
|
|
marketinfo: mktResponse,
|
|
},
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function shapeShiftSubview () {
|
|
var pair = 'btc_eth'
|
|
return (dispatch) => {
|
|
dispatch(actions.showSubLoadingIndication())
|
|
shapeShiftRequest('marketinfo', {pair}, (mktResponse) => {
|
|
shapeShiftRequest('getcoins', {}, (response) => {
|
|
dispatch(actions.hideSubLoadingIndication())
|
|
if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error))
|
|
dispatch({
|
|
type: actions.SHAPESHIFT_SUBVIEW,
|
|
value: {
|
|
marketinfo: mktResponse,
|
|
coinOptions: response,
|
|
},
|
|
})
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function coinShiftRquest (data, marketData) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
shapeShiftRequest('shift', { method: 'POST', data}, (response) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (response.error) return dispatch(actions.displayWarning(response.error))
|
|
var message = `
|
|
Deposit your ${response.depositType} to the address below:`
|
|
log.debug(`background.createShapeShiftTx`)
|
|
background.createShapeShiftTx(response.deposit, response.depositType)
|
|
dispatch(actions.showQrView(response.deposit, [message].concat(marketData)))
|
|
})
|
|
}
|
|
}
|
|
|
|
function buyWithShapeShift (data) {
|
|
return () => new Promise((resolve, reject) => {
|
|
shapeShiftRequest('shift', { method: 'POST', data}, (response) => {
|
|
if (response.error) {
|
|
return reject(response.error)
|
|
}
|
|
background.createShapeShiftTx(response.deposit, response.depositType)
|
|
return resolve(response)
|
|
})
|
|
})
|
|
}
|
|
|
|
function showQrView (data, message) {
|
|
return {
|
|
type: actions.SHOW_QR_VIEW,
|
|
value: {
|
|
message: message,
|
|
data: data,
|
|
},
|
|
}
|
|
}
|
|
function reshowQrCode (data, coin) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => {
|
|
if (mktResponse.error) return dispatch(actions.displayWarning(mktResponse.error))
|
|
|
|
var message = [
|
|
`Deposit your ${coin} to the address below:`,
|
|
`Deposit Limit: ${mktResponse.limit}`,
|
|
`Deposit Minimum:${mktResponse.minimum}`,
|
|
]
|
|
|
|
dispatch(actions.hideLoadingIndication())
|
|
return dispatch(actions.showQrView(data, message))
|
|
})
|
|
}
|
|
}
|
|
|
|
function shapeShiftRequest (query, options = {}, cb) {
|
|
var queryResponse, method
|
|
options.method ? method = options.method : method = 'GET'
|
|
|
|
var requestListner = function () {
|
|
try {
|
|
queryResponse = JSON.parse(this.responseText)
|
|
if (cb) {
|
|
cb(queryResponse)
|
|
}
|
|
return queryResponse
|
|
} catch (e) {
|
|
if (cb) {
|
|
cb({error: e})
|
|
}
|
|
return e
|
|
}
|
|
}
|
|
|
|
var shapShiftReq = new XMLHttpRequest()
|
|
shapShiftReq.addEventListener('load', requestListner)
|
|
shapShiftReq.open(method, `https://shapeshift.io/${query}/${options.pair ? options.pair : ''}`, true)
|
|
|
|
if (options.method === 'POST') {
|
|
var jsonObj = JSON.stringify(options.data)
|
|
shapShiftReq.setRequestHeader('Content-Type', 'application/json')
|
|
return shapShiftReq.send(jsonObj)
|
|
} else {
|
|
return shapShiftReq.send()
|
|
}
|
|
}
|
|
|
|
function setFeatureFlag (feature, activated, notificationType) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.setFeatureFlag(feature, activated, (err, updatedFeatureFlags) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
dispatch(actions.updateFeatureFlags(updatedFeatureFlags))
|
|
notificationType && dispatch(actions.showModal({ name: notificationType }))
|
|
resolve(updatedFeatureFlags)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function updateFeatureFlags (updatedFeatureFlags) {
|
|
return {
|
|
type: actions.UPDATE_FEATURE_FLAGS,
|
|
value: updatedFeatureFlags,
|
|
}
|
|
}
|
|
|
|
function setPreference (preference, value) {
|
|
return dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return new Promise((resolve, reject) => {
|
|
background.setPreference(preference, value, (err, updatedPreferences) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.updatePreferences(updatedPreferences))
|
|
resolve(updatedPreferences)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function updatePreferences (value) {
|
|
return {
|
|
type: actions.UPDATE_PREFERENCES,
|
|
value,
|
|
}
|
|
}
|
|
|
|
function setUseNativeCurrencyAsPrimaryCurrencyPreference (value) {
|
|
return setPreference('useNativeCurrencyAsPrimaryCurrency', value)
|
|
}
|
|
|
|
function setShowFiatConversionOnTestnetsPreference (value) {
|
|
return setPreference('showFiatInTestnets', value)
|
|
}
|
|
|
|
function setAutoLogoutTimeLimit (value) {
|
|
return setPreference('autoLogoutTimeLimit', value)
|
|
}
|
|
|
|
function setCompletedOnboarding () {
|
|
return async dispatch => {
|
|
dispatch(actions.showLoadingIndication())
|
|
|
|
try {
|
|
await pify(background.completeOnboarding).call(background)
|
|
} catch (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
throw err
|
|
}
|
|
|
|
dispatch(actions.completeOnboarding())
|
|
dispatch(actions.hideLoadingIndication())
|
|
}
|
|
}
|
|
|
|
function completeOnboarding () {
|
|
return {
|
|
type: actions.COMPLETE_ONBOARDING,
|
|
}
|
|
}
|
|
|
|
function setNetworkNonce (networkNonce) {
|
|
return {
|
|
type: actions.SET_NETWORK_NONCE,
|
|
value: networkNonce,
|
|
}
|
|
}
|
|
|
|
function updateNetworkNonce (address) {
|
|
return (dispatch) => {
|
|
return new Promise((resolve, reject) => {
|
|
global.ethQuery.getTransactionCount(address, (err, data) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
dispatch(setNetworkNonce(data))
|
|
resolve(data)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function setMouseUserState (isMouseUser) {
|
|
return {
|
|
type: actions.SET_MOUSE_USER_STATE,
|
|
value: isMouseUser,
|
|
}
|
|
}
|
|
|
|
// Call Background Then Update
|
|
//
|
|
// A function generator for a common pattern wherein:
|
|
// We show loading indication.
|
|
// We call a background method.
|
|
// We hide loading indication.
|
|
// If it errored, we show a warning.
|
|
// If it didn't, we update the state.
|
|
function callBackgroundThenUpdateNoSpinner (method, ...args) {
|
|
return (dispatch) => {
|
|
method.call(background, ...args, (err) => {
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
forceUpdateMetamaskState(dispatch)
|
|
})
|
|
}
|
|
}
|
|
|
|
function callBackgroundThenUpdate (method, ...args) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
method.call(background, ...args, (err) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
forceUpdateMetamaskState(dispatch)
|
|
})
|
|
}
|
|
}
|
|
|
|
function forceUpdateMetamaskState (dispatch) {
|
|
log.debug(`background.getState`)
|
|
return new Promise((resolve, reject) => {
|
|
background.getState((err, newState) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch(actions.updateMetamaskState(newState))
|
|
resolve(newState)
|
|
})
|
|
})
|
|
}
|
|
|
|
function toggleAccountMenu () {
|
|
return {
|
|
type: actions.TOGGLE_ACCOUNT_MENU,
|
|
}
|
|
}
|
|
|
|
function setParticipateInMetaMetrics (val) {
|
|
return (dispatch) => {
|
|
log.debug(`background.setParticipateInMetaMetrics`)
|
|
return new Promise((resolve, reject) => {
|
|
background.setParticipateInMetaMetrics(val, (err, metaMetricsId) => {
|
|
log.debug(err)
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch({
|
|
type: actions.SET_PARTICIPATE_IN_METAMETRICS,
|
|
value: val,
|
|
})
|
|
|
|
resolve([val, metaMetricsId])
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function setMetaMetricsSendCount (val) {
|
|
return (dispatch) => {
|
|
log.debug(`background.setMetaMetricsSendCount`)
|
|
return new Promise((resolve, reject) => {
|
|
background.setMetaMetricsSendCount(val, (err) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
|
|
dispatch({
|
|
type: actions.SET_METAMETRICS_SEND_COUNT,
|
|
value: val,
|
|
})
|
|
|
|
resolve(val)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function setUseBlockie (val) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.setUseBlockie`)
|
|
background.setUseBlockie(val, (err) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
})
|
|
dispatch({
|
|
type: actions.SET_USE_BLOCKIE,
|
|
value: val,
|
|
})
|
|
}
|
|
}
|
|
|
|
function setUseNonceField (val) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
log.debug(`background.setUseNonceField`)
|
|
background.setUseNonceField(val, (err) => {
|
|
dispatch(actions.hideLoadingIndication())
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
})
|
|
dispatch({
|
|
type: actions.SET_USE_NONCEFIELD,
|
|
value: val,
|
|
})
|
|
}
|
|
}
|
|
|
|
function updateCurrentLocale (key) {
|
|
return (dispatch) => {
|
|
dispatch(actions.showLoadingIndication())
|
|
return fetchLocale(key)
|
|
.then((localeMessages) => {
|
|
log.debug(`background.setCurrentLocale`)
|
|
background.setCurrentLocale(key, (err, textDirection) => {
|
|
if (err) {
|
|
dispatch(actions.hideLoadingIndication())
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
switchDirection(textDirection)
|
|
dispatch(actions.setCurrentLocale(key, localeMessages))
|
|
dispatch(actions.hideLoadingIndication())
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function setCurrentLocale (locale, messages) {
|
|
return {
|
|
type: actions.SET_CURRENT_LOCALE,
|
|
value: {
|
|
locale,
|
|
messages,
|
|
},
|
|
}
|
|
}
|
|
|
|
function updateNetworkEndpointType (networkEndpointType) {
|
|
return {
|
|
type: actions.UPDATE_NETWORK_ENDPOINT_TYPE,
|
|
value: networkEndpointType,
|
|
}
|
|
}
|
|
|
|
function setPendingTokens (pendingTokens) {
|
|
const { customToken = {}, selectedTokens = {} } = pendingTokens
|
|
const { address, symbol, decimals } = customToken
|
|
const tokens = address && symbol && decimals
|
|
? { ...selectedTokens, [address]: { ...customToken, isCustom: true } }
|
|
: selectedTokens
|
|
|
|
return {
|
|
type: actions.SET_PENDING_TOKENS,
|
|
payload: tokens,
|
|
}
|
|
}
|
|
|
|
function approveProviderRequestByOrigin (origin) {
|
|
return () => {
|
|
background.approveProviderRequestByOrigin(origin)
|
|
}
|
|
}
|
|
|
|
function rejectProviderRequestByOrigin (origin) {
|
|
return () => {
|
|
background.rejectProviderRequestByOrigin(origin)
|
|
}
|
|
}
|
|
|
|
function clearApprovedOrigins () {
|
|
return () => {
|
|
background.clearApprovedOrigins()
|
|
}
|
|
}
|
|
|
|
function setFirstTimeFlowType (type) {
|
|
return (dispatch) => {
|
|
log.debug(`background.setFirstTimeFlowType`)
|
|
background.setFirstTimeFlowType(type, (err) => {
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
})
|
|
dispatch({
|
|
type: actions.SET_FIRST_TIME_FLOW_TYPE,
|
|
value: type,
|
|
})
|
|
}
|
|
}
|
|
|
|
function setSelectedSettingsRpcUrl (newRpcUrl) {
|
|
return {
|
|
type: actions.SET_SELECTED_SETTINGS_RPC_URL,
|
|
value: newRpcUrl,
|
|
}
|
|
}
|
|
|
|
function setNetworksTabAddMode (isInAddMode) {
|
|
return {
|
|
type: actions.SET_NETWORKS_TAB_ADD_MODE,
|
|
value: isInAddMode,
|
|
}
|
|
}
|
|
|
|
function setLastActiveTime () {
|
|
return (dispatch) => {
|
|
background.setLastActiveTime((err) => {
|
|
if (err) {
|
|
return dispatch(actions.displayWarning(err.message))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
function loadingMethoDataStarted () {
|
|
return {
|
|
type: actions.LOADING_METHOD_DATA_STARTED,
|
|
}
|
|
}
|
|
|
|
function loadingMethoDataFinished () {
|
|
return {
|
|
type: actions.LOADING_METHOD_DATA_FINISHED,
|
|
}
|
|
}
|
|
|
|
function getContractMethodData (data = '') {
|
|
return (dispatch, getState) => {
|
|
const prefixedData = ethUtil.addHexPrefix(data)
|
|
const fourBytePrefix = prefixedData.slice(0, 10)
|
|
const { knownMethodData } = getState().metamask
|
|
if (knownMethodData && knownMethodData[fourBytePrefix]) {
|
|
return Promise.resolve(knownMethodData[fourBytePrefix])
|
|
}
|
|
|
|
dispatch(actions.loadingMethoDataStarted())
|
|
log.debug(`loadingMethodData`)
|
|
|
|
return getMethodDataAsync(fourBytePrefix)
|
|
.then(({ name, params }) => {
|
|
dispatch(actions.loadingMethoDataFinished())
|
|
|
|
background.addKnownMethodData(fourBytePrefix, { name, params })
|
|
|
|
return { name, params }
|
|
})
|
|
}
|
|
}
|
|
|
|
function loadingTokenParamsStarted () {
|
|
return {
|
|
type: actions.LOADING_TOKEN_PARAMS_STARTED,
|
|
}
|
|
}
|
|
|
|
function loadingTokenParamsFinished () {
|
|
return {
|
|
type: actions.LOADING_TOKEN_PARAMS_FINISHED,
|
|
}
|
|
}
|
|
|
|
function getTokenParams (tokenAddress) {
|
|
return (dispatch, getState) => {
|
|
const existingTokens = getState().metamask.tokens
|
|
const existingToken = existingTokens.find(({ address }) => tokenAddress === address)
|
|
|
|
if (existingToken) {
|
|
return Promise.resolve({
|
|
symbol: existingToken.symbol,
|
|
decimals: existingToken.decimals,
|
|
})
|
|
}
|
|
|
|
dispatch(actions.loadingTokenParamsStarted())
|
|
log.debug(`loadingTokenParams`)
|
|
|
|
|
|
return fetchSymbolAndDecimals(tokenAddress, existingTokens)
|
|
.then(({ symbol, decimals }) => {
|
|
dispatch(actions.addToken(tokenAddress, symbol, decimals))
|
|
dispatch(actions.loadingTokenParamsFinished())
|
|
})
|
|
}
|
|
}
|
|
|
|
function unsetMigratedPrivacyMode () {
|
|
return () => {
|
|
background.unsetMigratedPrivacyMode()
|
|
}
|
|
}
|
|
|
|
function setSeedPhraseBackedUp (seedPhraseBackupState) {
|
|
return (dispatch) => {
|
|
log.debug(`background.setSeedPhraseBackedUp`)
|
|
return new Promise((resolve, reject) => {
|
|
background.setSeedPhraseBackedUp(seedPhraseBackupState, (err) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
return forceUpdateMetamaskState(dispatch)
|
|
.then(resolve)
|
|
.catch(reject)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function hideSeedPhraseBackupAfterOnboarding () {
|
|
return {
|
|
type: actions.HIDE_SEED_PHRASE_BACKUP_AFTER_ONBOARDING,
|
|
}
|
|
}
|
|
|
|
function initializeThreeBox () {
|
|
return (dispatch) => {
|
|
return new Promise((resolve, reject) => {
|
|
background.initializeThreeBox((err) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function setShowRestorePromptToFalse () {
|
|
return (dispatch) => {
|
|
return new Promise((resolve, reject) => {
|
|
background.setShowRestorePromptToFalse((err) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function turnThreeBoxSyncingOn () {
|
|
return (dispatch) => {
|
|
return new Promise((resolve, reject) => {
|
|
background.turnThreeBoxSyncingOn((err) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function restoreFromThreeBox (accountAddress) {
|
|
return (dispatch) => {
|
|
return new Promise((resolve, reject) => {
|
|
background.restoreFromThreeBox(accountAddress, (err) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function getThreeBoxLastUpdated () {
|
|
return (dispatch) => {
|
|
return new Promise((resolve, reject) => {
|
|
background.getThreeBoxLastUpdated((err, lastUpdated) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
resolve(lastUpdated)
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function setThreeBoxSyncingPermission (threeBoxSyncingAllowed) {
|
|
return (dispatch) => {
|
|
return new Promise((resolve, reject) => {
|
|
background.setThreeBoxSyncingPermission(threeBoxSyncingAllowed, (err) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
resolve()
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
function turnThreeBoxSyncingOnAndInitialize () {
|
|
return async (dispatch) => {
|
|
await dispatch(setThreeBoxSyncingPermission(true))
|
|
await dispatch(turnThreeBoxSyncingOn())
|
|
await dispatch(initializeThreeBox(true))
|
|
}
|
|
}
|
|
|
|
function setNextNonce (nextNonce) {
|
|
return {
|
|
type: actions.SET_NEXT_NONCE,
|
|
value: nextNonce,
|
|
}
|
|
}
|
|
|
|
function getNextNonce () {
|
|
return (dispatch, getState) => {
|
|
const address = getState().metamask.selectedAddress
|
|
return new Promise((resolve, reject) => {
|
|
background.getNextNonce(address, (err, nextNonce) => {
|
|
if (err) {
|
|
dispatch(actions.displayWarning(err.message))
|
|
return reject(err)
|
|
}
|
|
dispatch(setNextNonce(nextNonce))
|
|
resolve(nextNonce)
|
|
})
|
|
})
|
|
}
|
|
}
|