mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 01:39:44 +01:00
Merge branch 'master' into dm-docs-2
This commit is contained in:
commit
ed264d3479
@ -19,15 +19,6 @@ workflows:
|
||||
requires:
|
||||
- prep-deps-npm
|
||||
- prep-build
|
||||
- job-screens:
|
||||
requires:
|
||||
- prep-deps-npm
|
||||
- prep-build
|
||||
- job-publish:
|
||||
requires:
|
||||
- prep-deps-npm
|
||||
- prep-build
|
||||
- job-screens
|
||||
- test-unit:
|
||||
requires:
|
||||
- prep-deps-npm
|
||||
@ -54,11 +45,21 @@ workflows:
|
||||
- test-lint
|
||||
- test-unit
|
||||
- test-e2e
|
||||
- job-screens
|
||||
- test-integration-mascara-chrome
|
||||
- test-integration-mascara-firefox
|
||||
- test-integration-flat-chrome
|
||||
- test-integration-flat-firefox
|
||||
- job-screens:
|
||||
requires:
|
||||
- prep-deps-npm
|
||||
- prep-build
|
||||
- all-tests-pass
|
||||
- job-publish:
|
||||
requires:
|
||||
- prep-deps-npm
|
||||
- prep-build
|
||||
- job-screens
|
||||
- all-tests-pass
|
||||
|
||||
jobs:
|
||||
prep-deps-npm:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,6 +20,7 @@ dist
|
||||
builds/
|
||||
disc/
|
||||
builds.zip
|
||||
docs/jsdocs
|
||||
|
||||
development/bundle.js
|
||||
development/states.js
|
||||
|
@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @file The entry point for the web extension singleton process.
|
||||
*/
|
||||
|
||||
const urlUtil = require('url')
|
||||
const endOfStream = require('end-of-stream')
|
||||
const pump = require('pump')
|
||||
@ -61,6 +65,90 @@ initialize().catch(log.error)
|
||||
// setup metamask mesh testing container
|
||||
setupMetamaskMeshMetrics()
|
||||
|
||||
/**
|
||||
* An object representing a transaction, in whatever state it is in.
|
||||
* @typedef TransactionMeta
|
||||
*
|
||||
* @property {number} id - An internally unique tx identifier.
|
||||
* @property {number} time - Time the tx was first suggested, in unix epoch time (ms).
|
||||
* @property {string} status - The current transaction status (unapproved, signed, submitted, dropped, failed, rejected), as defined in `tx-state-manager.js`.
|
||||
* @property {string} metamaskNetworkId - The transaction's network ID, used for EIP-155 compliance.
|
||||
* @property {boolean} loadingDefaults - TODO: Document
|
||||
* @property {Object} txParams - The tx params as passed to the network provider.
|
||||
* @property {Object[]} history - A history of mutations to this TransactionMeta object.
|
||||
* @property {boolean} gasPriceSpecified - True if the suggesting dapp specified a gas price, prevents auto-estimation.
|
||||
* @property {boolean} gasLimitSpecified - True if the suggesting dapp specified a gas limit, prevents auto-estimation.
|
||||
* @property {string} estimatedGas - A hex string represented the estimated gas limit required to complete the transaction.
|
||||
* @property {string} origin - A string representing the interface that suggested the transaction.
|
||||
* @property {Object} nonceDetails - A metadata object containing information used to derive the suggested nonce, useful for debugging nonce issues.
|
||||
* @property {string} rawTx - A hex string of the final signed transaction, ready to submit to the network.
|
||||
* @property {string} hash - A hex string of the transaction hash, used to identify the transaction on the network.
|
||||
* @property {number} submittedTime - The time the transaction was submitted to the network, in Unix epoch time (ms).
|
||||
*/
|
||||
|
||||
/**
|
||||
* The data emitted from the MetaMaskController.store EventEmitter, also used to initialize the MetaMaskController. Available in UI on React state as state.metamask.
|
||||
* @typedef MetaMaskState
|
||||
* @property {boolean} isInitialized - Whether the first vault has been created.
|
||||
* @property {boolean} isUnlocked - Whether the vault is currently decrypted and accounts are available for selection.
|
||||
* @property {boolean} isAccountMenuOpen - Represents whether the main account selection UI is currently displayed.
|
||||
* @property {boolean} isMascara - True if the current context is the extensionless MetaMascara project.
|
||||
* @property {boolean} isPopup - Returns true if the current view is an externally-triggered notification.
|
||||
* @property {string} rpcTarget - DEPRECATED - The URL of the current RPC provider.
|
||||
* @property {Object} identities - An object matching lower-case hex addresses to Identity objects with "address" and "name" (nickname) keys.
|
||||
* @property {Object} unapprovedTxs - An object mapping transaction hashes to unapproved transactions.
|
||||
* @property {boolean} noActiveNotices - False if there are notices the user should confirm before using the application.
|
||||
* @property {Array} frequentRpcList - A list of frequently used RPCs, including custom user-provided ones.
|
||||
* @property {Array} addressBook - A list of previously sent to addresses.
|
||||
* @property {address} selectedTokenAddress - Used to indicate if a token is globally selected. Should be deprecated in favor of UI-centric token selection.
|
||||
* @property {Object} tokenExchangeRates - Info about current token prices.
|
||||
* @property {Array} tokens - Tokens held by the current user, including their balances.
|
||||
* @property {Object} send - TODO: Document
|
||||
* @property {Object} coinOptions - TODO: Document
|
||||
* @property {boolean} useBlockie - Indicates preferred user identicon format. True for blockie, false for Jazzicon.
|
||||
* @property {Object} featureFlags - An object for optional feature flags.
|
||||
* @property {string} networkEndpointType - TODO: Document
|
||||
* @property {boolean} isRevealingSeedWords - True if seed words are currently being recovered, and should be shown to user.
|
||||
* @property {boolean} welcomeScreen - True if welcome screen should be shown.
|
||||
* @property {string} currentLocale - A locale string matching the user's preferred display language.
|
||||
* @property {Object} provider - The current selected network provider.
|
||||
* @property {string} provider.rpcTarget - The address for the RPC API, if using an RPC API.
|
||||
* @property {string} provider.type - An identifier for the type of network selected, allows MetaMask to use custom provider strategies for known networks.
|
||||
* @property {string} network - A stringified number of the current network ID.
|
||||
* @property {Object} accounts - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values.
|
||||
* @property {hex} currentBlockGasLimit - The most recently seen block gas limit, in a lower case hex prefixed string.
|
||||
* @property {TransactionMeta[]} selectedAddressTxList - An array of transactions associated with the currently selected account.
|
||||
* @property {Object} unapprovedMsgs - An object of messages associated with the currently selected account, mapping a unique ID to the options.
|
||||
* @property {number} unapprovedMsgCount - The number of messages in unapprovedMsgs.
|
||||
* @property {Object} unapprovedPersonalMsgs - An object of messages associated with the currently selected account, mapping a unique ID to the options.
|
||||
* @property {number} unapprovedPersonalMsgCount - The number of messages in unapprovedPersonalMsgs.
|
||||
* @property {Object} unapprovedTypedMsgs - An object of messages associated with the currently selected account, mapping a unique ID to the options.
|
||||
* @property {number} unapprovedTypedMsgCount - The number of messages in unapprovedTypedMsgs.
|
||||
* @property {string[]} keyringTypes - An array of unique keyring identifying strings, representing available strategies for creating accounts.
|
||||
* @property {Keyring[]} keyrings - An array of keyring descriptions, summarizing the accounts that are available for use, and what keyrings they belong to.
|
||||
* @property {Object} computedBalances - Maps accounts to their balances, accounting for balance changes from pending transactions.
|
||||
* @property {string} currentAccountTab - A view identifying string for displaying the current displayed view, allows user to have a preferred tab in the old UI (between tokens and history).
|
||||
* @property {string} selectedAddress - A lower case hex string of the currently selected address.
|
||||
* @property {string} currentCurrency - A string identifying the user's preferred display currency, for use in showing conversion rates.
|
||||
* @property {number} conversionRate - A number representing the current exchange rate from the user's preferred currency to Ether.
|
||||
* @property {number} conversionDate - A unix epoch date (ms) for the time the current conversion rate was last retrieved.
|
||||
* @property {Object} infuraNetworkStatus - An object of infura network status checks.
|
||||
* @property {Block[]} recentBlocks - An array of recent blocks, used to calculate an effective but cheap gas price.
|
||||
* @property {Array} shapeShiftTxList - An array of objects describing shapeshift exchange attempts.
|
||||
* @property {Array} lostAccounts - TODO: Remove this feature. A leftover from the version-3 migration where our seed-phrase library changed to fix a bug where some accounts were mis-generated, but we recovered the old accounts as "lost" instead of losing them.
|
||||
* @property {boolean} forgottenPassword - Returns true if the user has initiated the password recovery screen, is recovering from seed phrase.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef VersionedData
|
||||
* @property {MetaMaskState} data - The data emitted from MetaMask controller, or used to initialize it.
|
||||
* @property {Number} version - The latest migration version that has been run.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initializes the MetaMask controller, and sets up all platform configuration.
|
||||
* @returns {Promise} Setup complete.
|
||||
*/
|
||||
async function initialize () {
|
||||
const initState = await loadStateFromPersistence()
|
||||
const initLangCode = await getFirstPreferredLangCode()
|
||||
@ -72,6 +160,11 @@ async function initialize () {
|
||||
// State and Persistence
|
||||
//
|
||||
|
||||
/**
|
||||
* Loads any stored data, prioritizing the latest storage strategy.
|
||||
* Migrates that data schema in case it was last loaded on an older version.
|
||||
* @returns {Promise<MetaMaskState>} Last data emitted from previous instance of MetaMask.
|
||||
*/
|
||||
async function loadStateFromPersistence () {
|
||||
// migrations
|
||||
const migrator = new Migrator({ migrations })
|
||||
@ -134,6 +227,16 @@ async function loadStateFromPersistence () {
|
||||
return versionedData.data
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the MetaMask Controller with any initial state and default language.
|
||||
* Configures platform-specific error reporting strategy.
|
||||
* Streams emitted state updates to platform-specific storage strategy.
|
||||
* Creates platform listeners for new Dapps/Contexts, and sets up their data connections to the controller.
|
||||
*
|
||||
* @param {Object} initState - The initial state to start the controller with, matches the state that is emitted from the controller.
|
||||
* @param {String} initLangCode - The region code for the language preferred by the current user.
|
||||
* @returns {Promise} After setup is complete.
|
||||
*/
|
||||
function setupController (initState, initLangCode) {
|
||||
//
|
||||
// MetaMask Controller
|
||||
@ -172,6 +275,11 @@ function setupController (initState, initLangCode) {
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Assigns the given state to the versioned object (with metadata), and returns that.
|
||||
* @param {Object} state - The state object as emitted by the MetaMaskController.
|
||||
* @returns {VersionedData} The state object wrapped in an object that includes a metadata key.
|
||||
*/
|
||||
function versionifyData (state) {
|
||||
versionedData.data = state
|
||||
return versionedData
|
||||
@ -208,6 +316,18 @@ function setupController (initState, initLangCode) {
|
||||
return popupIsOpen || Boolean(Object.keys(openMetamaskTabsIDs).length) || notificationIsOpen
|
||||
}
|
||||
|
||||
/**
|
||||
* A runtime.Port object, as provided by the browser:
|
||||
* @link https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/Port
|
||||
* @typedef Port
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Connects a Port to the MetaMask controller via a multiplexed duplex stream.
|
||||
* This method identifies trusted (MetaMask) interfaces, and connects them differently from untrusted (web pages).
|
||||
* @param {Port} remotePort - The port provided by a new context.
|
||||
*/
|
||||
function connectRemote (remotePort) {
|
||||
const processName = remotePort.name
|
||||
const isMetaMaskInternalProcess = metamaskInternalProcessHash[processName]
|
||||
@ -261,7 +381,10 @@ function setupController (initState, initLangCode) {
|
||||
controller.messageManager.on('updateBadge', updateBadge)
|
||||
controller.personalMessageManager.on('updateBadge', updateBadge)
|
||||
|
||||
// plugin badge text
|
||||
/**
|
||||
* Updates the Web Extension's "badge" number, on the little fox in the toolbar.
|
||||
* The number reflects the current number of pending transactions or message signatures needing user approval.
|
||||
*/
|
||||
function updateBadge () {
|
||||
var label = ''
|
||||
var unapprovedTxCount = controller.txController.getUnapprovedTxCount()
|
||||
@ -283,7 +406,9 @@ function setupController (initState, initLangCode) {
|
||||
// Etc...
|
||||
//
|
||||
|
||||
// popup trigger
|
||||
/**
|
||||
* Opens the browser popup for user confirmation
|
||||
*/
|
||||
function triggerUi () {
|
||||
extension.tabs.query({ active: true }, tabs => {
|
||||
const currentlyActiveMetamaskTab = Boolean(tabs.find(tab => openMetamaskTabsIDs[tab.id]))
|
||||
|
@ -1,44 +0,0 @@
|
||||
const MAINET_RPC_URL = 'https://mainnet.infura.io/metamask'
|
||||
const ROPSTEN_RPC_URL = 'https://ropsten.infura.io/metamask'
|
||||
const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask'
|
||||
const RINKEBY_RPC_URL = 'https://rinkeby.infura.io/metamask'
|
||||
const LOCALHOST_RPC_URL = 'http://localhost:8545'
|
||||
|
||||
const MAINET_RPC_URL_BETA = 'https://mainnet.infura.io/metamask2'
|
||||
const ROPSTEN_RPC_URL_BETA = 'https://ropsten.infura.io/metamask2'
|
||||
const KOVAN_RPC_URL_BETA = 'https://kovan.infura.io/metamask2'
|
||||
const RINKEBY_RPC_URL_BETA = 'https://rinkeby.infura.io/metamask2'
|
||||
|
||||
const DEFAULT_RPC = 'rinkeby'
|
||||
const OLD_UI_NETWORK_TYPE = 'network'
|
||||
const BETA_UI_NETWORK_TYPE = 'networkBeta'
|
||||
|
||||
global.METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
||||
|
||||
module.exports = {
|
||||
network: {
|
||||
localhost: LOCALHOST_RPC_URL,
|
||||
mainnet: MAINET_RPC_URL,
|
||||
ropsten: ROPSTEN_RPC_URL,
|
||||
kovan: KOVAN_RPC_URL,
|
||||
rinkeby: RINKEBY_RPC_URL,
|
||||
},
|
||||
// Used for beta UI
|
||||
networkBeta: {
|
||||
localhost: LOCALHOST_RPC_URL,
|
||||
mainnet: MAINET_RPC_URL_BETA,
|
||||
ropsten: ROPSTEN_RPC_URL_BETA,
|
||||
kovan: KOVAN_RPC_URL_BETA,
|
||||
rinkeby: RINKEBY_RPC_URL_BETA,
|
||||
},
|
||||
networkNames: {
|
||||
3: 'Ropsten',
|
||||
4: 'Rinkeby',
|
||||
42: 'Kovan',
|
||||
},
|
||||
enums: {
|
||||
DEFAULT_RPC,
|
||||
OLD_UI_NETWORK_TYPE,
|
||||
BETA_UI_NETWORK_TYPE,
|
||||
},
|
||||
}
|
@ -23,6 +23,9 @@ if (shouldInjectWeb3()) {
|
||||
setupStreams()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a script tag that injects inpage.js
|
||||
*/
|
||||
function setupInjection () {
|
||||
try {
|
||||
// inject in-page script
|
||||
@ -37,6 +40,10 @@ function setupInjection () {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up two-way communication streams between the
|
||||
* browser extension and local per-page browser context
|
||||
*/
|
||||
function setupStreams () {
|
||||
// setup communication to page and plugin
|
||||
const pageStream = new LocalMessageDuplexStream({
|
||||
@ -89,17 +96,34 @@ function setupStreams () {
|
||||
mux.ignoreStream('publicConfig')
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Error handler for page to plugin stream disconnections
|
||||
*
|
||||
* @param {string} remoteLabel Remote stream name
|
||||
* @param {Error} err Stream connection error
|
||||
*/
|
||||
function logStreamDisconnectWarning (remoteLabel, err) {
|
||||
let warningMsg = `MetamaskContentscript - lost connection to ${remoteLabel}`
|
||||
if (err) warningMsg += '\n' + err.stack
|
||||
console.warn(warningMsg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if Web3 should be injected
|
||||
*
|
||||
* @returns {boolean} {@code true} if Web3 should be injected
|
||||
*/
|
||||
function shouldInjectWeb3 () {
|
||||
return doctypeCheck() && suffixCheck()
|
||||
&& documentElementCheck() && !blacklistedDomainCheck()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the doctype of the current document if it exists
|
||||
*
|
||||
* @returns {boolean} {@code true} if the doctype is html or if none exists
|
||||
*/
|
||||
function doctypeCheck () {
|
||||
const doctype = window.document.doctype
|
||||
if (doctype) {
|
||||
@ -109,6 +133,11 @@ function doctypeCheck () {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current document extension
|
||||
*
|
||||
* @returns {boolean} {@code true} if the current extension is not prohibited
|
||||
*/
|
||||
function suffixCheck () {
|
||||
var prohibitedTypes = ['xml', 'pdf']
|
||||
var currentUrl = window.location.href
|
||||
@ -122,6 +151,11 @@ function suffixCheck () {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the documentElement of the current document
|
||||
*
|
||||
* @returns {boolean} {@code true} if the documentElement is an html node or if none exists
|
||||
*/
|
||||
function documentElementCheck () {
|
||||
var documentElement = document.documentElement.nodeName
|
||||
if (documentElement) {
|
||||
@ -130,6 +164,11 @@ function documentElementCheck () {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current domain is blacklisted
|
||||
*
|
||||
* @returns {boolean} {@code true} if the current domain is blacklisted
|
||||
*/
|
||||
function blacklistedDomainCheck () {
|
||||
var blacklistedDomains = [
|
||||
'uscourts.gov',
|
||||
@ -148,6 +187,9 @@ function blacklistedDomainCheck () {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects the current page to a phishing information page
|
||||
*/
|
||||
function redirectToPhishingWarning () {
|
||||
console.log('MetaMask - redirecting to phishing warning')
|
||||
window.location.href = 'https://metamask.io/phishing.html'
|
||||
|
@ -2,8 +2,24 @@ const ObservableStore = require('obs-store')
|
||||
const extend = require('xtend')
|
||||
const BalanceController = require('./balance')
|
||||
|
||||
class ComputedbalancesController {
|
||||
/**
|
||||
* @typedef {Object} ComputedBalancesOptions
|
||||
* @property {Object} accountTracker Account tracker store reference
|
||||
* @property {Object} txController Token controller reference
|
||||
* @property {Object} blockTracker Block tracker reference
|
||||
* @property {Object} initState Initial state to populate this internal store with
|
||||
*/
|
||||
|
||||
/**
|
||||
* Background controller responsible for syncing
|
||||
* and computing ETH balances for all accounts
|
||||
*/
|
||||
class ComputedbalancesController {
|
||||
/**
|
||||
* Creates a new controller instance
|
||||
*
|
||||
* @param {ComputedBalancesOptions} [opts] Controller configuration parameters
|
||||
*/
|
||||
constructor (opts = {}) {
|
||||
const { accountTracker, txController, blockTracker } = opts
|
||||
this.accountTracker = accountTracker
|
||||
@ -19,6 +35,9 @@ class ComputedbalancesController {
|
||||
this._initBalanceUpdating()
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates balances associated with each internal address
|
||||
*/
|
||||
updateAllBalances () {
|
||||
Object.keys(this.balances).forEach((balance) => {
|
||||
const address = balance.address
|
||||
@ -26,12 +45,23 @@ class ComputedbalancesController {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes internal address tracking
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_initBalanceUpdating () {
|
||||
const store = this.accountTracker.store.getState()
|
||||
this.syncAllAccountsFromStore(store)
|
||||
this.accountTracker.store.subscribe(this.syncAllAccountsFromStore.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses current account state to sync and track all
|
||||
* addresses associated with the current account
|
||||
*
|
||||
* @param {{ accounts: Object }} store Account tracking state
|
||||
*/
|
||||
syncAllAccountsFromStore (store) {
|
||||
const upstream = Object.keys(store.accounts)
|
||||
const balances = Object.keys(this.balances)
|
||||
@ -50,6 +80,13 @@ class ComputedbalancesController {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally establishes a new subscription
|
||||
* to track an address associated with the current
|
||||
* account
|
||||
*
|
||||
* @param {string} address Address to conditionally subscribe to
|
||||
*/
|
||||
trackAddressIfNotAlready (address) {
|
||||
const state = this.store.getState()
|
||||
if (!(address in state.computedBalances)) {
|
||||
@ -57,6 +94,12 @@ class ComputedbalancesController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a new subscription to track an
|
||||
* address associated with the current account
|
||||
*
|
||||
* @param {string} address Address to conditionally subscribe to
|
||||
*/
|
||||
trackAddress (address) {
|
||||
const updater = new BalanceController({
|
||||
address,
|
||||
|
56
app/scripts/controllers/network/enums.js
Normal file
56
app/scripts/controllers/network/enums.js
Normal file
@ -0,0 +1,56 @@
|
||||
const ROPSTEN = 'ropsten'
|
||||
const RINKEBY = 'rinkeby'
|
||||
const KOVAN = 'kovan'
|
||||
const MAINNET = 'mainnet'
|
||||
const LOCALHOST = 'localhost'
|
||||
|
||||
const ROPSTEN_CODE = 3
|
||||
const RINKEYBY_CODE = 4
|
||||
const KOVAN_CODE = 42
|
||||
|
||||
const ROPSTEN_DISPLAY_NAME = 'Ropsten'
|
||||
const RINKEBY_DISPLAY_NAME = 'Rinkeby'
|
||||
const KOVAN_DISPLAY_NAME = 'Kovan'
|
||||
const MAINNET_DISPLAY_NAME = 'Main Ethereum Network'
|
||||
|
||||
const MAINNET_RPC_URL = 'https://mainnet.infura.io/metamask'
|
||||
const ROPSTEN_RPC_URL = 'https://ropsten.infura.io/metamask'
|
||||
const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask'
|
||||
const RINKEBY_RPC_URL = 'https://rinkeby.infura.io/metamask'
|
||||
const LOCALHOST_RPC_URL = 'http://localhost:8545'
|
||||
|
||||
const MAINNET_RPC_URL_BETA = 'https://mainnet.infura.io/metamask2'
|
||||
const ROPSTEN_RPC_URL_BETA = 'https://ropsten.infura.io/metamask2'
|
||||
const KOVAN_RPC_URL_BETA = 'https://kovan.infura.io/metamask2'
|
||||
const RINKEBY_RPC_URL_BETA = 'https://rinkeby.infura.io/metamask2'
|
||||
|
||||
const DEFAULT_NETWORK = 'rinkeby'
|
||||
const OLD_UI_NETWORK_TYPE = 'network'
|
||||
const BETA_UI_NETWORK_TYPE = 'networkBeta'
|
||||
|
||||
module.exports = {
|
||||
ROPSTEN,
|
||||
RINKEBY,
|
||||
KOVAN,
|
||||
MAINNET,
|
||||
LOCALHOST,
|
||||
ROPSTEN_CODE,
|
||||
RINKEYBY_CODE,
|
||||
KOVAN_CODE,
|
||||
ROPSTEN_DISPLAY_NAME,
|
||||
RINKEBY_DISPLAY_NAME,
|
||||
KOVAN_DISPLAY_NAME,
|
||||
MAINNET_DISPLAY_NAME,
|
||||
MAINNET_RPC_URL,
|
||||
ROPSTEN_RPC_URL,
|
||||
KOVAN_RPC_URL,
|
||||
RINKEBY_RPC_URL,
|
||||
LOCALHOST_RPC_URL,
|
||||
MAINNET_RPC_URL_BETA,
|
||||
ROPSTEN_RPC_URL_BETA,
|
||||
KOVAN_RPC_URL_BETA,
|
||||
RINKEBY_RPC_URL_BETA,
|
||||
DEFAULT_NETWORK,
|
||||
OLD_UI_NETWORK_TYPE,
|
||||
BETA_UI_NETWORK_TYPE,
|
||||
}
|
2
app/scripts/controllers/network/index.js
Normal file
2
app/scripts/controllers/network/index.js
Normal file
@ -0,0 +1,2 @@
|
||||
const NetworkController = require('./network')
|
||||
module.exports = NetworkController
|
@ -7,11 +7,18 @@ const ObservableStore = require('obs-store')
|
||||
const ComposedStore = require('obs-store/lib/composed')
|
||||
const extend = require('xtend')
|
||||
const EthQuery = require('eth-query')
|
||||
const createEventEmitterProxy = require('../lib/events-proxy.js')
|
||||
const networkConfig = require('../config.js')
|
||||
const createEventEmitterProxy = require('../../lib/events-proxy.js')
|
||||
const log = require('loglevel')
|
||||
const { OLD_UI_NETWORK_TYPE, DEFAULT_RPC } = networkConfig.enums
|
||||
const INFURA_PROVIDER_TYPES = ['ropsten', 'rinkeby', 'kovan', 'mainnet']
|
||||
const {
|
||||
ROPSTEN,
|
||||
RINKEBY,
|
||||
KOVAN,
|
||||
MAINNET,
|
||||
OLD_UI_NETWORK_TYPE,
|
||||
DEFAULT_NETWORK,
|
||||
} = require('./enums')
|
||||
const { getNetworkEndpoints } = require('./util')
|
||||
const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET]
|
||||
|
||||
module.exports = class NetworkController extends EventEmitter {
|
||||
|
||||
@ -19,8 +26,8 @@ module.exports = class NetworkController extends EventEmitter {
|
||||
super()
|
||||
|
||||
this._networkEndpointVersion = OLD_UI_NETWORK_TYPE
|
||||
this._networkEndpoints = this.getNetworkEndpoints(OLD_UI_NETWORK_TYPE)
|
||||
this._defaultRpc = this._networkEndpoints[DEFAULT_RPC]
|
||||
this._networkEndpoints = getNetworkEndpoints(OLD_UI_NETWORK_TYPE)
|
||||
this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK]
|
||||
|
||||
config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider)
|
||||
this.networkStore = new ObservableStore('loading')
|
||||
@ -37,17 +44,13 @@ module.exports = class NetworkController extends EventEmitter {
|
||||
}
|
||||
|
||||
this._networkEndpointVersion = version
|
||||
this._networkEndpoints = this.getNetworkEndpoints(version)
|
||||
this._defaultRpc = this._networkEndpoints[DEFAULT_RPC]
|
||||
this._networkEndpoints = getNetworkEndpoints(version)
|
||||
this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK]
|
||||
const { type } = this.getProviderConfig()
|
||||
|
||||
return this.setProviderType(type, true)
|
||||
}
|
||||
|
||||
getNetworkEndpoints (version = OLD_UI_NETWORK_TYPE) {
|
||||
return networkConfig[version]
|
||||
}
|
||||
|
||||
initializeProvider (_providerParams) {
|
||||
this._baseProviderParams = _providerParams
|
||||
const { type, rpcTarget } = this.providerStore.getState()
|
65
app/scripts/controllers/network/util.js
Normal file
65
app/scripts/controllers/network/util.js
Normal file
@ -0,0 +1,65 @@
|
||||
const {
|
||||
ROPSTEN,
|
||||
RINKEBY,
|
||||
KOVAN,
|
||||
MAINNET,
|
||||
LOCALHOST,
|
||||
ROPSTEN_CODE,
|
||||
RINKEYBY_CODE,
|
||||
KOVAN_CODE,
|
||||
ROPSTEN_DISPLAY_NAME,
|
||||
RINKEBY_DISPLAY_NAME,
|
||||
KOVAN_DISPLAY_NAME,
|
||||
MAINNET_DISPLAY_NAME,
|
||||
MAINNET_RPC_URL,
|
||||
ROPSTEN_RPC_URL,
|
||||
KOVAN_RPC_URL,
|
||||
RINKEBY_RPC_URL,
|
||||
LOCALHOST_RPC_URL,
|
||||
MAINNET_RPC_URL_BETA,
|
||||
ROPSTEN_RPC_URL_BETA,
|
||||
KOVAN_RPC_URL_BETA,
|
||||
RINKEBY_RPC_URL_BETA,
|
||||
OLD_UI_NETWORK_TYPE,
|
||||
BETA_UI_NETWORK_TYPE,
|
||||
} = require('./enums')
|
||||
|
||||
const networkToNameMap = {
|
||||
[ROPSTEN]: ROPSTEN_DISPLAY_NAME,
|
||||
[RINKEBY]: RINKEBY_DISPLAY_NAME,
|
||||
[KOVAN]: KOVAN_DISPLAY_NAME,
|
||||
[MAINNET]: MAINNET_DISPLAY_NAME,
|
||||
[ROPSTEN_CODE]: ROPSTEN_DISPLAY_NAME,
|
||||
[RINKEYBY_CODE]: RINKEBY_DISPLAY_NAME,
|
||||
[KOVAN_CODE]: KOVAN_DISPLAY_NAME,
|
||||
}
|
||||
|
||||
const networkEndpointsMap = {
|
||||
[OLD_UI_NETWORK_TYPE]: {
|
||||
[LOCALHOST]: LOCALHOST_RPC_URL,
|
||||
[MAINNET]: MAINNET_RPC_URL,
|
||||
[ROPSTEN]: ROPSTEN_RPC_URL,
|
||||
[KOVAN]: KOVAN_RPC_URL,
|
||||
[RINKEBY]: RINKEBY_RPC_URL,
|
||||
},
|
||||
[BETA_UI_NETWORK_TYPE]: {
|
||||
[LOCALHOST]: LOCALHOST_RPC_URL,
|
||||
[MAINNET]: MAINNET_RPC_URL_BETA,
|
||||
[ROPSTEN]: ROPSTEN_RPC_URL_BETA,
|
||||
[KOVAN]: KOVAN_RPC_URL_BETA,
|
||||
[RINKEBY]: RINKEBY_RPC_URL_BETA,
|
||||
},
|
||||
}
|
||||
|
||||
const getNetworkDisplayName = key => networkToNameMap[key]
|
||||
|
||||
const getNetworkEndpoints = (networkType = OLD_UI_NETWORK_TYPE) => {
|
||||
return {
|
||||
...networkEndpointsMap[networkType],
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getNetworkDisplayName,
|
||||
getNetworkEndpoints,
|
||||
}
|
@ -39,14 +39,14 @@ class TokenRatesController {
|
||||
*/
|
||||
async fetchExchangeRate (address) {
|
||||
try {
|
||||
const response = await fetch(`https://exchanges.balanc3.net/prices?from=${address}&to=ETH&autoConversion=false&summaryOnly=true`)
|
||||
const response = await fetch(`https://metamask.dev.balanc3.net/prices?from=${address}&to=ETH&autoConversion=false&summaryOnly=true`)
|
||||
const json = await response.json()
|
||||
return json && json.length ? json[0].averagePrice : 0
|
||||
} catch (error) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Number} - Interval used to poll for exchange rates
|
||||
* @type {Number}
|
||||
*/
|
||||
set interval (interval) {
|
||||
this._handle && clearInterval(this._handle)
|
||||
@ -55,7 +55,7 @@ class TokenRatesController {
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Object} - Preferences controller instance
|
||||
* @type {Object}
|
||||
*/
|
||||
set preferences (preferences) {
|
||||
this._preferences && this._preferences.unsubscribe()
|
||||
@ -66,7 +66,7 @@ class TokenRatesController {
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Array} - Array of token objects with contract addresses
|
||||
* @type {Array}
|
||||
*/
|
||||
set tokens (tokens) {
|
||||
this._tokens = tokens
|
||||
|
@ -1,69 +1,97 @@
|
||||
const asmcrypto = require('asmcrypto.js')
|
||||
const Unibabel = require('browserify-unibabel')
|
||||
|
||||
/**
|
||||
* A Microsoft Edge-specific encryption class that exposes
|
||||
* the interface expected by eth-keykeyring-controller
|
||||
*/
|
||||
class EdgeEncryptor {
|
||||
/**
|
||||
* Encrypts an arbitrary object to ciphertext
|
||||
*
|
||||
* @param {string} password Used to generate a key to encrypt the data
|
||||
* @param {Object} dataObject Data to encrypt
|
||||
* @returns {Promise<string>} Promise resolving to an object with ciphertext
|
||||
*/
|
||||
encrypt (password, dataObject) {
|
||||
var salt = this._generateSalt()
|
||||
return this._keyFromPassword(password, salt)
|
||||
.then(function (key) {
|
||||
var data = JSON.stringify(dataObject)
|
||||
var dataBuffer = Unibabel.utf8ToBuffer(data)
|
||||
var vector = global.crypto.getRandomValues(new Uint8Array(16))
|
||||
var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
|
||||
|
||||
encrypt (password, dataObject) {
|
||||
var buffer = new Uint8Array(resultbuffer)
|
||||
var vectorStr = Unibabel.bufferToBase64(vector)
|
||||
var vaultStr = Unibabel.bufferToBase64(buffer)
|
||||
return JSON.stringify({
|
||||
data: vaultStr,
|
||||
iv: vectorStr,
|
||||
salt: salt,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var salt = this._generateSalt()
|
||||
return this._keyFromPassword(password, salt)
|
||||
.then(function (key) {
|
||||
/**
|
||||
* Decrypts an arbitrary object from ciphertext
|
||||
*
|
||||
* @param {string} password Used to generate a key to decrypt the data
|
||||
* @param {string} text Ciphertext of an encrypted object
|
||||
* @returns {Promise<Object>} Promise resolving to copy of decrypted object
|
||||
*/
|
||||
decrypt (password, text) {
|
||||
const payload = JSON.parse(text)
|
||||
const salt = payload.salt
|
||||
return this._keyFromPassword(password, salt)
|
||||
.then(function (key) {
|
||||
const encryptedData = Unibabel.base64ToBuffer(payload.data)
|
||||
const vector = Unibabel.base64ToBuffer(payload.iv)
|
||||
return new Promise((resolve, reject) => {
|
||||
var result
|
||||
try {
|
||||
result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
|
||||
} catch (err) {
|
||||
return reject(new Error('Incorrect password'))
|
||||
}
|
||||
const decryptedData = new Uint8Array(result)
|
||||
const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
|
||||
const decryptedObj = JSON.parse(decryptedStr)
|
||||
resolve(decryptedObj)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
var data = JSON.stringify(dataObject)
|
||||
var dataBuffer = Unibabel.utf8ToBuffer(data)
|
||||
var vector = global.crypto.getRandomValues(new Uint8Array(16))
|
||||
var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
|
||||
/**
|
||||
* Retrieves a cryptographic key using a password
|
||||
*
|
||||
* @private
|
||||
* @param {string} password Password used to unlock a cryptographic key
|
||||
* @param {string} salt Random base64 data
|
||||
* @returns {Promise<Object>} Promise resolving to a derived key
|
||||
*/
|
||||
_keyFromPassword (password, salt) {
|
||||
|
||||
var buffer = new Uint8Array(resultbuffer)
|
||||
var vectorStr = Unibabel.bufferToBase64(vector)
|
||||
var vaultStr = Unibabel.bufferToBase64(buffer)
|
||||
return JSON.stringify({
|
||||
data: vaultStr,
|
||||
iv: vectorStr,
|
||||
salt: salt,
|
||||
})
|
||||
})
|
||||
}
|
||||
var passBuffer = Unibabel.utf8ToBuffer(password)
|
||||
var saltBuffer = Unibabel.base64ToBuffer(salt)
|
||||
return new Promise((resolve) => {
|
||||
var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
|
||||
resolve(key)
|
||||
})
|
||||
}
|
||||
|
||||
decrypt (password, text) {
|
||||
|
||||
const payload = JSON.parse(text)
|
||||
const salt = payload.salt
|
||||
return this._keyFromPassword(password, salt)
|
||||
.then(function (key) {
|
||||
const encryptedData = Unibabel.base64ToBuffer(payload.data)
|
||||
const vector = Unibabel.base64ToBuffer(payload.iv)
|
||||
return new Promise((resolve, reject) => {
|
||||
var result
|
||||
try {
|
||||
result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
|
||||
} catch (err) {
|
||||
return reject(new Error('Incorrect password'))
|
||||
}
|
||||
const decryptedData = new Uint8Array(result)
|
||||
const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
|
||||
const decryptedObj = JSON.parse(decryptedStr)
|
||||
resolve(decryptedObj)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
_keyFromPassword (password, salt) {
|
||||
|
||||
var passBuffer = Unibabel.utf8ToBuffer(password)
|
||||
var saltBuffer = Unibabel.base64ToBuffer(salt)
|
||||
return new Promise((resolve) => {
|
||||
var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
|
||||
resolve(key)
|
||||
})
|
||||
}
|
||||
|
||||
_generateSalt (byteCount = 32) {
|
||||
var view = new Uint8Array(byteCount)
|
||||
global.crypto.getRandomValues(view)
|
||||
var b64encoded = btoa(String.fromCharCode.apply(null, view))
|
||||
return b64encoded
|
||||
}
|
||||
/**
|
||||
* Generates random base64 encoded data
|
||||
*
|
||||
* @private
|
||||
* @returns {string} Randomized base64 encoded data
|
||||
*/
|
||||
_generateSalt (byteCount = 32) {
|
||||
var view = new Uint8Array(byteCount)
|
||||
global.crypto.getRandomValues(view)
|
||||
var b64encoded = btoa(String.fromCharCode.apply(null, view))
|
||||
return b64encoded
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EdgeEncryptor
|
||||
|
@ -1,15 +1,24 @@
|
||||
// test and development environment variables
|
||||
const env = process.env.METAMASK_ENV
|
||||
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
|
||||
const { DEFAULT_NETWORK, MAINNET } = require('./controllers/network/enums')
|
||||
|
||||
//
|
||||
// The default state of MetaMask
|
||||
//
|
||||
module.exports = {
|
||||
/**
|
||||
* @typedef {Object} FirstTimeState
|
||||
* @property {Object} config Initial configuration parameters
|
||||
* @property {Object} NetworkController Network controller state
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {FirstTimeState}
|
||||
*/
|
||||
const initialState = {
|
||||
config: {},
|
||||
NetworkController: {
|
||||
provider: {
|
||||
type: (METAMASK_DEBUG || env === 'test') ? 'rinkeby' : 'mainnet',
|
||||
type: (METAMASK_DEBUG || env === 'test') ? DEFAULT_NETWORK : MAINNET,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = initialState
|
||||
|
@ -42,20 +42,20 @@ log.debug('MetaMask - injected web3')
|
||||
setupDappAutoReload(web3, inpageProvider.publicConfigStore)
|
||||
|
||||
// set web3 defaultAccount
|
||||
|
||||
inpageProvider.publicConfigStore.subscribe(function (state) {
|
||||
web3.eth.defaultAccount = state.selectedAddress
|
||||
})
|
||||
|
||||
//
|
||||
// util
|
||||
//
|
||||
|
||||
// need to make sure we aren't affected by overlapping namespaces
|
||||
// and that we dont affect the app with our namespace
|
||||
// mostly a fix for web3's BigNumber if AMD's "define" is defined...
|
||||
var __define
|
||||
|
||||
/**
|
||||
* Caches reference to global define object and deletes it to
|
||||
* avoid conflicts with other global define objects, such as
|
||||
* AMD's define function
|
||||
*/
|
||||
function cleanContextForImports () {
|
||||
__define = global.define
|
||||
try {
|
||||
@ -65,6 +65,9 @@ function cleanContextForImports () {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores global define object from cached reference
|
||||
*/
|
||||
function restoreContextAfterImports () {
|
||||
try {
|
||||
global.define = __define
|
||||
|
@ -1,12 +1,11 @@
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const normalize = require('eth-sig-util').normalize
|
||||
const MetamaskConfig = require('../config.js')
|
||||
|
||||
|
||||
const MAINNET_RPC = MetamaskConfig.network.mainnet
|
||||
const ROPSTEN_RPC = MetamaskConfig.network.ropsten
|
||||
const KOVAN_RPC = MetamaskConfig.network.kovan
|
||||
const RINKEBY_RPC = MetamaskConfig.network.rinkeby
|
||||
const {
|
||||
MAINNET_RPC_URL,
|
||||
ROPSTEN_RPC_URL,
|
||||
KOVAN_RPC_URL,
|
||||
RINKEBY_RPC_URL,
|
||||
} = require('../controllers/network/enums')
|
||||
|
||||
/* The config-manager is a convenience object
|
||||
* wrapping a pojo-migrator.
|
||||
@ -174,19 +173,19 @@ ConfigManager.prototype.getCurrentRpcAddress = function () {
|
||||
switch (provider.type) {
|
||||
|
||||
case 'mainnet':
|
||||
return MAINNET_RPC
|
||||
return MAINNET_RPC_URL
|
||||
|
||||
case 'ropsten':
|
||||
return ROPSTEN_RPC
|
||||
return ROPSTEN_RPC_URL
|
||||
|
||||
case 'kovan':
|
||||
return KOVAN_RPC
|
||||
return KOVAN_RPC_URL
|
||||
|
||||
case 'rinkeby':
|
||||
return RINKEBY_RPC
|
||||
return RINKEBY_RPC_URL
|
||||
|
||||
default:
|
||||
return provider && provider.rpcTarget ? provider.rpcTarget : RINKEBY_RPC
|
||||
return provider && provider.rpcTarget ? provider.rpcTarget : RINKEBY_RPC_URL
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,10 @@
|
||||
module.exports = createProviderMiddleware
|
||||
|
||||
// forward requests to provider
|
||||
/**
|
||||
* Forwards an HTTP request to the current Web3 provider
|
||||
*
|
||||
* @param {{ provider: Object }} config Configuration containing current Web3 provider
|
||||
*/
|
||||
function createProviderMiddleware ({ provider }) {
|
||||
return (req, res, next, end) => {
|
||||
provider.sendAsync(req, (err, _res) => {
|
||||
|
@ -6,6 +6,13 @@ module.exports = PortDuplexStream
|
||||
|
||||
inherits(PortDuplexStream, Duplex)
|
||||
|
||||
/**
|
||||
* Creates a stream that's both readable and writable.
|
||||
* The stream supports arbitrary objects.
|
||||
*
|
||||
* @class
|
||||
* @param {Object} port Remote Port object
|
||||
*/
|
||||
function PortDuplexStream (port) {
|
||||
Duplex.call(this, {
|
||||
objectMode: true,
|
||||
@ -15,8 +22,13 @@ function PortDuplexStream (port) {
|
||||
port.onDisconnect.addListener(this._onDisconnect.bind(this))
|
||||
}
|
||||
|
||||
// private
|
||||
|
||||
/**
|
||||
* Callback triggered when a message is received from
|
||||
* the remote Port associated with this Stream.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} msg - Payload from the onMessage listener of Port
|
||||
*/
|
||||
PortDuplexStream.prototype._onMessage = function (msg) {
|
||||
if (Buffer.isBuffer(msg)) {
|
||||
delete msg._isBuffer
|
||||
@ -27,14 +39,31 @@ PortDuplexStream.prototype._onMessage = function (msg) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback triggered when the remote Port
|
||||
* associated with this Stream disconnects.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
PortDuplexStream.prototype._onDisconnect = function () {
|
||||
this.destroy()
|
||||
}
|
||||
|
||||
// stream plumbing
|
||||
|
||||
/**
|
||||
* Explicitly sets read operations to a no-op
|
||||
*/
|
||||
PortDuplexStream.prototype._read = noop
|
||||
|
||||
|
||||
/**
|
||||
* Called internally when data should be written to
|
||||
* this writable stream.
|
||||
*
|
||||
* @private
|
||||
* @param {*} msg Arbitrary object to write
|
||||
* @param {string} encoding Encoding to use when writing payload
|
||||
* @param {Function} cb Called when writing is complete or an error occurs
|
||||
*/
|
||||
PortDuplexStream.prototype._write = function (msg, encoding, cb) {
|
||||
try {
|
||||
if (Buffer.isBuffer(msg)) {
|
||||
|
@ -1,6 +1,9 @@
|
||||
|
||||
module.exports = setupMetamaskMeshMetrics
|
||||
|
||||
/**
|
||||
* Injects an iframe into the current document for testing
|
||||
*/
|
||||
function setupMetamaskMeshMetrics() {
|
||||
const testingContainer = document.createElement('iframe')
|
||||
testingContainer.src = 'https://metamask.github.io/mesh-testing/'
|
||||
|
@ -263,6 +263,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Constructor helper: initialize a public config store.
|
||||
* This store is used to make some config info available to Dapps synchronously.
|
||||
*/
|
||||
initPublicConfigStore () {
|
||||
// get init state
|
||||
@ -314,9 +315,11 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an api-object which is consumed by the UI
|
||||
* Returns an Object containing API Callback Functions.
|
||||
* These functions are the interface for the UI.
|
||||
* The API object can be transmitted over a stream with dnode.
|
||||
*
|
||||
* @returns {Object}
|
||||
* @returns {Object} Object containing API functions.
|
||||
*/
|
||||
getApi () {
|
||||
const keyringController = this.keyringController
|
||||
@ -407,16 +410,18 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Creates a new Vault(?) and create a new keychain(?)
|
||||
* Creates a new Vault and create a new keychain.
|
||||
*
|
||||
* A vault is ...
|
||||
* A vault, or KeyringController, is a controller that contains
|
||||
* many different account strategies, currently called Keyrings.
|
||||
* Creating it new means wiping all previous keyrings.
|
||||
*
|
||||
* A keychain is ...
|
||||
* A keychain, or keyring, controls many accounts with a single backup and signing strategy.
|
||||
* For example, a mnemonic phrase can generate many accounts, and is a keyring.
|
||||
*
|
||||
* @param {string} password
|
||||
*
|
||||
* @param {} password
|
||||
*
|
||||
* @returns {} vault
|
||||
* @returns {Object} vault
|
||||
*/
|
||||
async createNewVaultAndKeychain (password) {
|
||||
const release = await this.createVaultMutex.acquire()
|
||||
@ -442,7 +447,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Vault and restore an existent keychain
|
||||
* Create a new Vault and restore an existent keyring.
|
||||
* @param {} password
|
||||
* @param {} seed
|
||||
*/
|
||||
@ -459,11 +464,17 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type Identity
|
||||
* @property {string} name - The account nickname.
|
||||
* @property {string} address - The account's ethereum address, in lower case.
|
||||
* @property {boolean} mayBeFauceting - Whether this account is currently
|
||||
* receiving funds from our automatic Ropsten faucet.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the first Identiy from the passed Vault and selects the related address
|
||||
*
|
||||
* An Identity is ...
|
||||
*
|
||||
* @param {} vault
|
||||
*/
|
||||
selectFirstIdentity (vault) {
|
||||
@ -472,12 +483,12 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.preferencesController.setSelectedAddress(address)
|
||||
}
|
||||
|
||||
// ?
|
||||
// Opinionated Keyring Management
|
||||
//
|
||||
// Account Management
|
||||
//
|
||||
|
||||
/**
|
||||
* Adds a new account to ...
|
||||
* Adds a new account to the default (first) HD seed phrase Keyring.
|
||||
*
|
||||
* @returns {} keyState
|
||||
*/
|
||||
@ -507,6 +518,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
*
|
||||
* Used when creating a first vault, to allow confirmation.
|
||||
* Also used when revealing the seed words in the confirmation view.
|
||||
*
|
||||
* @param {Function} cb - A callback called on completion.
|
||||
*/
|
||||
placeSeedWords (cb) {
|
||||
|
||||
@ -526,6 +539,8 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
* Validity: seed phrase restores the accounts belonging to the current vault.
|
||||
*
|
||||
* Called when the first account is created and on unlocking the vault.
|
||||
*
|
||||
* @returns {Promise<string>} Seed phrase to be confirmed by the user.
|
||||
*/
|
||||
async verifySeedPhrase () {
|
||||
|
||||
@ -556,6 +571,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
*
|
||||
* The seed phrase remains available in the background process.
|
||||
*
|
||||
* @param {function} cb Callback function called with the current address.
|
||||
*/
|
||||
clearSeedWordCache (cb) {
|
||||
this.configManager.setSeedWords(null)
|
||||
@ -563,9 +579,13 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* ?
|
||||
* Clears the transaction history, to allow users to force-reset their nonces.
|
||||
* Mostly used in development environments, when networks are restarted with
|
||||
* the same network ID.
|
||||
*
|
||||
* @returns Promise<string> The current selected address.
|
||||
*/
|
||||
async resetAccount (cb) {
|
||||
async resetAccount () {
|
||||
const selectedAddress = this.preferencesController.getSelectedAddress()
|
||||
this.txController.wipeTransactions(selectedAddress)
|
||||
|
||||
@ -577,11 +597,13 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an account ... ?
|
||||
* Imports an account with the specified import strategy.
|
||||
* These are defined in app/scripts/account-import-strategies
|
||||
* Each strategy represents a different way of serializing an Ethereum key pair.
|
||||
*
|
||||
* @param {} strategy
|
||||
* @param {} args
|
||||
* @param {} cb
|
||||
* @param {string} strategy - A unique identifier for an account import strategy.
|
||||
* @param {any} args - The data required by that strategy to import an account.
|
||||
* @param {Function} cb - A callback function called with a state update on success.
|
||||
*/
|
||||
importAccountWithStrategy (strategy, args, cb) {
|
||||
accountImporter.importAccount(strategy, args)
|
||||
@ -595,13 +617,42 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Identity Management (sign)
|
||||
// Identity Management (signature operations)
|
||||
|
||||
// eth_sign methods:
|
||||
|
||||
/**
|
||||
* @param {} msgParams
|
||||
* @param {} cb
|
||||
* Called when a Dapp uses the eth_sign method, to request user approval.
|
||||
* eth_sign is a pure signature of arbitrary data. It is on a deprecation
|
||||
* path, since this data can be a transaction, or can leak private key
|
||||
* information.
|
||||
*
|
||||
* @param {Object} msgParams - The params passed to eth_sign.
|
||||
* @param {Function} cb = The callback function called with the signature.
|
||||
*/
|
||||
signMessage (msgParams, cb) {
|
||||
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)}`))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Signifies user intent to complete an eth_sign method.
|
||||
*
|
||||
* @param {Object} msgParams The params passed to eth_call.
|
||||
* @returns {Promise<Object>} Full state update.
|
||||
*/
|
||||
signMessage (msgParams) {
|
||||
log.info('MetaMaskController - signMessage')
|
||||
const msgId = msgParams.metamaskId
|
||||
|
||||
@ -620,148 +671,32 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
// Prefixed Style Message Signing Methods:
|
||||
|
||||
/**
|
||||
* Used to cancel a message submitted via eth_sign.
|
||||
*
|
||||
* @param {} msgParams
|
||||
* @param {} cb
|
||||
* @param {string} msgId - The id of the message to cancel.
|
||||
*/
|
||||
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)
|
||||
cancelMessage (msgId, cb) {
|
||||
const messageManager = this.messageManager
|
||||
messageManager.rejectMsg(msgId)
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb(null, this.getState())
|
||||
}
|
||||
return Promise.resolve(migratorOutput)
|
||||
}
|
||||
|
||||
// personal_sign methods:
|
||||
|
||||
/**
|
||||
* Import (lost) Accounts
|
||||
* Called when a dapp uses the personal_sign method.
|
||||
* This is identical to the Geth eth_sign method, and may eventually replace
|
||||
* eth_sign.
|
||||
*
|
||||
* @param {Object} {lostAccounts} @Array accounts <{ address, privateKey }>
|
||||
* We currently define our eth_sign and personal_sign mostly for legacy Dapps.
|
||||
*
|
||||
* Uses the array's private keys to create a new Simple Key Pair keychain
|
||||
* and add it to the keyring controller.
|
||||
* @param {Object} msgParams - The params of the message to sign & return to the Dapp.
|
||||
* @param {Function} cb - The callback function called with the signature.
|
||||
* Passed back to the requesting Dapp.
|
||||
*/
|
||||
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.'))
|
||||
@ -782,6 +717,52 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Signifies a user's approval to sign a personal_sign message in queue.
|
||||
* Triggers signing, and the callback function from newUnsignedPersonalMessage.
|
||||
*
|
||||
* @param {Object} msgParams - The params of the message to sign & return to the Dapp.
|
||||
* @returns {Promise<Object>} - A full state update.
|
||||
*/
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to cancel a personal_sign type message.
|
||||
* @param {string} msgId - The ID of the message to cancel.
|
||||
* @param {Function} cb - The callback function called with a full state update.
|
||||
*/
|
||||
cancelPersonalMessage (msgId, cb) {
|
||||
const messageManager = this.personalMessageManager
|
||||
messageManager.rejectMsg(msgId)
|
||||
if (cb && typeof cb === 'function') {
|
||||
cb(null, this.getState())
|
||||
}
|
||||
}
|
||||
|
||||
// eth_signTypedData methods
|
||||
|
||||
/**
|
||||
* Called when a dapp uses the eth_signTypedData method, per EIP 712.
|
||||
*
|
||||
* @param {Object} msgParams - The params passed to eth_signTypedData.
|
||||
* @param {Function} cb - The callback function, called with the signature.
|
||||
*/
|
||||
newUnsignedTypedMessage (msgParams, cb) {
|
||||
let msgId
|
||||
try {
|
||||
@ -804,22 +785,36 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
/**
|
||||
* The method for a user approving a call to eth_signTypedData, per EIP 712.
|
||||
* Triggers the callback in newUnsignedTypedMessage.
|
||||
*
|
||||
* @param {Object} msgParams - The params passed to eth_signTypedData.
|
||||
* @returns {Object} Full state update.
|
||||
*/
|
||||
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()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to cancel a eth_signTypedData type message.
|
||||
* @param {string} msgId - The ID of the message to cancel.
|
||||
* @param {Function} cb - The callback function called with a full state update.
|
||||
*/
|
||||
cancelTypedMessage (msgId, cb) {
|
||||
const messageManager = this.typedMessageManager
|
||||
messageManager.rejectMsg(msgId)
|
||||
@ -828,18 +823,119 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// MetaMask Version 3 Migration Account Restauration Methods
|
||||
|
||||
/**
|
||||
* A legacy method (probably dead code) that was used when we swapped out our
|
||||
* key management library that we depended on.
|
||||
*
|
||||
* Described in:
|
||||
* https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd
|
||||
*
|
||||
* @deprecated
|
||||
* @param {} migratorOutput
|
||||
*/
|
||||
restoreOldVaultAccounts (migratorOutput) {
|
||||
const { serialized } = migratorOutput
|
||||
return this.keyringController.restoreKeyring(serialized)
|
||||
.then(() => migratorOutput)
|
||||
}
|
||||
|
||||
/**
|
||||
* A legacy method used to record user confirmation that they understand
|
||||
* that some of their accounts have been recovered but should be backed up.
|
||||
*
|
||||
* @deprecated
|
||||
* @param {Function} cb - A callback function called with a full state update.
|
||||
*/
|
||||
markAccountsFound (cb) {
|
||||
this.configManager.setLostAccounts([])
|
||||
this.sendUpdate()
|
||||
cb(null, this.getState())
|
||||
}
|
||||
|
||||
/**
|
||||
* A legacy method (probably dead code) that was used when we swapped out our
|
||||
* key management library that we depended on.
|
||||
*
|
||||
* Described in:
|
||||
* https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd
|
||||
*
|
||||
* @deprecated
|
||||
* @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)
|
||||
}
|
||||
|
||||
/**
|
||||
* An account object
|
||||
* @typedef Account
|
||||
* @property string privateKey - The private key of the account.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Probably no longer needed, related to the Version 3 migration.
|
||||
* Imports a hash of accounts to private keys into the vault.
|
||||
*
|
||||
* Described in:
|
||||
* https://medium.com/metamask/metamask-3-migration-guide-914b79533cdd
|
||||
*
|
||||
* Uses the array's private keys to create a new Simple Key Pair keychain
|
||||
* and add it to the keyring controller.
|
||||
* @deprecated
|
||||
* @param {Account[]} lostAccounts -
|
||||
* @returns {Keyring[]} An array of the restored keyrings.
|
||||
*/
|
||||
importLostAccounts ({ lostAccounts }) {
|
||||
const privKeys = lostAccounts.map(acct => acct.privateKey)
|
||||
return this.keyringController.restoreKeyring({
|
||||
type: 'Simple Key Pair',
|
||||
data: privKeys,
|
||||
})
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// END (VAULT / KEYRING RELATED METHODS)
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Allows a user to try to speed up a transaction by retrying it
|
||||
* with higher gas.
|
||||
*
|
||||
* @param {string} txId - The ID of the transaction to speed up.
|
||||
* @param {Function} cb - The callback function called with a full state update.
|
||||
*/
|
||||
async retryTransaction (txId, cb) {
|
||||
await this.txController.retryTransaction(txId)
|
||||
const state = await this.getState()
|
||||
return state
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// PASSWORD MANAGEMENT
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Allows a user to begin the seed phrase recovery process.
|
||||
* @param {Function} cb - A callback function called when complete.
|
||||
*/
|
||||
markPasswordForgotten(cb) {
|
||||
this.configManager.setPasswordForgotten(true)
|
||||
this.sendUpdate()
|
||||
cb()
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows a user to end the seed phrase recovery process.
|
||||
* @param {Function} cb - A callback function called when complete.
|
||||
*/
|
||||
unMarkPasswordForgotten(cb) {
|
||||
this.configManager.setPasswordForgotten(false)
|
||||
this.sendUpdate()
|
||||
@ -850,6 +946,13 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
// SETUP
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Used to create a multiplexed stream for connecting to an untrusted context
|
||||
* like a Dapp or other extension.
|
||||
* @param {*} connectionStream - The Duplex stream to connect to.
|
||||
* @param {string} originDomain - The domain requesting the stream, which
|
||||
* may trigger a blacklist reload.
|
||||
*/
|
||||
setupUntrustedCommunication (connectionStream, originDomain) {
|
||||
// Check if new connection is blacklisted
|
||||
if (this.blacklistController.checkForPhishing(originDomain)) {
|
||||
@ -865,6 +968,16 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.setupPublicConfig(mux.createStream('publicConfig'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to create a multiplexed stream for connecting to a trusted context,
|
||||
* like our own user interfaces, which have the provider APIs, but also
|
||||
* receive the exported API from this controller, which includes trusted
|
||||
* functions, like the ability to approve transactions or sign messages.
|
||||
*
|
||||
* @param {*} connectionStream - The duplex stream to connect to.
|
||||
* @param {string} originDomain - The domain requesting the connection,
|
||||
* used in logging and error reporting.
|
||||
*/
|
||||
setupTrustedCommunication (connectionStream, originDomain) {
|
||||
// setup multiplexing
|
||||
const mux = setupMultiplex(connectionStream)
|
||||
@ -873,12 +986,25 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.setupProviderConnection(mux.createStream('provider'), originDomain)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we detect a suspicious domain. Requests the browser redirects
|
||||
* to our anti-phishing page.
|
||||
*
|
||||
* @private
|
||||
* @param {*} connectionStream - The duplex stream to the per-page script,
|
||||
* for sending the reload attempt to.
|
||||
* @param {string} hostname - The URL that triggered the suspicion.
|
||||
*/
|
||||
sendPhishingWarning (connectionStream, hostname) {
|
||||
const mux = setupMultiplex(connectionStream)
|
||||
const phishingStream = mux.createStream('phishing')
|
||||
phishingStream.write({ hostname })
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for providing our API over a stream using Dnode.
|
||||
* @param {*} outStream - The stream to provide our API over.
|
||||
*/
|
||||
setupControllerConnection (outStream) {
|
||||
const api = this.getApi()
|
||||
const dnode = Dnode(api)
|
||||
@ -897,6 +1023,11 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for serving our ethereum provider over a given stream.
|
||||
* @param {*} outStream - The stream to provide over.
|
||||
* @param {string} origin - The URI of the requesting resource.
|
||||
*/
|
||||
setupProviderConnection (outStream, origin) {
|
||||
// setup json rpc engine stack
|
||||
const engine = new RpcEngine()
|
||||
@ -926,6 +1057,16 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for providing our public config info over a stream.
|
||||
* This includes info we like to be synchronous if possible, like
|
||||
* the current selected account, and network ID.
|
||||
*
|
||||
* Since synchronous methods have been deprecated in web3,
|
||||
* this is a good candidate for deprecation.
|
||||
*
|
||||
* @param {*} outStream - The stream to provide public config over.
|
||||
*/
|
||||
setupPublicConfig (outStream) {
|
||||
pump(
|
||||
asStream(this.publicConfigStore),
|
||||
@ -936,10 +1077,21 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for emitting the full MetaMask state to all registered listeners.
|
||||
* @private
|
||||
*/
|
||||
privateSendUpdate () {
|
||||
this.emit('update', this.getState())
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for estimating a good gas price at recent prices.
|
||||
* Returns the lowest price that would have been included in
|
||||
* 50% of recent blocks.
|
||||
*
|
||||
* @returns {string} A hex representation of the suggested wei gas price.
|
||||
*/
|
||||
getGasPrice () {
|
||||
const { recentBlocksController } = this
|
||||
const { recentBlocks } = recentBlocksController.store.getState()
|
||||
@ -973,6 +1125,11 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
|
||||
// Log blocks
|
||||
|
||||
/**
|
||||
* A method for setting the user's preferred display currency.
|
||||
* @param {string} currencyCode - The code of the preferred currency.
|
||||
* @param {Function} cb - A callback function returning currency info.
|
||||
*/
|
||||
setCurrentCurrency (currencyCode, cb) {
|
||||
try {
|
||||
this.currencyController.setCurrentCurrency(currencyCode)
|
||||
@ -988,6 +1145,13 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for forwarding the user to the easiest way to obtain ether,
|
||||
* or the network "gas" currency, for the current selected network.
|
||||
*
|
||||
* @param {string} address - The address to fund.
|
||||
* @param {string} amount - The amount of ether desired, as a base 10 string.
|
||||
*/
|
||||
buyEth (address, amount) {
|
||||
if (!amount) amount = '5'
|
||||
const network = this.networkController.getNetworkState()
|
||||
@ -995,18 +1159,33 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
if (url) this.platform.openWindow({ url })
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for triggering a shapeshift currency transfer.
|
||||
* @param {string} depositAddress - The address to deposit to.
|
||||
* @property {string} depositType - An abbreviation of the type of crypto currency to be deposited.
|
||||
*/
|
||||
createShapeShiftTx (depositAddress, depositType) {
|
||||
this.shapeshiftController.createShapeShiftTx(depositAddress, depositType)
|
||||
}
|
||||
|
||||
// network
|
||||
|
||||
async setCustomRpc (rpcTarget, rpcList) {
|
||||
/**
|
||||
* A method for selecting a custom URL for an ethereum RPC provider.
|
||||
* @param {string} rpcTarget - A URL for a valid Ethereum RPC API.
|
||||
* @returns {Promise<String>} - The RPC Target URL confirmed.
|
||||
*/
|
||||
async setCustomRpc (rpcTarget) {
|
||||
this.networkController.setRpcTarget(rpcTarget)
|
||||
await this.preferencesController.updateFrequentRpcList(rpcTarget)
|
||||
return rpcTarget
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not to use the blockie identicon format.
|
||||
* @param {boolean} val - True for bockie, false for jazzicon.
|
||||
* @param {Function} cb - A callback function called when complete.
|
||||
*/
|
||||
setUseBlockie (val, cb) {
|
||||
try {
|
||||
this.preferencesController.setUseBlockie(val)
|
||||
@ -1016,6 +1195,11 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for setting a user's current locale, affecting the language rendered.
|
||||
* @param {string} key - Locale identifier.
|
||||
* @param {Function} cb - A callback function called when complete.
|
||||
*/
|
||||
setCurrentLocale (key, cb) {
|
||||
try {
|
||||
this.preferencesController.setCurrentLocale(key)
|
||||
@ -1025,6 +1209,11 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for initializing storage the first time.
|
||||
* @param {Object} initState - The default state to initialize with.
|
||||
* @private
|
||||
*/
|
||||
recordFirstTimeInfo (initState) {
|
||||
if (!('firstTimeInfo' in initState)) {
|
||||
initState.firstTimeInfo = {
|
||||
@ -1034,11 +1223,21 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for recording whether the MetaMask user interface is open or not.
|
||||
* @private
|
||||
* @param {boolean} open
|
||||
*/
|
||||
set isClientOpen (open) {
|
||||
this._isClientOpen = open
|
||||
this.isClientOpenAndUnlocked = this.getState().isUnlocked && open
|
||||
}
|
||||
|
||||
/**
|
||||
* A method for activating the retrieval of price data, which should only be fetched when the UI is visible.
|
||||
* @private
|
||||
* @param {boolean} active - True if price data should be getting fetched.
|
||||
*/
|
||||
set isClientOpenAndUnlocked (active) {
|
||||
this.tokenRatesController.isActive = active
|
||||
}
|
||||
|
@ -7,10 +7,14 @@ const launchMetamaskUi = require('../../ui')
|
||||
const StreamProvider = require('web3-stream-provider')
|
||||
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
|
||||
|
||||
|
||||
module.exports = initializePopup
|
||||
|
||||
|
||||
/**
|
||||
* Asynchronously initializes the MetaMask popup UI
|
||||
*
|
||||
* @param {{ container: Element, connectionStream: * }} config Popup configuration object
|
||||
* @param {Function} cb Called when initialization is complete
|
||||
*/
|
||||
function initializePopup ({ container, connectionStream }, cb) {
|
||||
// setup app
|
||||
async.waterfall([
|
||||
@ -19,6 +23,12 @@ function initializePopup ({ container, connectionStream }, cb) {
|
||||
], cb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes streamed connections to background scripts and a Web3 provider
|
||||
*
|
||||
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
|
||||
* @param {Function} cb Called when controller connection is established
|
||||
*/
|
||||
function connectToAccountManager (connectionStream, cb) {
|
||||
// setup communication with background
|
||||
// setup multiplexing
|
||||
@ -28,6 +38,11 @@ function connectToAccountManager (connectionStream, cb) {
|
||||
setupWeb3Connection(mx.createStream('provider'))
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a streamed connection to a Web3 provider
|
||||
*
|
||||
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
|
||||
*/
|
||||
function setupWeb3Connection (connectionStream) {
|
||||
var providerStream = new StreamProvider()
|
||||
providerStream.pipe(connectionStream).pipe(providerStream)
|
||||
@ -38,6 +53,12 @@ function setupWeb3Connection (connectionStream) {
|
||||
global.eth = new Eth(providerStream)
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a streamed connection to the background account manager
|
||||
*
|
||||
* @param {PortDuplexStream} connectionStream PortStream instance establishing a background connection
|
||||
* @param {Function} cb Called when the remote account manager connection is established
|
||||
*/
|
||||
function setupControllerConnection (connectionStream, cb) {
|
||||
// this is a really sneaky way of adding EventEmitter api
|
||||
// to a bi-directional dnode instance
|
||||
|
@ -1,471 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>controllers/transactions.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">controllers/transactions.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>const EventEmitter = require('events')
|
||||
const ObservableStore = require('obs-store')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
/**
|
||||
* @file The transaction controller. Receives incoming transactions, and emits events for various states of their processing.
|
||||
* @copyright Copyright (c) 2018 MetaMask
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
|
||||
const Transaction = require('ethereumjs-tx')
|
||||
const EthQuery = require('ethjs-query')
|
||||
const TransactionStateManager = require('../lib/tx-state-manager')
|
||||
const TxGasUtil = require('../lib/tx-gas-utils')
|
||||
const PendingTransactionTracker = require('../lib/pending-tx-tracker')
|
||||
const NonceTracker = require('../lib/nonce-tracker')
|
||||
|
||||
/*
|
||||
Transaction Controller is an aggregate of sub-controllers and trackers
|
||||
composing them in a way to be exposed to the metamask controller
|
||||
- txStateManager
|
||||
responsible for the state of a transaction and
|
||||
storing the transaction
|
||||
- pendingTxTracker
|
||||
watching blocks for transactions to be include
|
||||
and emitting confirmed events
|
||||
- txGasUtil
|
||||
gas calculations and safety buffering
|
||||
- nonceTracker
|
||||
calculating nonces
|
||||
*/
|
||||
|
||||
module.exports = class TransactionController extends EventEmitter {
|
||||
constructor (opts) {
|
||||
super()
|
||||
this.networkStore = opts.networkStore || new ObservableStore({})
|
||||
this.preferencesStore = opts.preferencesStore || new ObservableStore({})
|
||||
this.provider = opts.provider
|
||||
this.blockTracker = opts.blockTracker
|
||||
this.signEthTx = opts.signTransaction
|
||||
this.getGasPrice = opts.getGasPrice
|
||||
|
||||
this.memStore = new ObservableStore({})
|
||||
this.query = new EthQuery(this.provider)
|
||||
this.txGasUtil = new TxGasUtil(this.provider)
|
||||
|
||||
this.txStateManager = new TransactionStateManager({
|
||||
initState: opts.initState,
|
||||
txHistoryLimit: opts.txHistoryLimit,
|
||||
getNetwork: this.getNetwork.bind(this),
|
||||
})
|
||||
|
||||
this.txStateManager.getFilteredTxList({
|
||||
status: 'unapproved',
|
||||
loadingDefaults: true,
|
||||
}).forEach((tx) => {
|
||||
this.addTxDefaults(tx)
|
||||
.then((txMeta) => {
|
||||
txMeta.loadingDefaults = false
|
||||
this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot')
|
||||
}).catch((error) => {
|
||||
this.txStateManager.setTxStatusFailed(tx.id, error)
|
||||
})
|
||||
})
|
||||
|
||||
this.txStateManager.getFilteredTxList({
|
||||
status: 'approved',
|
||||
}).forEach((txMeta) => {
|
||||
const txSignError = new Error('Transaction found as "approved" during boot - possibly stuck during signing')
|
||||
this.txStateManager.setTxStatusFailed(txMeta.id, txSignError)
|
||||
})
|
||||
|
||||
|
||||
this.store = this.txStateManager.store
|
||||
this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
|
||||
this.nonceTracker = new NonceTracker({
|
||||
provider: this.provider,
|
||||
getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager),
|
||||
getConfirmedTransactions: (address) => {
|
||||
return this.txStateManager.getFilteredTxList({
|
||||
from: address,
|
||||
status: 'confirmed',
|
||||
err: undefined,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
this.pendingTxTracker = new PendingTransactionTracker({
|
||||
provider: this.provider,
|
||||
nonceTracker: this.nonceTracker,
|
||||
publishTransaction: (rawTx) => this.query.sendRawTransaction(rawTx),
|
||||
getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager),
|
||||
getCompletedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager),
|
||||
})
|
||||
|
||||
this.txStateManager.store.subscribe(() => this.emit('update:badge'))
|
||||
|
||||
this.pendingTxTracker.on('tx:warning', (txMeta) => {
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
|
||||
})
|
||||
this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId))
|
||||
this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager))
|
||||
this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
|
||||
if (!txMeta.firstRetryBlockNumber) {
|
||||
txMeta.firstRetryBlockNumber = latestBlockNumber
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:block-update')
|
||||
}
|
||||
})
|
||||
this.pendingTxTracker.on('tx:retry', (txMeta) => {
|
||||
if (!('retryCount' in txMeta)) txMeta.retryCount = 0
|
||||
txMeta.retryCount++
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
|
||||
})
|
||||
|
||||
this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker))
|
||||
// this is a little messy but until ethstore has been either
|
||||
// removed or redone this is to guard against the race condition
|
||||
this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker))
|
||||
this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker))
|
||||
// memstore is computed from a few different stores
|
||||
this._updateMemstore()
|
||||
this.txStateManager.store.subscribe(() => this._updateMemstore())
|
||||
this.networkStore.subscribe(() => this._updateMemstore())
|
||||
this.preferencesStore.subscribe(() => this._updateMemstore())
|
||||
}
|
||||
|
||||
getState () {
|
||||
return this.memStore.getState()
|
||||
}
|
||||
|
||||
getNetwork () {
|
||||
return this.networkStore.getState()
|
||||
}
|
||||
|
||||
getSelectedAddress () {
|
||||
return this.preferencesStore.getState().selectedAddress
|
||||
}
|
||||
|
||||
getUnapprovedTxCount () {
|
||||
return Object.keys(this.txStateManager.getUnapprovedTxList()).length
|
||||
}
|
||||
|
||||
getPendingTxCount (account) {
|
||||
return this.txStateManager.getPendingTransactions(account).length
|
||||
}
|
||||
|
||||
getFilteredTxList (opts) {
|
||||
return this.txStateManager.getFilteredTxList(opts)
|
||||
}
|
||||
|
||||
getChainId () {
|
||||
const networkState = this.networkStore.getState()
|
||||
const getChainId = parseInt(networkState)
|
||||
if (Number.isNaN(getChainId)) {
|
||||
return 0
|
||||
} else {
|
||||
return getChainId
|
||||
}
|
||||
}
|
||||
|
||||
wipeTransactions (address) {
|
||||
this.txStateManager.wipeTransactions(address)
|
||||
}
|
||||
|
||||
// Adds a tx to the txlist
|
||||
addTx (txMeta) {
|
||||
this.txStateManager.addTx(txMeta)
|
||||
this.emit(`${txMeta.id}:unapproved`, txMeta)
|
||||
}
|
||||
|
||||
async newUnapprovedTransaction (txParams, opts = {}) {
|
||||
log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`)
|
||||
const initialTxMeta = await this.addUnapprovedTransaction(txParams)
|
||||
initialTxMeta.origin = opts.origin
|
||||
this.txStateManager.updateTx(initialTxMeta, '#newUnapprovedTransaction - adding the origin')
|
||||
// listen for tx completion (success, fail)
|
||||
return new Promise((resolve, reject) => {
|
||||
this.txStateManager.once(`${initialTxMeta.id}:finished`, (finishedTxMeta) => {
|
||||
switch (finishedTxMeta.status) {
|
||||
case 'submitted':
|
||||
return resolve(finishedTxMeta.hash)
|
||||
case 'rejected':
|
||||
return reject(new Error('MetaMask Tx Signature: User denied transaction signature.'))
|
||||
case 'failed':
|
||||
return reject(new Error(finishedTxMeta.err.message))
|
||||
default:
|
||||
return reject(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async addUnapprovedTransaction (txParams) {
|
||||
// validate
|
||||
const normalizedTxParams = this._normalizeTxParams(txParams)
|
||||
this._validateTxParams(normalizedTxParams)
|
||||
// construct txMeta
|
||||
let txMeta = this.txStateManager.generateTxMeta({ txParams: normalizedTxParams })
|
||||
this.addTx(txMeta)
|
||||
this.emit('newUnapprovedTx', txMeta)
|
||||
// add default tx params
|
||||
try {
|
||||
txMeta = await this.addTxDefaults(txMeta)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
this.txStateManager.setTxStatusFailed(txMeta.id, error)
|
||||
throw error
|
||||
}
|
||||
txMeta.loadingDefaults = false
|
||||
// save txMeta
|
||||
this.txStateManager.updateTx(txMeta)
|
||||
|
||||
return txMeta
|
||||
}
|
||||
|
||||
async addTxDefaults (txMeta) {
|
||||
const txParams = txMeta.txParams
|
||||
// ensure value
|
||||
txMeta.gasPriceSpecified = Boolean(txParams.gasPrice)
|
||||
let gasPrice = txParams.gasPrice
|
||||
if (!gasPrice) {
|
||||
gasPrice = this.getGasPrice ? this.getGasPrice() : await this.query.gasPrice()
|
||||
}
|
||||
txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16))
|
||||
txParams.value = txParams.value || '0x0'
|
||||
// set gasLimit
|
||||
return await this.txGasUtil.analyzeGasUsage(txMeta)
|
||||
}
|
||||
|
||||
async retryTransaction (originalTxId) {
|
||||
const originalTxMeta = this.txStateManager.getTx(originalTxId)
|
||||
const lastGasPrice = originalTxMeta.txParams.gasPrice
|
||||
const txMeta = this.txStateManager.generateTxMeta({
|
||||
txParams: originalTxMeta.txParams,
|
||||
lastGasPrice,
|
||||
loadingDefaults: false,
|
||||
})
|
||||
this.addTx(txMeta)
|
||||
this.emit('newUnapprovedTx', txMeta)
|
||||
return txMeta
|
||||
}
|
||||
|
||||
async updateTransaction (txMeta) {
|
||||
this.txStateManager.updateTx(txMeta, 'confTx: user updated transaction')
|
||||
}
|
||||
|
||||
async updateAndApproveTransaction (txMeta) {
|
||||
this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction')
|
||||
await this.approveTransaction(txMeta.id)
|
||||
}
|
||||
|
||||
async approveTransaction (txId) {
|
||||
let nonceLock
|
||||
try {
|
||||
// approve
|
||||
this.txStateManager.setTxStatusApproved(txId)
|
||||
// get next nonce
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
const fromAddress = txMeta.txParams.from
|
||||
// wait for a nonce
|
||||
nonceLock = await this.nonceTracker.getNonceLock(fromAddress)
|
||||
// add nonce to txParams
|
||||
// if txMeta has lastGasPrice then it is a retry at same nonce with higher
|
||||
// gas price transaction and their for the nonce should not be calculated
|
||||
const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce
|
||||
txMeta.txParams.nonce = ethUtil.addHexPrefix(nonce.toString(16))
|
||||
// add nonce debugging information to txMeta
|
||||
txMeta.nonceDetails = nonceLock.nonceDetails
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction')
|
||||
// sign transaction
|
||||
const rawTx = await this.signTransaction(txId)
|
||||
await this.publishTransaction(txId, rawTx)
|
||||
// must set transaction to submitted/failed before releasing lock
|
||||
nonceLock.releaseLock()
|
||||
} catch (err) {
|
||||
this.txStateManager.setTxStatusFailed(txId, err)
|
||||
// must set transaction to submitted/failed before releasing lock
|
||||
if (nonceLock) nonceLock.releaseLock()
|
||||
// continue with error chain
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async signTransaction (txId) {
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
// add network/chain id
|
||||
const chainId = this.getChainId()
|
||||
const txParams = Object.assign({}, txMeta.txParams, { chainId })
|
||||
// sign tx
|
||||
const fromAddress = txParams.from
|
||||
const ethTx = new Transaction(txParams)
|
||||
await this.signEthTx(ethTx, fromAddress)
|
||||
// set state to signed
|
||||
this.txStateManager.setTxStatusSigned(txMeta.id)
|
||||
const rawTx = ethUtil.bufferToHex(ethTx.serialize())
|
||||
return rawTx
|
||||
}
|
||||
|
||||
async publishTransaction (txId, rawTx) {
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
txMeta.rawTx = rawTx
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#publishTransaction')
|
||||
const txHash = await this.query.sendRawTransaction(rawTx)
|
||||
this.setTxHash(txId, txHash)
|
||||
this.txStateManager.setTxStatusSubmitted(txId)
|
||||
}
|
||||
|
||||
async cancelTransaction (txId) {
|
||||
this.txStateManager.setTxStatusRejected(txId)
|
||||
}
|
||||
|
||||
// receives a txHash records the tx as signed
|
||||
setTxHash (txId, txHash) {
|
||||
// Add the tx hash to the persisted meta-tx object
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
txMeta.hash = txHash
|
||||
this.txStateManager.updateTx(txMeta, 'transactions#setTxHash')
|
||||
}
|
||||
|
||||
//
|
||||
// PRIVATE METHODS
|
||||
//
|
||||
|
||||
_normalizeTxParams (txParams) {
|
||||
// functions that handle normalizing of that key in txParams
|
||||
const whiteList = {
|
||||
from: from => ethUtil.addHexPrefix(from).toLowerCase(),
|
||||
to: to => ethUtil.addHexPrefix(txParams.to).toLowerCase(),
|
||||
nonce: nonce => ethUtil.addHexPrefix(nonce),
|
||||
value: value => ethUtil.addHexPrefix(value),
|
||||
data: data => ethUtil.addHexPrefix(data),
|
||||
gas: gas => ethUtil.addHexPrefix(gas),
|
||||
gasPrice: gasPrice => ethUtil.addHexPrefix(gasPrice),
|
||||
}
|
||||
|
||||
// apply only keys in the whiteList
|
||||
const normalizedTxParams = {}
|
||||
Object.keys(whiteList).forEach((key) => {
|
||||
if (txParams[key]) normalizedTxParams[key] = whiteList[key](txParams[key])
|
||||
})
|
||||
|
||||
return normalizedTxParams
|
||||
}
|
||||
|
||||
_validateTxParams (txParams) {
|
||||
this._validateFrom(txParams)
|
||||
this._validateRecipient(txParams)
|
||||
if ('value' in txParams) {
|
||||
const value = txParams.value.toString()
|
||||
if (value.includes('-')) {
|
||||
throw new Error(`Invalid transaction value of ${txParams.value} not a positive number.`)
|
||||
}
|
||||
|
||||
if (value.includes('.')) {
|
||||
throw new Error(`Invalid transaction value of ${txParams.value} number must be in wei`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_validateFrom (txParams) {
|
||||
if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`)
|
||||
if (!ethUtil.isValidAddress(txParams.from)) throw new Error('Invalid from address')
|
||||
}
|
||||
|
||||
_validateRecipient (txParams) {
|
||||
if (txParams.to === '0x' || txParams.to === null ) {
|
||||
if (txParams.data) {
|
||||
delete txParams.to
|
||||
} else {
|
||||
throw new Error('Invalid recipient address')
|
||||
}
|
||||
} else if ( txParams.to !== undefined && !ethUtil.isValidAddress(txParams.to) ) {
|
||||
throw new Error('Invalid recipient address')
|
||||
}
|
||||
return txParams
|
||||
}
|
||||
|
||||
_markNonceDuplicatesDropped (txId) {
|
||||
this.txStateManager.setTxStatusConfirmed(txId)
|
||||
// get the confirmed transactions nonce and from address
|
||||
const txMeta = this.txStateManager.getTx(txId)
|
||||
const { nonce, from } = txMeta.txParams
|
||||
const sameNonceTxs = this.txStateManager.getFilteredTxList({nonce, from})
|
||||
if (!sameNonceTxs.length) return
|
||||
// mark all same nonce transactions as dropped and give i a replacedBy hash
|
||||
sameNonceTxs.forEach((otherTxMeta) => {
|
||||
if (otherTxMeta.id === txId) return
|
||||
otherTxMeta.replacedBy = txMeta.hash
|
||||
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce')
|
||||
this.txStateManager.setTxStatusDropped(otherTxMeta.id)
|
||||
})
|
||||
}
|
||||
|
||||
_updateMemstore () {
|
||||
const unapprovedTxs = this.txStateManager.getUnapprovedTxList()
|
||||
const selectedAddressTxList = this.txStateManager.getFilteredTxList({
|
||||
from: this.getSelectedAddress(),
|
||||
metamaskNetworkId: this.getNetwork(),
|
||||
})
|
||||
this.memStore.updateState({ unapprovedTxs, selectedAddressTxList })
|
||||
}
|
||||
}
|
||||
</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>
|
@ -1,486 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>Global - 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">Global</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h3 class="subsection-title">Type Definitions</h3>
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="MetaMaskOptions">MetaMaskOptions</h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="metamask-controller.js.html">metamask-controller.js</a>, <a href="metamask-controller.js.html#line48">line 48</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>platform</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type"><a href="global.html#Platform">Platform</a></span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>An object including platform-specific functions.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="Platform">Platform</h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="platforms_extension.js.html">platforms/extension.js</a>, <a href="platforms_extension.js.html#line3">line 3</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>reload</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>A function to reload the application.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>openWindow</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Opens a URL in the web browser.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>getVersion</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Gets the current version of MetaMask.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>openExtensionInBrowser</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Opens the MetaMask UI in a full window.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>getPlatformInfo</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">function</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"><p>Callback function that returns info about the current platform.</p></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description">
|
||||
<p>An object that provides a variety of platform-specific functions.</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
<span class="param-type">object</span>
|
||||
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</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>
|
@ -1,275 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>Home - 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">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
controllers/transactions.js
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="controllers_transactions.js.html">controllers/transactions.js</a>, <a href="controllers_transactions.js.html#line4">line 4</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-copyright">Copyright:</dt>
|
||||
<dd class="tag-copyright"><ul class="dummy"><li>Copyright (c) 2018 MetaMask</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
<dt class="tag-license">License:</dt>
|
||||
<dd class="tag-license"><ul class="dummy"><li>MIT</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description"><p>The transaction controller. Receives incoming transactions, and emits events for various states of their processing.</p></div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
metamask-controller.js
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="metamask-controller.js.html">metamask-controller.js</a>, <a href="metamask-controller.js.html#line1">line 1</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dt class="tag-copyright">Copyright:</dt>
|
||||
<dd class="tag-copyright"><ul class="dummy"><li>Copyright (c) 2018 MetaMask</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
<dt class="tag-license">License:</dt>
|
||||
<dd class="tag-license"><ul class="dummy"><li>MIT</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="description"><p>The central metamask controller. Aggregates other controllers and exports an api.</p></div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</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>
|
File diff suppressed because it is too large
Load Diff
@ -1,229 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>exports - 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">exports</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
|
||||
<h2>
|
||||
exports
|
||||
</h2>
|
||||
|
||||
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="name" id="exports"><span class="type-signature"></span>new exports<span class="signature">(opts)</span><span class="type-signature"></span></h4>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="details">
|
||||
|
||||
|
||||
<dt class="tag-source">Source:</dt>
|
||||
<dd class="tag-source"><ul class="dummy"><li>
|
||||
<a href="metamask-controller.js.html">metamask-controller.js</a>, <a href="metamask-controller.js.html#line59">line 59</a>
|
||||
</li></ul></dd>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h5>Parameters:</h5>
|
||||
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
|
||||
<tr>
|
||||
|
||||
<td class="name"><code>opts</code></td>
|
||||
|
||||
|
||||
<td class="type">
|
||||
|
||||
|
||||
<span class="param-type">Object</span>
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<td class="description last"></td>
|
||||
</tr>
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</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>
|
@ -1,117 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="google" content="notranslate">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<title>platforms/extension.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">platforms/extension.js</h1>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source linenums"><code>const extension = require('extensionizer')
|
||||
|
||||
/**
|
||||
* An object that provides a variety of platform-specific functions.
|
||||
*
|
||||
* @typedef {object} Platform
|
||||
*
|
||||
* @property {Function} reload - A function to reload the application.
|
||||
* @property {Function} openWindow - Opens a URL in the web browser.
|
||||
* @property {Function} getVersion - Gets the current version of MetaMask.
|
||||
* @property {Function} openExtensionInBrowser - Opens the MetaMask UI in a full window.
|
||||
* @property {Function} getPlatformInfo - Callback function that returns info about the current platform.
|
||||
*/
|
||||
|
||||
class ExtensionPlatform {
|
||||
|
||||
//
|
||||
// Public
|
||||
//
|
||||
reload () {
|
||||
extension.runtime.reload()
|
||||
}
|
||||
|
||||
openWindow ({ url }) {
|
||||
extension.tabs.create({ url })
|
||||
}
|
||||
|
||||
getVersion () {
|
||||
return extension.runtime.getManifest().version
|
||||
}
|
||||
|
||||
openExtensionInBrowser () {
|
||||
const extensionURL = extension.runtime.getURL('home.html')
|
||||
this.openWindow({ url: extensionURL })
|
||||
}
|
||||
|
||||
getPlatformInfo (cb) {
|
||||
try {
|
||||
extension.runtime.getPlatformInfo((platform) => {
|
||||
cb(null, platform)
|
||||
})
|
||||
} catch (e) {
|
||||
cb(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ExtensionPlatform
|
||||
</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>
|
@ -1,25 +0,0 @@
|
||||
/*global document */
|
||||
(function() {
|
||||
var source = document.getElementsByClassName('prettyprint source linenums');
|
||||
var i = 0;
|
||||
var lineNumber = 0;
|
||||
var lineId;
|
||||
var lines;
|
||||
var totalLines;
|
||||
var anchorHash;
|
||||
|
||||
if (source && source[0]) {
|
||||
anchorHash = document.location.hash.substring(1);
|
||||
lines = source[0].getElementsByTagName('li');
|
||||
totalLines = lines.length;
|
||||
|
||||
for (; i < totalLines; i++) {
|
||||
lineNumber++;
|
||||
lineId = 'line' + lineNumber;
|
||||
lines[i].id = lineId;
|
||||
if (lineId === anchorHash) {
|
||||
lines[i].className += ' selected';
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -1,2 +0,0 @@
|
||||
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
|
||||
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
|
@ -1,28 +0,0 @@
|
||||
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
|
||||
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
|
||||
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
|
||||
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
|
||||
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
|
||||
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
|
||||
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
|
||||
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
|
||||
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
|
||||
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
|
||||
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
|
||||
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
|
||||
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
|
||||
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
|
||||
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
|
||||
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
|
||||
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
|
||||
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
|
||||
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
|
||||
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
|
||||
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
|
||||
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
|
||||
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
|
||||
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
|
||||
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
|
||||
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
|
||||
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
|
||||
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
|
19
docs/jsdocs/scripts/semantic.min.js
vendored
19
docs/jsdocs/scripts/semantic.min.js
vendored
File diff suppressed because one or more lines are too long
@ -1,626 +0,0 @@
|
||||
@import url(https://fonts.googleapis.com/css?family=Montserrat:400,700);
|
||||
|
||||
* {
|
||||
box-sizing: border-box
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #4d4e53;
|
||||
background-color: white;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
font-family: 'Helvetica Neue', Helvetica, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 160%;
|
||||
}
|
||||
|
||||
a,
|
||||
a:active {
|
||||
color: #606;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
article a {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
article a:hover, article a:active {
|
||||
border-bottom-color: #222;
|
||||
}
|
||||
|
||||
p, ul, ol, blockquote {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 300;
|
||||
font-size: 48px;
|
||||
margin: 1em 0 .5em;
|
||||
}
|
||||
|
||||
h1.page-title {
|
||||
font-size: 48px;
|
||||
margin: 1em 30px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
margin: 1.5em 0 .3em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
margin: 1.2em 0 .3em;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
margin: 1em 0 .2em;
|
||||
color: #4d4e53;
|
||||
}
|
||||
|
||||
h4.name {
|
||||
color: #fff;
|
||||
background: #6d426d;
|
||||
box-shadow: 0 .25em .5em #d3d3d3;
|
||||
border-top: 1px solid #d3d3d3;
|
||||
border-bottom: 1px solid #d3d3d3;
|
||||
margin: 1.5em 0 0.5em;
|
||||
padding: .75em 0 .75em 10px;
|
||||
}
|
||||
|
||||
h5, .container-overview .subsection-title {
|
||||
font-size: 120%;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 8px 0 3px 0;
|
||||
}
|
||||
|
||||
h6 {
|
||||
font-size: 100%;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 6px 0 3px 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
tt, code, kbd, samp {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
background: #f4f4f4;
|
||||
padding: 1px 5px;
|
||||
}
|
||||
|
||||
.class-description {
|
||||
font-size: 130%;
|
||||
line-height: 140%;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.class-description:empty {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
#main {
|
||||
float: right;
|
||||
min-width: 360px;
|
||||
width: calc(100% - 240px);
|
||||
}
|
||||
|
||||
header {
|
||||
display: block
|
||||
}
|
||||
|
||||
section {
|
||||
display: block;
|
||||
background-color: #fff;
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
.variation {
|
||||
display: none
|
||||
}
|
||||
|
||||
.signature-attributes {
|
||||
font-size: 60%;
|
||||
color: #eee;
|
||||
font-style: italic;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
nav {
|
||||
float: left;
|
||||
display: block;
|
||||
width: 250px;
|
||||
background: #fff;
|
||||
overflow: auto;
|
||||
position: fixed;
|
||||
height: 100%;
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
nav h3 {
|
||||
margin-top: 12px;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
margin: 15px 0 10px;
|
||||
padding: 0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
/* font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; */
|
||||
font-size: 100%;
|
||||
line-height: 17px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
nav ul a,
|
||||
nav ul a:active {
|
||||
/* font-family: 'Montserrat', sans-serif; */
|
||||
line-height: 18px;
|
||||
padding: 0;
|
||||
/* display: block; */
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
nav a:hover,
|
||||
nav a:active {
|
||||
color: #606;
|
||||
}
|
||||
|
||||
nav > ul {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
nav > ul > li > a {
|
||||
color: #606;
|
||||
}
|
||||
|
||||
nav ul ul {
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
nav ul ul a {
|
||||
color: hsl(207, 1%, 60%);
|
||||
border-left: 1px solid hsl(207, 10%, 86%);
|
||||
}
|
||||
|
||||
nav ul ul a,
|
||||
nav ul ul a:active {
|
||||
padding-left: 20px
|
||||
}
|
||||
|
||||
nav h2 {
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
nav > h2 > a {
|
||||
display: block;
|
||||
margin: 10px 0 -10px;
|
||||
color: #606 !important;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: hsl(0, 0%, 28%);
|
||||
margin-left: 250px;
|
||||
display: block;
|
||||
padding: 15px;
|
||||
font-style: italic;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.ancestors {
|
||||
color: #999
|
||||
}
|
||||
|
||||
.ancestors a {
|
||||
color: #999 !important;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both
|
||||
}
|
||||
|
||||
.important {
|
||||
font-weight: bold;
|
||||
color: #950B02;
|
||||
}
|
||||
|
||||
.yes-def {
|
||||
text-indent: -1000px
|
||||
}
|
||||
|
||||
.type-signature {
|
||||
color: #CA79CA
|
||||
}
|
||||
|
||||
.type-signature:last-child {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.name, .signature {
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace
|
||||
}
|
||||
|
||||
.signature {
|
||||
color: #fc83ff;
|
||||
}
|
||||
|
||||
.details {
|
||||
margin-top: 6px;
|
||||
border-left: 2px solid #DDD;
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.details dt {
|
||||
width: 120px;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.details dd {
|
||||
margin-left: 70px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.details ul {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.details ul {
|
||||
list-style-type: none
|
||||
}
|
||||
|
||||
.details pre.prettyprint {
|
||||
margin: 0
|
||||
}
|
||||
|
||||
.details .object-value {
|
||||
padding-top: 0
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.code-caption {
|
||||
font-style: italic;
|
||||
font-size: 107%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.prettyprint {
|
||||
font-size: 14px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.prettyprint.source {
|
||||
width: inherit;
|
||||
line-height: 18px;
|
||||
display: block;
|
||||
background-color: #0d152a;
|
||||
color: #aeaeae;
|
||||
}
|
||||
|
||||
.prettyprint code {
|
||||
line-height: 18px;
|
||||
display: block;
|
||||
background-color: #0d152a;
|
||||
color: #4D4E53;
|
||||
}
|
||||
|
||||
.prettyprint > code {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.prettyprint .linenums code {
|
||||
padding: 0 15px
|
||||
}
|
||||
|
||||
.prettyprint .linenums li:first-of-type code {
|
||||
padding-top: 15px
|
||||
}
|
||||
|
||||
.prettyprint code span.line {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
.prettyprint.linenums {
|
||||
padding-left: 70px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.prettyprint.linenums ol {
|
||||
padding-left: 0
|
||||
}
|
||||
|
||||
.prettyprint.linenums li {
|
||||
border-left: 3px #34446B solid;
|
||||
}
|
||||
|
||||
.prettyprint.linenums li.selected, .prettyprint.linenums li.selected * {
|
||||
background-color: #34446B;
|
||||
}
|
||||
|
||||
.prettyprint.linenums li * {
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
.params, .props {
|
||||
border-spacing: 0;
|
||||
border: 1px solid #ddd;
|
||||
border-collapse: collapse;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.params .type {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.params code {
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.params td, .params .name, .props .name, .name code {
|
||||
color: #4D4E53;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.params td, .params th, .props td, .props th {
|
||||
margin: 0px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
padding: 10px;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.params td {
|
||||
border-top: 1px solid #eee
|
||||
}
|
||||
|
||||
.params thead tr, .props thead tr {
|
||||
background-color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.params .params thead tr, .props .props thead tr {
|
||||
background-color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.params td.description > p:first-child, .props td.description > p:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.params td.description > p:last-child, .props td.description > p:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
span.param-type, .params td .param-type, .param-type dd {
|
||||
color: #606;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', monospace
|
||||
}
|
||||
|
||||
.param-type dt, .param-type dd {
|
||||
display: inline-block
|
||||
}
|
||||
|
||||
.param-type {
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #454545
|
||||
}
|
||||
|
||||
/* navicon button */
|
||||
.navicon-button {
|
||||
display: none;
|
||||
position: relative;
|
||||
padding: 2.0625rem 1.5rem;
|
||||
transition: 0.25s;
|
||||
cursor: pointer;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
opacity: .8;
|
||||
}
|
||||
.navicon-button .navicon:before, .navicon-button .navicon:after {
|
||||
transition: 0.25s;
|
||||
}
|
||||
.navicon-button:hover {
|
||||
transition: 0.5s;
|
||||
opacity: 1;
|
||||
}
|
||||
.navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after {
|
||||
transition: 0.25s;
|
||||
}
|
||||
.navicon-button:hover .navicon:before {
|
||||
top: .825rem;
|
||||
}
|
||||
.navicon-button:hover .navicon:after {
|
||||
top: -.825rem;
|
||||
}
|
||||
|
||||
/* navicon */
|
||||
.navicon {
|
||||
position: relative;
|
||||
width: 2.5em;
|
||||
height: .3125rem;
|
||||
background: #000;
|
||||
transition: 0.3s;
|
||||
border-radius: 2.5rem;
|
||||
}
|
||||
.navicon:before, .navicon:after {
|
||||
display: block;
|
||||
content: "";
|
||||
height: .3125rem;
|
||||
width: 2.5rem;
|
||||
background: #000;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
transition: 0.3s 0.25s;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
.navicon:before {
|
||||
top: .625rem;
|
||||
}
|
||||
.navicon:after {
|
||||
top: -.625rem;
|
||||
}
|
||||
|
||||
/* open */
|
||||
.nav-trigger:checked + label:not(.steps) .navicon:before,
|
||||
.nav-trigger:checked + label:not(.steps) .navicon:after {
|
||||
top: 0 !important;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label .navicon:before,
|
||||
.nav-trigger:checked + label .navicon:after {
|
||||
transition: 0.5s;
|
||||
}
|
||||
|
||||
/* Minus */
|
||||
.nav-trigger:checked + label {
|
||||
-webkit-transform: scale(0.75);
|
||||
transform: scale(0.75);
|
||||
}
|
||||
|
||||
/* × and + */
|
||||
.nav-trigger:checked + label.plus .navicon,
|
||||
.nav-trigger:checked + label.x .navicon {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label.plus .navicon:before,
|
||||
.nav-trigger:checked + label.x .navicon:before {
|
||||
-webkit-transform: rotate(-45deg);
|
||||
transform: rotate(-45deg);
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label.plus .navicon:after,
|
||||
.nav-trigger:checked + label.x .navicon:after {
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
background: #FFF;
|
||||
}
|
||||
|
||||
.nav-trigger:checked + label.plus {
|
||||
-webkit-transform: scale(0.75) rotate(45deg);
|
||||
transform: scale(0.75) rotate(45deg);
|
||||
}
|
||||
|
||||
.nav-trigger:checked ~ nav {
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
.nav-trigger:checked ~ .overlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-trigger {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: hsla(0, 0%, 0%, 0.5);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 320px) and (max-width: 680px) {
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
nav {
|
||||
background: #FFF;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: -250px;
|
||||
z-index: 3;
|
||||
padding: 0 10px;
|
||||
transition: left 0.2s;
|
||||
}
|
||||
|
||||
.navicon-button {
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
top: 1.5em;
|
||||
right: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#main {
|
||||
width: 100%;
|
||||
min-width: 360px;
|
||||
}
|
||||
|
||||
#main h1.page-title {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
#main section {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
.ui.accordion .title:not(.ui) {
|
||||
padding: 0px;
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
.pln {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* string content */
|
||||
.str {
|
||||
color: #61ce3c;
|
||||
}
|
||||
|
||||
/* a keyword */
|
||||
.kwd {
|
||||
color: #fbde2d;
|
||||
}
|
||||
|
||||
/* a comment */
|
||||
.com {
|
||||
color: #aeaeae;
|
||||
}
|
||||
|
||||
/* a type name */
|
||||
.typ {
|
||||
color: #8da6ce;
|
||||
}
|
||||
|
||||
/* a literal value */
|
||||
.lit {
|
||||
color: #fbde2d;
|
||||
}
|
||||
|
||||
/* punctuation */
|
||||
.pun {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* lisp open bracket */
|
||||
.opn {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* lisp close bracket */
|
||||
.clo {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/* a markup tag name */
|
||||
.tag {
|
||||
color: #8da6ce;
|
||||
}
|
||||
|
||||
/* a markup attribute name */
|
||||
.atn {
|
||||
color: #fbde2d;
|
||||
}
|
||||
|
||||
/* a markup attribute value */
|
||||
.atv {
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
/* a declaration */
|
||||
.dec {
|
||||
color: #EF5050;
|
||||
}
|
||||
|
||||
/* a variable name */
|
||||
.var {
|
||||
color: #c82829;
|
||||
}
|
||||
|
||||
/* a function name */
|
||||
.fun {
|
||||
color: #4271ae;
|
||||
}
|
||||
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
364
docs/jsdocs/styles/semantic.min.css
vendored
364
docs/jsdocs/styles/semantic.min.css
vendored
File diff suppressed because one or more lines are too long
@ -35,7 +35,7 @@ const HDCreateVaultComplete = require('./keychains/hd/create-vault-complete')
|
||||
const HDRestoreVaultScreen = require('./keychains/hd/restore-vault')
|
||||
const RevealSeedConfirmation = require('./keychains/hd/recover-seed/confirmation')
|
||||
const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns
|
||||
const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
|
||||
const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums')
|
||||
|
||||
module.exports = connect(mapStateToProps)(App)
|
||||
|
||||
|
@ -8,7 +8,7 @@ const ShapeshiftForm = require('./shapeshift-form')
|
||||
const Loading = require('./loading')
|
||||
const AccountPanel = require('./account-panel')
|
||||
const RadioList = require('./custom-radio-list')
|
||||
const networkNames = require('../../../app/scripts/config.js').networkNames
|
||||
const { getNetworkDisplayName } = require('../../../app/scripts/controllers/network/util')
|
||||
|
||||
module.exports = connect(mapStateToProps)(BuyButtonSubview)
|
||||
|
||||
@ -142,7 +142,7 @@ BuyButtonSubview.prototype.primarySubview = function () {
|
||||
case '3':
|
||||
case '4':
|
||||
case '42':
|
||||
const networkName = networkNames[network]
|
||||
const networkName = getNetworkDisplayName(network)
|
||||
const label = `${networkName} Test Faucet`
|
||||
return (
|
||||
h('div.flex-column', {
|
||||
|
6
package-lock.json
generated
6
package-lock.json
generated
@ -19752,9 +19752,9 @@
|
||||
}
|
||||
},
|
||||
"raven-js": {
|
||||
"version": "3.24.0",
|
||||
"resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.24.0.tgz",
|
||||
"integrity": "sha512-+/ygcWib8PXAE7Xq53j1tYxCgkzFyp9z05LYAKp2PA9KwO4Ek74q1tkGwZyPWI/FoXOgas6jNtQ7O3tdPif6uA=="
|
||||
"version": "3.24.2",
|
||||
"resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.24.2.tgz",
|
||||
"integrity": "sha512-Dy/FHDxuo5pXywVf8Nrs5utB2juMATpkxWGqHjVbpFD3m8CaWYLvkB5SEXjWFUZ5GvUsrBVVQ+Dfcp0x6Z7SOg=="
|
||||
},
|
||||
"raw-body": {
|
||||
"version": "2.3.2",
|
||||
|
@ -103,7 +103,7 @@
|
||||
"ethereumjs-wallet": "^0.6.0",
|
||||
"etherscan-link": "^1.0.2",
|
||||
"ethjs": "^0.3.4",
|
||||
"ethjs-contract": "^0.1.9",
|
||||
"ethjs-contract": "^0.2.0",
|
||||
"ethjs-ens": "^2.0.0",
|
||||
"ethjs-query": "^0.3.4",
|
||||
"express": "^4.15.5",
|
||||
@ -152,7 +152,7 @@
|
||||
"pumpify": "^1.3.4",
|
||||
"qrcode-npm": "0.0.3",
|
||||
"ramda": "^0.24.1",
|
||||
"raven-js": "^3.24.0",
|
||||
"raven-js": "^3.24.2",
|
||||
"react": "^15.6.2",
|
||||
"react-addons-css-transition-group": "^15.6.0",
|
||||
"react-dom": "^15.6.2",
|
||||
@ -278,6 +278,6 @@
|
||||
"watchify": "^3.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
const assert = require('assert')
|
||||
const nock = require('nock')
|
||||
const NetworkController = require('../../app/scripts/controllers/network')
|
||||
const {
|
||||
getNetworkDisplayName,
|
||||
getNetworkEndpoints,
|
||||
} = require('../../app/scripts/controllers/network/util')
|
||||
|
||||
const { createTestProviderTools } = require('../stub/provider')
|
||||
const providerResultStub = {}
|
||||
@ -79,4 +83,40 @@ describe('# Network Controller', function () {
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('# Network utils', () => {
|
||||
it('getNetworkDisplayName should return the correct network name', () => {
|
||||
const tests = [
|
||||
{
|
||||
input: 3,
|
||||
expected: 'Ropsten',
|
||||
}, {
|
||||
input: 4,
|
||||
expected: 'Rinkeby',
|
||||
}, {
|
||||
input: 42,
|
||||
expected: 'Kovan',
|
||||
}, {
|
||||
input: 'ropsten',
|
||||
expected: 'Ropsten',
|
||||
}, {
|
||||
input: 'rinkeby',
|
||||
expected: 'Rinkeby',
|
||||
}, {
|
||||
input: 'kovan',
|
||||
expected: 'Kovan',
|
||||
}, {
|
||||
input: 'mainnet',
|
||||
expected: 'Main Ethereum Network',
|
||||
},
|
||||
]
|
||||
|
||||
tests.forEach(({ input, expected }) => assert.equal(getNetworkDisplayName(input), expected))
|
||||
})
|
||||
|
||||
it('getNetworkEndpoints should return the correct endpoints', () => {
|
||||
assert.equal(getNetworkEndpoints('networkBeta').ropsten, 'https://ropsten.infura.io/metamask2')
|
||||
assert.equal(getNetworkEndpoints('network').rinkeby, 'https://rinkeby.infura.io/metamask')
|
||||
})
|
||||
})
|
||||
|
@ -9,7 +9,7 @@ const ShapeshiftForm = require('./shapeshift-form')
|
||||
const Loading = require('./loading')
|
||||
const AccountPanel = require('./account-panel')
|
||||
const RadioList = require('./custom-radio-list')
|
||||
const networkNames = require('../../../app/scripts/config.js').networkNames
|
||||
const { getNetworkDisplayName } = require('../../../app/scripts/controllers/network/util')
|
||||
|
||||
BuyButtonSubview.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
@ -148,7 +148,7 @@ BuyButtonSubview.prototype.primarySubview = function () {
|
||||
case '3':
|
||||
case '4':
|
||||
case '42':
|
||||
const networkName = networkNames[network]
|
||||
const networkName = getNetworkDisplayName(network)
|
||||
const label = `${networkName} ${this.context.t('testFaucet')}`
|
||||
return (
|
||||
h('div.flex-column', {
|
||||
|
@ -3,12 +3,14 @@ const PropTypes = require('prop-types')
|
||||
const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const { withRouter } = require('react-router-dom')
|
||||
const { compose } = require('recompose')
|
||||
const actions = require('../../actions')
|
||||
const Dropdown = require('./components/dropdown').Dropdown
|
||||
const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem
|
||||
const NetworkDropdownIcon = require('./components/network-dropdown-icon')
|
||||
const R = require('ramda')
|
||||
|
||||
const { SETTINGS_ROUTE } = require('../../routes')
|
||||
|
||||
// classes from nodes of the toggle element.
|
||||
const notToggleElementClassnames = [
|
||||
@ -41,9 +43,6 @@ function mapDispatchToProps (dispatch) {
|
||||
setRpcTarget: (target) => {
|
||||
dispatch(actions.setRpcTarget(target))
|
||||
},
|
||||
showConfigPage: () => {
|
||||
dispatch(actions.showConfigPage())
|
||||
},
|
||||
showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()),
|
||||
hideNetworkDropdown: () => dispatch(actions.hideNetworkDropdown()),
|
||||
}
|
||||
@ -59,7 +58,10 @@ NetworkDropdown.contextTypes = {
|
||||
t: PropTypes.func,
|
||||
}
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(NetworkDropdown)
|
||||
module.exports = compose(
|
||||
withRouter,
|
||||
connect(mapStateToProps, mapDispatchToProps)
|
||||
)(NetworkDropdown)
|
||||
|
||||
|
||||
// TODO: specify default props and proptypes
|
||||
@ -227,7 +229,7 @@ NetworkDropdown.prototype.render = function () {
|
||||
DropdownMenuItem,
|
||||
{
|
||||
closeMenu: () => this.props.hideNetworkDropdown(),
|
||||
onClick: () => this.props.showConfigPage(),
|
||||
onClick: () => this.props.history.push(SETTINGS_ROUTE),
|
||||
style: dropdownMenuItemStyle,
|
||||
},
|
||||
[
|
||||
|
@ -4,7 +4,7 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('../../actions')
|
||||
const networkNames = require('../../../../app/scripts/config.js').networkNames
|
||||
const { getNetworkDisplayName } = require('../../../../app/scripts/controllers/network/util')
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
@ -52,7 +52,7 @@ BuyOptions.prototype.renderModalContentOption = function (title, header, onClick
|
||||
BuyOptions.prototype.render = function () {
|
||||
const { network, toCoinbase, address, toFaucet } = this.props
|
||||
const isTestNetwork = ['3', '4', '42'].find(n => n === network)
|
||||
const networkName = networkNames[network]
|
||||
const networkName = getNetworkDisplayName(network)
|
||||
|
||||
return h('div', {}, [
|
||||
h('div.buy-modal-content.transfers-subview', {
|
||||
|
@ -4,7 +4,7 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('../../actions')
|
||||
const networkNames = require('../../../../app/scripts/config.js').networkNames
|
||||
const { getNetworkDisplayName } = require('../../../../app/scripts/controllers/network/util')
|
||||
const ShapeshiftForm = require('../shapeshift-form')
|
||||
|
||||
let DIRECT_DEPOSIT_ROW_TITLE
|
||||
@ -122,7 +122,7 @@ DepositEtherModal.prototype.render = function () {
|
||||
const { buyingWithShapeshift } = this.state
|
||||
|
||||
const isTestNetwork = ['3', '4', '42'].find(n => n === network)
|
||||
const networkName = networkNames[network]
|
||||
const networkName = getNetworkDisplayName(network)
|
||||
|
||||
return h('div.page-container.page-container--full-width.page-container--full-height', {}, [
|
||||
|
||||
|
@ -12,7 +12,7 @@ const SimpleDropdown = require('../../dropdowns/simple-dropdown')
|
||||
const ToggleButton = require('react-toggle-button')
|
||||
const { REVEAL_SEED_ROUTE } = require('../../../routes')
|
||||
const locales = require('../../../../../app/_locales/index.json')
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../../../app/scripts/config').enums
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../../../app/scripts/controllers/network/enums')
|
||||
|
||||
const getInfuraCurrencyOptions = () => {
|
||||
const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => {
|
||||
|
@ -16,7 +16,7 @@ const { getEnvironmentType } = require('../../../../app/scripts/lib/util')
|
||||
const getCaretCoordinates = require('textarea-caret')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const Mascot = require('../mascot')
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../../app/scripts/config').enums
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../../app/scripts/controllers/network/enums')
|
||||
const { DEFAULT_ROUTE, RESTORE_VAULT_ROUTE } = require('../../routes')
|
||||
|
||||
class UnlockScreen extends Component {
|
||||
|
@ -36,6 +36,7 @@
|
||||
font-weight: 400;
|
||||
line-height: 21px;
|
||||
margin-left: 8px;
|
||||
cursor:pointer;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@
|
||||
|
||||
.network-dropdown-title {
|
||||
height: 25px;
|
||||
width: 75px;
|
||||
width: 120px;
|
||||
color: $white;
|
||||
font-family: Roboto;
|
||||
font-size: 18px;
|
||||
|
@ -789,6 +789,7 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ const getCaretCoordinates = require('textarea-caret')
|
||||
const { RESTORE_VAULT_ROUTE, DEFAULT_ROUTE } = require('../routes')
|
||||
const { getEnvironmentType } = require('../../../app/scripts/lib/util')
|
||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../app/scripts/lib/enums')
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/controllers/network/enums')
|
||||
|
||||
class InitializeMenuScreen extends Component {
|
||||
constructor (props) {
|
||||
|
@ -3,7 +3,7 @@ const actions = require('../actions')
|
||||
const MetamascaraPlatform = require('../../../app/scripts/platforms/window')
|
||||
const { getEnvironmentType } = require('../../../app/scripts/lib/util')
|
||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../../app/scripts/lib/enums')
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/controllers/network/enums')
|
||||
|
||||
module.exports = reduceMetamask
|
||||
|
||||
|
@ -7,7 +7,7 @@ const App = require('./app')
|
||||
const OldApp = require('../../old-ui/app/app')
|
||||
const { autoAddToBetaUI } = require('./selectors')
|
||||
const { setFeatureFlag, setNetworkEndpoints } = require('./actions')
|
||||
const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
|
||||
const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums')
|
||||
const I18nProvider = require('./i18n-provider')
|
||||
|
||||
function mapStateToProps (state) {
|
||||
|
@ -6,7 +6,7 @@ const connect = require('react-redux').connect
|
||||
const actions = require('./actions')
|
||||
const getCaretCoordinates = require('textarea-caret')
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums
|
||||
const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/controllers/network/enums')
|
||||
const { getEnvironmentType } = require('../../app/scripts/lib/util')
|
||||
const { ENVIRONMENT_TYPE_POPUP } = require('../../app/scripts/lib/enums')
|
||||
|
||||
|
@ -5,7 +5,11 @@ const actions = require('./app/actions')
|
||||
const configureStore = require('./app/store')
|
||||
const txHelper = require('./lib/tx-helper')
|
||||
const { fetchLocale } = require('./i18n-helper')
|
||||
const { OLD_UI_NETWORK_TYPE, BETA_UI_NETWORK_TYPE } = require('../app/scripts/config').enums
|
||||
const {
|
||||
OLD_UI_NETWORK_TYPE,
|
||||
BETA_UI_NETWORK_TYPE,
|
||||
} = require('../app/scripts/controllers/network/enums')
|
||||
|
||||
const log = require('loglevel')
|
||||
|
||||
module.exports = launchMetamaskUi
|
||||
|
Loading…
Reference in New Issue
Block a user