diff options
Diffstat (limited to 'docs/jsdocs/metamask-controller.js.html')
-rw-r--r-- | docs/jsdocs/metamask-controller.js.html | 1144 |
1 files changed, 1144 insertions, 0 deletions
diff --git a/docs/jsdocs/metamask-controller.js.html b/docs/jsdocs/metamask-controller.js.html new file mode 100644 index 000000000..2162138d1 --- /dev/null +++ b/docs/jsdocs/metamask-controller.js.html @@ -0,0 +1,1144 @@ +<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="google" content="notranslate">
+ <meta http-equiv="Content-Language" content="en">
+ <title>metamask-controller.js - Documentation</title>
+
+ <script src="scripts/prettify/prettify.js"></script>
+ <script src="scripts/prettify/lang-css.js"></script>
+ <script
+ src="https://code.jquery.com/jquery-3.1.1.min.js"
+ integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
+ crossorigin="anonymous"></script>
+ <script src="scripts/semantic.min.js"></script>
+ <!--[if lt IE 9]>
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+ <link type="text/css" rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
+ <link type="text/css" rel="stylesheet" href="styles/semantic.min.css">
+ <link type="text/css" rel="stylesheet" href="styles/override.css">
+</head>
+<body>
+
+<input type="checkbox" id="nav-trigger" class="nav-trigger" />
+<label for="nav-trigger" class="navicon-button x">
+ <div class="navicon"></div>
+</label>
+
+<label for="nav-trigger" class="overlay"></label>
+
+<nav>
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><div class="ui vertical accordion"><div class="title"><div class="ui list"><div class="item"><i class="inverted dropdown icon"></i><a href="module.exports_module.exports.html">exports</a></div></div></div></li></div></ul><h3><a href="global.html">Global</a></h3>
+</nav>
+
+<div id="main">
+
+ <h1 class="page-title">metamask-controller.js</h1>
+
+
+
+
+
+
+
+ <section>
+ <article>
+ <pre class="prettyprint source linenums"><code>/** + * @file The central metamask controller. Aggregates other controllers and exports an api. + * @copyright Copyright (c) 2018 MetaMask + * @license MIT + */ + +const EventEmitter = require('events') +const extend = require('xtend') +const pump = require('pump') +const Dnode = require('dnode') +const ObservableStore = require('obs-store') +const asStream = require('obs-store/lib/asStream') +const AccountTracker = require('./lib/account-tracker') +const RpcEngine = require('json-rpc-engine') +const debounce = require('debounce') +const createEngineStream = require('json-rpc-middleware-stream/engineStream') +const createFilterMiddleware = require('eth-json-rpc-filters') +const createOriginMiddleware = require('./lib/createOriginMiddleware') +const createLoggerMiddleware = require('./lib/createLoggerMiddleware') +const createProviderMiddleware = require('./lib/createProviderMiddleware') +const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex +const KeyringController = require('eth-keyring-controller') +const NetworkController = require('./controllers/network') +const PreferencesController = require('./controllers/preferences') +const CurrencyController = require('./controllers/currency') +const NoticeController = require('./notice-controller') +const ShapeShiftController = require('./controllers/shapeshift') +const AddressBookController = require('./controllers/address-book') +const InfuraController = require('./controllers/infura') +const BlacklistController = require('./controllers/blacklist') +const RecentBlocksController = require('./controllers/recent-blocks') +const MessageManager = require('./lib/message-manager') +const PersonalMessageManager = require('./lib/personal-message-manager') +const TypedMessageManager = require('./lib/typed-message-manager') +const TransactionController = require('./controllers/transactions') +const BalancesController = require('./controllers/computed-balances') +const ConfigManager = require('./lib/config-manager') +const nodeify = require('./lib/nodeify') +const accountImporter = require('./account-import-strategies') +const getBuyEthUrl = require('./lib/buy-eth-url') +const Mutex = require('await-semaphore').Mutex +const version = require('../manifest.json').version +const BN = require('ethereumjs-util').BN +const GWEI_BN = new BN('1000000000') +const percentile = require('percentile') +const seedPhraseVerifier = require('./lib/seed-phrase-verifier') + +/** + * @typedef {object} MetaMaskOptions + * @property {Platform} platform - An object including platform-specific functions. + */ + +module.exports = class MetamaskController extends EventEmitter { + + /** + * @constructor + * @param {Object} opts + */ + constructor (opts) { + super() + + // Avoids warnings when we use lots of emitters. + this.defaultMaxListeners = 20 + + this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200) + this.opts = opts + const initState = opts.initState || {} + this.recordFirstTimeInfo(initState) + + // platform-specific api + this.platform = opts.platform + + // observable state store + this.store = new ObservableStore(initState) + + // lock to ensure only one vault created at once + this.createVaultMutex = new Mutex() + + // network store + this.networkController = new NetworkController(initState.NetworkController) + + // config manager + this.configManager = new ConfigManager({ + store: this.store, + }) + + // preferences controller + this.preferencesController = new PreferencesController({ + initState: initState.PreferencesController, + initLangCode: opts.initLangCode, + }) + + // currency controller + this.currencyController = new CurrencyController({ + initState: initState.CurrencyController, + }) + this.currencyController.updateConversionRate() + this.currencyController.scheduleConversionInterval() + + // infura controller + this.infuraController = new InfuraController({ + initState: initState.InfuraController, + }) + this.infuraController.scheduleInfuraNetworkCheck() + + this.blacklistController = new BlacklistController() + this.blacklistController.scheduleUpdates() + + // rpc provider + this.provider = this.initializeProvider() + this.blockTracker = this.provider._blockTracker + + this.recentBlocksController = new RecentBlocksController({ + blockTracker: this.blockTracker, + provider: this.provider, + }) + + // account tracker watches balances, nonces, and any code at their address. + this.accountTracker = new AccountTracker({ + provider: this.provider, + blockTracker: this.blockTracker, + }) + + // key mgmt + this.keyringController = new KeyringController({ + initState: initState.KeyringController, + getNetwork: this.networkController.getNetworkState.bind(this.networkController), + encryptor: opts.encryptor || undefined, + }) + + // If only one account exists, make sure it is selected. + this.keyringController.memStore.subscribe((state) => { + const addresses = state.keyrings.reduce((res, keyring) => { + return res.concat(keyring.accounts) + }, []) + if (addresses.length === 1) { + const address = addresses[0] + this.preferencesController.setSelectedAddress(address) + } + this.accountTracker.syncWithAddresses(addresses) + }) + + // address book controller + this.addressBookController = new AddressBookController({ + initState: initState.AddressBookController, + }, this.keyringController) + + // tx mgmt + this.txController = new TransactionController({ + initState: initState.TransactionController || initState.TransactionManager, + networkStore: this.networkController.networkStore, + preferencesStore: this.preferencesController.store, + txHistoryLimit: 40, + getNetwork: this.networkController.getNetworkState.bind(this), + signTransaction: this.keyringController.signTransaction.bind(this.keyringController), + provider: this.provider, + blockTracker: this.blockTracker, + getGasPrice: this.getGasPrice.bind(this), + }) + this.txController.on('newUnapprovedTx', opts.showUnapprovedTx.bind(opts)) + + // computed balances (accounting for pending transactions) + this.balancesController = new BalancesController({ + accountTracker: this.accountTracker, + txController: this.txController, + blockTracker: this.blockTracker, + }) + this.networkController.on('networkDidChange', () => { + this.balancesController.updateAllBalances() + }) + this.balancesController.updateAllBalances() + + // notices + this.noticeController = new NoticeController({ + initState: initState.NoticeController, + version, + firstVersion: initState.firstTimeInfo.version, + }) + this.noticeController.updateNoticesList() + // to be uncommented when retrieving notices from a remote server. + // this.noticeController.startPolling() + + this.shapeshiftController = new ShapeShiftController({ + initState: initState.ShapeShiftController, + }) + + this.networkController.lookupNetwork() + this.messageManager = new MessageManager() + this.personalMessageManager = new PersonalMessageManager() + this.typedMessageManager = new TypedMessageManager() + this.publicConfigStore = this.initPublicConfigStore() + + // manual disk state subscriptions + this.txController.store.subscribe((state) => { + this.store.updateState({ TransactionController: state }) + }) + this.keyringController.store.subscribe((state) => { + this.store.updateState({ KeyringController: state }) + }) + this.preferencesController.store.subscribe((state) => { + this.store.updateState({ PreferencesController: state }) + }) + this.addressBookController.store.subscribe((state) => { + this.store.updateState({ AddressBookController: state }) + }) + this.currencyController.store.subscribe((state) => { + this.store.updateState({ CurrencyController: state }) + }) + this.noticeController.store.subscribe((state) => { + this.store.updateState({ NoticeController: state }) + }) + this.shapeshiftController.store.subscribe((state) => { + this.store.updateState({ ShapeShiftController: state }) + }) + this.networkController.store.subscribe((state) => { + this.store.updateState({ NetworkController: state }) + }) + + this.infuraController.store.subscribe((state) => { + this.store.updateState({ InfuraController: state }) + }) + + // manual mem state subscriptions + const sendUpdate = this.sendUpdate.bind(this) + this.networkController.store.subscribe(sendUpdate) + this.accountTracker.store.subscribe(sendUpdate) + this.txController.memStore.subscribe(sendUpdate) + this.balancesController.store.subscribe(sendUpdate) + this.messageManager.memStore.subscribe(sendUpdate) + this.personalMessageManager.memStore.subscribe(sendUpdate) + this.typedMessageManager.memStore.subscribe(sendUpdate) + this.keyringController.memStore.subscribe(sendUpdate) + this.preferencesController.store.subscribe(sendUpdate) + this.recentBlocksController.store.subscribe(sendUpdate) + this.addressBookController.store.subscribe(sendUpdate) + this.currencyController.store.subscribe(sendUpdate) + this.noticeController.memStore.subscribe(sendUpdate) + this.shapeshiftController.store.subscribe(sendUpdate) + this.infuraController.store.subscribe(sendUpdate) + } + + /** + * Constructor helper: initialize a provider. + */ + initializeProvider () { + const providerOpts = { + static: { + eth_syncing: false, + web3_clientVersion: `MetaMask/v${version}`, + eth_sendTransaction: (payload, next, end) => { + const origin = payload.origin + const txParams = payload.params[0] + nodeify(this.txController.newUnapprovedTransaction, this.txController)(txParams, { origin }, end) + }, + }, + // account mgmt + getAccounts: (cb) => { + const isUnlocked = this.keyringController.memStore.getState().isUnlocked + const result = [] + const selectedAddress = this.preferencesController.getSelectedAddress() + + // only show address if account is unlocked + if (isUnlocked && selectedAddress) { + result.push(selectedAddress) + } + cb(null, result) + }, + // tx signing + // old style msg signing + processMessage: this.newUnsignedMessage.bind(this), + // personal_sign msg signing + processPersonalMessage: this.newUnsignedPersonalMessage.bind(this), + processTypedMessage: this.newUnsignedTypedMessage.bind(this), + } + const providerProxy = this.networkController.initializeProvider(providerOpts) + return providerProxy + } + + /** + * Constructor helper: initialize a public config store. + */ + initPublicConfigStore () { + // get init state + const publicConfigStore = new ObservableStore() + + // memStore -> transform -> publicConfigStore + this.on('update', (memState) => { + const publicState = selectPublicState(memState) + publicConfigStore.putState(publicState) + }) + + function selectPublicState (memState) { + const result = { + selectedAddress: memState.isUnlocked ? memState.selectedAddress : undefined, + networkVersion: memState.network, + } + return result + } + + return publicConfigStore + } + +//============================================================================= +// EXPOSED TO THE UI SUBSYSTEM +//============================================================================= + + /** + * The metamask-state of the various controllers, made available to the UI + * + * @returns {Object} status + */ + getState () { + const wallet = this.configManager.getWallet() + const vault = this.keyringController.store.getState().vault + const isInitialized = (!!wallet || !!vault) + + return extend( + { + isInitialized, + }, + this.networkController.store.getState(), + this.accountTracker.store.getState(), + this.txController.memStore.getState(), + this.messageManager.memStore.getState(), + this.personalMessageManager.memStore.getState(), + this.typedMessageManager.memStore.getState(), + this.keyringController.memStore.getState(), + this.balancesController.store.getState(), + this.preferencesController.store.getState(), + this.addressBookController.store.getState(), + this.currencyController.store.getState(), + this.noticeController.memStore.getState(), + this.infuraController.store.getState(), + this.recentBlocksController.store.getState(), + // config manager + this.configManager.getConfig(), + this.shapeshiftController.store.getState(), + { + lostAccounts: this.configManager.getLostAccounts(), + seedWords: this.configManager.getSeedWords(), + forgottenPassword: this.configManager.getPasswordForgotten(), + } + ) + } + + /** + * Returns an api-object which is consumed by the UI + * + * @returns {Object} + */ + getApi () { + const keyringController = this.keyringController + const preferencesController = this.preferencesController + const txController = this.txController + const noticeController = this.noticeController + const addressBookController = this.addressBookController + const networkController = this.networkController + + return { + // etc + getState: (cb) => cb(null, this.getState()), + setCurrentCurrency: this.setCurrentCurrency.bind(this), + setUseBlockie: this.setUseBlockie.bind(this), + setCurrentLocale: this.setCurrentLocale.bind(this), + markAccountsFound: this.markAccountsFound.bind(this), + markPasswordForgotten: this.markPasswordForgotten.bind(this), + unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this), + + // coinbase + buyEth: this.buyEth.bind(this), + // shapeshift + createShapeShiftTx: this.createShapeShiftTx.bind(this), + + // primary HD keyring management + addNewAccount: nodeify(this.addNewAccount, this), + placeSeedWords: this.placeSeedWords.bind(this), + verifySeedPhrase: nodeify(this.verifySeedPhrase, this), + clearSeedWordCache: this.clearSeedWordCache.bind(this), + resetAccount: nodeify(this.resetAccount, this), + importAccountWithStrategy: this.importAccountWithStrategy.bind(this), + + // vault management + submitPassword: nodeify(keyringController.submitPassword, keyringController), + + // network management + setNetworkEndpoints: nodeify(networkController.setNetworkEndpoints, networkController), + setProviderType: nodeify(networkController.setProviderType, networkController), + setCustomRpc: nodeify(this.setCustomRpc, this), + + // PreferencesController + setSelectedAddress: nodeify(preferencesController.setSelectedAddress, preferencesController), + addToken: nodeify(preferencesController.addToken, preferencesController), + removeToken: nodeify(preferencesController.removeToken, preferencesController), + setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController), + setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController), + + // AddressController + setAddressBook: nodeify(addressBookController.setAddressBook, addressBookController), + + // KeyringController + setLocked: nodeify(keyringController.setLocked, keyringController), + createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this), + createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this), + addNewKeyring: nodeify(keyringController.addNewKeyring, keyringController), + saveAccountLabel: nodeify(keyringController.saveAccountLabel, keyringController), + exportAccount: nodeify(keyringController.exportAccount, keyringController), + + // txController + cancelTransaction: nodeify(txController.cancelTransaction, txController), + updateTransaction: nodeify(txController.updateTransaction, txController), + updateAndApproveTransaction: nodeify(txController.updateAndApproveTransaction, txController), + retryTransaction: nodeify(this.retryTransaction, this), + + // messageManager + signMessage: nodeify(this.signMessage, this), + cancelMessage: this.cancelMessage.bind(this), + + // personalMessageManager + signPersonalMessage: nodeify(this.signPersonalMessage, this), + cancelPersonalMessage: this.cancelPersonalMessage.bind(this), + + // personalMessageManager + signTypedMessage: nodeify(this.signTypedMessage, this), + cancelTypedMessage: this.cancelTypedMessage.bind(this), + + // notices + checkNotices: noticeController.updateNoticesList.bind(noticeController), + markNoticeRead: noticeController.markNoticeRead.bind(noticeController), + } + } + + + +//============================================================================= +// VAULT / KEYRING RELATED METHODS +//============================================================================= + + /** + * Creates a new Vault(?) and create a new keychain(?) + * + * A vault is ... + * + * A keychain is ... + * + * + * @param {} password + * + * @returns {} vault + */ + async createNewVaultAndKeychain (password) { + const release = await this.createVaultMutex.acquire() + let vault + + try { + const accounts = await this.keyringController.getAccounts() + + if (accounts.length > 0) { + vault = await this.keyringController.fullUpdate() + + } else { + vault = await this.keyringController.createNewVaultAndKeychain(password) + this.selectFirstIdentity(vault) + } + release() + } catch (err) { + release() + throw err + } + + return vault + } + + /** + * Create a new Vault and restore an existent keychain + * @param {} password + * @param {} seed + */ + async createNewVaultAndRestore (password, seed) { + const release = await this.createVaultMutex.acquire() + try { + const vault = await this.keyringController.createNewVaultAndRestore(password, seed) + this.selectFirstIdentity(vault) + release() + return vault + } catch (err) { + release() + throw err + } + } + + /** + * Retrieves the first Identiy from the passed Vault and selects the related address + * + * An Identity is ... + * + * @param {} vault + */ + selectFirstIdentity (vault) { + const { identities } = vault + const address = Object.keys(identities)[0] + this.preferencesController.setSelectedAddress(address) + } + + // ? + // Opinionated Keyring Management + // + + /** + * Adds a new account to ... + * + * @returns {} keyState + */ + async addNewAccount () { + const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] + if (!primaryKeyring) { + throw new Error('MetamaskController - No HD Key Tree found') + } + const keyringController = this.keyringController + const oldAccounts = await keyringController.getAccounts() + const keyState = await keyringController.addNewAccount(primaryKeyring) + const newAccounts = await keyringController.getAccounts() + + await this.verifySeedPhrase() + + newAccounts.forEach((address) => { + if (!oldAccounts.includes(address)) { + this.preferencesController.setSelectedAddress(address) + } + }) + + return keyState + } + + /** + * Adds the current vault's seed words to the UI's state tree. + * + * Used when creating a first vault, to allow confirmation. + * Also used when revealing the seed words in the confirmation view. + */ + placeSeedWords (cb) { + + this.verifySeedPhrase() + .then((seedWords) => { + this.configManager.setSeedWords(seedWords) + return cb(null, seedWords) + }) + .catch((err) => { + return cb(err) + }) + } + + /** + * Verifies the validity of the current vault's seed phrase. + * + * Validity: seed phrase restores the accounts belonging to the current vault. + * + * Called when the first account is created and on unlocking the vault. + */ + async verifySeedPhrase () { + + const primaryKeyring = this.keyringController.getKeyringsByType('HD Key Tree')[0] + if (!primaryKeyring) { + throw new Error('MetamaskController - No HD Key Tree found') + } + + const serialized = await primaryKeyring.serialize() + const seedWords = serialized.mnemonic + + const accounts = await primaryKeyring.getAccounts() + if (accounts.length < 1) { + throw new Error('MetamaskController - No accounts found') + } + + try { + await seedPhraseVerifier.verifyAccounts(accounts, seedWords) + return seedWords + } catch (err) { + log.error(err.message) + throw err + } + } + + /** + * Remove the primary account seed phrase from the UI's state tree. + * + * The seed phrase remains available in the background process. + * + */ + clearSeedWordCache (cb) { + this.configManager.setSeedWords(null) + cb(null, this.preferencesController.getSelectedAddress()) + } + + /** + * ? + */ + async resetAccount (cb) { + const selectedAddress = this.preferencesController.getSelectedAddress() + this.txController.wipeTransactions(selectedAddress) + + const networkController = this.networkController + const oldType = networkController.getProviderConfig().type + await networkController.setProviderType(oldType, true) + + return selectedAddress + } + + /** + * Imports an account ... ? + * + * @param {} strategy + * @param {} args + * @param {} cb + */ + importAccountWithStrategy (strategy, args, cb) { + accountImporter.importAccount(strategy, args) + .then((privateKey) => { + return this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) + }) + .then(keyring => keyring.getAccounts()) + .then((accounts) => this.preferencesController.setSelectedAddress(accounts[0])) + .then(() => { cb(null, this.keyringController.fullUpdate()) }) + .catch((reason) => { cb(reason) }) + } + + // --------------------------------------------------------------------------- + // Identity Management (sign) + + /** + * @param {} msgParams + * @param {} cb + */ + signMessage (msgParams, cb) { + log.info('MetaMaskController - signMessage') + const msgId = msgParams.metamaskId + + // sets the status op the message to 'approved' + // and removes the metamaskId for signing + return this.messageManager.approveMessage(msgParams) + .then((cleanMsgParams) => { + // signs the message + return this.keyringController.signMessage(cleanMsgParams) + }) + .then((rawSig) => { + // tells the listener that the message has been signed + // and can be returned to the dapp + this.messageManager.setMsgStatusSigned(msgId, rawSig) + return this.getState() + }) + } + + // Prefixed Style Message Signing Methods: + + /** + * + * @param {} msgParams + * @param {} cb + */ + approvePersonalMessage (msgParams, cb) { + const msgId = this.personalMessageManager.addUnapprovedMessage(msgParams) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + this.personalMessageManager.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return cb(null, data.rawSig) + case 'rejected': + return cb(new Error('MetaMask Message Signature: User denied transaction signature.')) + default: + return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + } + + /** + * @param {} msgParams + */ + signPersonalMessage (msgParams) { + log.info('MetaMaskController - signPersonalMessage') + const msgId = msgParams.metamaskId + // sets the status op the message to 'approved' + // and removes the metamaskId for signing + return this.personalMessageManager.approveMessage(msgParams) + .then((cleanMsgParams) => { + // signs the message + return this.keyringController.signPersonalMessage(cleanMsgParams) + }) + .then((rawSig) => { + // tells the listener that the message has been signed + // and can be returned to the dapp + this.personalMessageManager.setMsgStatusSigned(msgId, rawSig) + return this.getState() + }) + } + + /** + * @param {} msgParams + */ + signTypedMessage (msgParams) { + log.info('MetaMaskController - signTypedMessage') + const msgId = msgParams.metamaskId + // sets the status op the message to 'approved' + // and removes the metamaskId for signing + return this.typedMessageManager.approveMessage(msgParams) + .then((cleanMsgParams) => { + // signs the message + return this.keyringController.signTypedMessage(cleanMsgParams) + }) + .then((rawSig) => { + // tells the listener that the message has been signed + // and can be returned to the dapp + this.typedMessageManager.setMsgStatusSigned(msgId, rawSig) + return this.getState() + }) + } + + // --------------------------------------------------------------------------- + // Account Restauration + + /** + * ? + * + * @param {} migratorOutput + */ + restoreOldVaultAccounts (migratorOutput) { + const { serialized } = migratorOutput + return this.keyringController.restoreKeyring(serialized) + .then(() => migratorOutput) + } + + /** + * ? + * + * @param {} migratorOutput + */ + restoreOldLostAccounts (migratorOutput) { + const { lostAccounts } = migratorOutput + if (lostAccounts) { + this.configManager.setLostAccounts(lostAccounts.map(acct => acct.address)) + return this.importLostAccounts(migratorOutput) + } + return Promise.resolve(migratorOutput) + } + + /** + * Import (lost) Accounts + * + * @param {Object} {lostAccounts} @Array accounts <{ address, privateKey }> + * + * Uses the array's private keys to create a new Simple Key Pair keychain + * and add it to the keyring controller. + */ + importLostAccounts ({ lostAccounts }) { + const privKeys = lostAccounts.map(acct => acct.privateKey) + return this.keyringController.restoreKeyring({ + type: 'Simple Key Pair', + data: privKeys, + }) + } + +//============================================================================= +// END (VAULT / KEYRING RELATED METHODS) +//============================================================================= + +// + +//============================================================================= +// MESSAGES +//============================================================================= + + async retryTransaction (txId, cb) { + await this.txController.retryTransaction(txId) + const state = await this.getState() + return state + } + + + newUnsignedMessage (msgParams, cb) { + const msgId = this.messageManager.addUnapprovedMessage(msgParams) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + this.messageManager.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return cb(null, data.rawSig) + case 'rejected': + return cb(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + } + + newUnsignedPersonalMessage (msgParams, cb) { + if (!msgParams.from) { + return cb(new Error('MetaMask Message Signature: from field is required.')) + } + + const msgId = this.personalMessageManager.addUnapprovedMessage(msgParams) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + this.personalMessageManager.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return cb(null, data.rawSig) + case 'rejected': + return cb(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + } + + newUnsignedTypedMessage (msgParams, cb) { + let msgId + try { + msgId = this.typedMessageManager.addUnapprovedMessage(msgParams) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + } catch (e) { + return cb(e) + } + + this.typedMessageManager.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return cb(null, data.rawSig) + case 'rejected': + return cb(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + } + + cancelMessage (msgId, cb) { + const messageManager = this.messageManager + messageManager.rejectMsg(msgId) + if (cb && typeof cb === 'function') { + cb(null, this.getState()) + } + } + + cancelPersonalMessage (msgId, cb) { + const messageManager = this.personalMessageManager + messageManager.rejectMsg(msgId) + if (cb && typeof cb === 'function') { + cb(null, this.getState()) + } + } + + cancelTypedMessage (msgId, cb) { + const messageManager = this.typedMessageManager + messageManager.rejectMsg(msgId) + if (cb && typeof cb === 'function') { + cb(null, this.getState()) + } + } + + markAccountsFound (cb) { + this.configManager.setLostAccounts([]) + this.sendUpdate() + cb(null, this.getState()) + } + + markPasswordForgotten(cb) { + this.configManager.setPasswordForgotten(true) + this.sendUpdate() + cb() + } + + unMarkPasswordForgotten(cb) { + this.configManager.setPasswordForgotten(false) + this.sendUpdate() + cb() + } + +//============================================================================= +// SETUP +//============================================================================= + + setupUntrustedCommunication (connectionStream, originDomain) { + // Check if new connection is blacklisted + if (this.blacklistController.checkForPhishing(originDomain)) { + log.debug('MetaMask - sending phishing warning for', originDomain) + this.sendPhishingWarning(connectionStream, originDomain) + return + } + + // setup multiplexing + const mux = setupMultiplex(connectionStream) + // connect features + this.setupProviderConnection(mux.createStream('provider'), originDomain) + this.setupPublicConfig(mux.createStream('publicConfig')) + } + + setupTrustedCommunication (connectionStream, originDomain) { + // setup multiplexing + const mux = setupMultiplex(connectionStream) + // connect features + this.setupControllerConnection(mux.createStream('controller')) + this.setupProviderConnection(mux.createStream('provider'), originDomain) + } + + sendPhishingWarning (connectionStream, hostname) { + const mux = setupMultiplex(connectionStream) + const phishingStream = mux.createStream('phishing') + phishingStream.write({ hostname }) + } + + setupControllerConnection (outStream) { + const api = this.getApi() + const dnode = Dnode(api) + pump( + outStream, + dnode, + outStream, + (err) => { + if (err) log.error(err) + } + ) + dnode.on('remote', (remote) => { + // push updates to popup + const sendUpdate = remote.sendUpdate.bind(remote) + this.on('update', sendUpdate) + }) + } + + setupProviderConnection (outStream, origin) { + // setup json rpc engine stack + const engine = new RpcEngine() + + // create filter polyfill middleware + const filterMiddleware = createFilterMiddleware({ + provider: this.provider, + blockTracker: this.provider._blockTracker, + }) + + engine.push(createOriginMiddleware({ origin })) + engine.push(createLoggerMiddleware({ origin })) + engine.push(filterMiddleware) + engine.push(createProviderMiddleware({ provider: this.provider })) + + // setup connection + const providerStream = createEngineStream({ engine }) + pump( + outStream, + providerStream, + outStream, + (err) => { + // cleanup filter polyfill middleware + filterMiddleware.destroy() + if (err) log.error(err) + } + ) + } + + setupPublicConfig (outStream) { + pump( + asStream(this.publicConfigStore), + outStream, + (err) => { + if (err) log.error(err) + } + ) + } + + privateSendUpdate () { + this.emit('update', this.getState()) + } + + getGasPrice () { + const { recentBlocksController } = this + const { recentBlocks } = recentBlocksController.store.getState() + + // Return 1 gwei if no blocks have been observed: + if (recentBlocks.length === 0) { + return '0x' + GWEI_BN.toString(16) + } + + const lowestPrices = recentBlocks.map((block) => { + if (!block.gasPrices || block.gasPrices.length < 1) { + return GWEI_BN + } + return block.gasPrices + .map(hexPrefix => hexPrefix.substr(2)) + .map(hex => new BN(hex, 16)) + .sort((a, b) => { + return a.gt(b) ? 1 : -1 + })[0] + }) + .map(number => number.div(GWEI_BN).toNumber()) + + const percentileNum = percentile(50, lowestPrices) + const percentileNumBn = new BN(percentileNum) + return '0x' + percentileNumBn.mul(GWEI_BN).toString(16) + } + +//============================================================================= +// CONFIG +//============================================================================= + + // Log blocks + + setCurrentCurrency (currencyCode, cb) { + try { + this.currencyController.setCurrentCurrency(currencyCode) + this.currencyController.updateConversionRate() + const data = { + conversionRate: this.currencyController.getConversionRate(), + currentCurrency: this.currencyController.getCurrentCurrency(), + conversionDate: this.currencyController.getConversionDate(), + } + cb(null, data) + } catch (err) { + cb(err) + } + } + + buyEth (address, amount) { + if (!amount) amount = '5' + const network = this.networkController.getNetworkState() + const url = getBuyEthUrl({ network, address, amount }) + if (url) this.platform.openWindow({ url }) + } + + createShapeShiftTx (depositAddress, depositType) { + this.shapeshiftController.createShapeShiftTx(depositAddress, depositType) + } + + // network + + async setCustomRpc (rpcTarget, rpcList) { + this.networkController.setRpcTarget(rpcTarget) + await this.preferencesController.updateFrequentRpcList(rpcTarget) + return rpcTarget + } + + setUseBlockie (val, cb) { + try { + this.preferencesController.setUseBlockie(val) + cb(null) + } catch (err) { + cb(err) + } + } + + setCurrentLocale (key, cb) { + try { + this.preferencesController.setCurrentLocale(key) + cb(null) + } catch (err) { + cb(err) + } + } + + /** + * Records the MetaMask version and time of first installation, + * mutating the initState param. + * + * @private + * + * @param {object} initState The initial state passed to the controller, + * which may be new. + */ + recordFirstTimeInfo (initState) { + if (!('firstTimeInfo' in initState)) { + initState.firstTimeInfo = { + version, + date: Date.now(), + } + } + } + +} +</code></pre>
+ </article>
+ </section>
+
+
+
+
+</div>
+
+<br class="clear">
+
+<footer>
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> on Thu Apr 12 2018 14:37:39 GMT-0700 (PDT) using the radgrad jsdoc theme. Derived from docdash.
+</footer>
+
+<script>prettyPrint();</script>
+<script src="scripts/linenumber.js"></script>
+<script>$('.ui.accordion').accordion();</script>
+</body>
+</html>
|